GCC工具详解【Linux知识贩卖机】

在这里插入图片描述
很多人在喧嚣声中登场,也有少数人在静默中退出。 --单独中的洞见2

文章目录

  • 简介
  • 程序到可执行文件
    • 链接
    • 动态链接和静态链接
    • 动态库和静态库
    • 动态库和静态库的打包
      • 打包静态库
      • 打包动态库
      • 选项
    • -static
  • 总结

简介

在这里插入图片描述

GCC(GNU Compiler Collection) 是一个由GNU计划开发的编程语言编译器套装,用于支持多种编程语言。GCC最初是为GNU操作系统而开发的,但它现在也被广泛用于其他操作系统,包括各种版本的Linux、Unix、BSD和一些嵌入式系统。

GCC的一些主要特征和用途如下:

  1. 多语言支持:

    • GCC支持多种编程语言,包括C、C++、Fortran、Ada、Objective-C和其他一些语言。
    • 对于C++,有专门的g++命令,它是GCC套装中的C++编译器。
  2. 交叉编译:

    • GCC可以用于交叉编译,即在一种平台上生成另一种平台上运行的可执行文件。
  3. 优化:

    • 提供多个优化选项,允许程序员在编译时进行性能优化。
  4. 标准符合性:

    • GCC致力于遵循编程语言的标准,如ISO C、ISO C++等,以确保生成的代码在不同平台上的一致性。
  5. 开源:

    • GCC是自由软件,使用GNU通用公共许可证(GPL)发布,这意味着用户可以查看、修改和分发源代码。
  6. 支持多种平台:

    • GCC可以在多种硬件体系结构和操作系统上使用,包括x86、ARM、PowerPC等,并且可以在各种Linux发行版、Unix系统以及其他操作系统上运行。
  7. 插件支持:

    • GCC具有插件架构,允许开发者编写并使用插件来扩展编译器的功能。
  8. 生态系统:

    • GCC是一个庞大的生态系统的一部分,许多项目和库都依赖于GCC进行编译。

基本上,GCC是一个功能强大、灵活且广泛使用的编译器套装,为开发者提供了生成高质量可执行文件的工具。

程序到可执行文件

程序的整个编译过程可以分为多个阶段,这些阶段的主要任务是将高级源代码转换为可执行文件。典型的编译过程的阶段如下:

  1. 预处理(Preprocessing):

    • 任务:在实际编译之前对源代码进行预处理。
    • 工具:预处理器(通常是 cpp)。
    • 过程:包括宏展开、头文件包含、条件编译等。
  2. 编译(Compilation):

    • 任务:将预处理后的源代码翻译成汇编语言。
    • 工具:编译器(如 gccg++)。
    • 过程:将源代码翻译成汇编代码。
  3. 汇编(Assembly):

    • 任务:将汇编代码翻译成机器代码。
    • 工具:汇编器(通常是 as)。
    • 过程:将汇编代码翻译成二进制目标文件。
  4. 链接(Linking):

    • 任务:将多个目标文件和库文件组合成一个可执行文件。
    • 工具:链接器(通常是 ld)。
    • 过程:解析符号引用、地址重定位、符号解析,生成最终的可执行文件。
  5. 加载(Loading)(可选):

    • 任务:将可执行文件加载到内存中,准备执行。
    • 工具:操作系统的加载器。
    • 过程:将可执行文件从磁盘加载到内存,并将控制权转交给程序的入口点。

整个过程可以用以下命令表示(以C语言为例):

# 预处理
cpp source_code.c > intermediate_code.i

# 编译
gcc -S intermediate_code.i -o assembly_code.s

# 汇编
as assembly_code.s -o object_code.o

# 链接
gcc object_code1.o object_code2.o -o executable_file

在实际项目中,这些步骤可能会合并或者包含其他步骤,例如优化(Optimization)阶段。在编译器的命令行选项中,你可以使用不同的标志来控制每个阶段的行为,以满足特定的需求。

tips:

cppgcc -E 的作用是相似的,它们都用于进行预处理。实际上,在大多数系统上,cpp 实际上就是 gcc -E 的一个符号链接。

  • cpp 命令:

  • cpp 是 C/C++ 的预处理器,它执行宏展开、条件编译等预处理任务。

  • 可以单独使用,如 cpp source_code.c -o output.i

  • 在一些系统上,cpp 可能是 gcc 中的一部分,而在另一些系统上,它可能是一个独立的工具。

  • gcc -E 命令:

  • gcc -Egcc 的一个选项,用于执行预处理操作。

  • 它实际上就是调用 cpp 进行预处理,但是通过 gcc 命令可以更方便地指定其他编译选项。

  • 使用方式为 gcc -E source_code.c -o output.i

在这里插入图片描述

所以,cppgcc -E 的效果基本相同,都是执行 C/C++ 源代码的预处理阶段。在实践中,你可以根据需要选择使用其中的一个。如果你只需要进行预处理而不需要其他编译阶段,cpp 可能更直接,而如果你希望通过 gcc 使用其他编译选项,那么就可以使用 gcc -E

类似于 cppgcc -E 的关系,asgcc -c 也有相似的关系。

  • as 命令:

  • as 是汇编器,用于将汇编代码转换为目标文件。

  • 可以单独使用,如 as assembly_code.s -o object_code.o

  • gcc -c 命令:

  • gcc -cgcc 的一个选项,用于执行编译操作并生成目标文件。

  • 使用方式为 gcc -c source_code.c -o object_code.o

  • 这实际上调用了 cc1(GCC 的前端)来进行编译,再使用 as 进行汇编。

在这里插入图片描述

因此,asgcc -c 在生成目标文件的过程中都会涉及到汇编阶段,只是 gcc -c 在执行时会将编译器的一些默认选项应用于源代码。在实践中,你可以根据需要选择使用其中的一个。如果只需进行汇编,as 可能更直接,而如果你想使用 gcc 的其他编译选项,那么可以使用 gcc -c

链接

粗略的说,链接是编程中的最后一个阶段,其主要任务是将多个目标文件和库文件组合成一个可执行文件。在链接阶段,各个目标文件之间的引用关系被解析,形成最终的可执行文件。

具体地说,链接的主要步骤包括:

步骤行为
1. 符号解析在编译过程中,各个源文件中可能存在引用其他文件中定义的函数或变量的情况。符号解析阶段会解决这些引用,确定它们的实际地址。
2. 地址重定位在编译过程中,生成的目标文件中包含相对地址(相对于文件开头的地址)。在链接阶段,这些相对地址需要被转换为绝对地址,以便最终的可执行文件能够正确地执行。
3. 库链接如果程序使用了外部库,链接器会将程序与这些库进行链接,将库的代码和数据合并到最终的可执行文件中。
4. 生成可执行文件:在解析符号、重定位地址、链接库之后,链接器将所有的目标文件和库文件组合在一起,生成最终的可执行文件。
5. 生成符号表链接过程生成一个符号表,其中包含了程序中所有函数和变量的地址信息。这对于动态链接、调试以及其他操作是很重要的。

链接过程的目标是产生一个可以直接在操作系统上运行的可执行文件。这个文件包含了程序的机器代码、数据、符号表等信息。

动态链接和静态链接

链接又可以分为静态链接和动态链接两种形式,他们是两种将程序组合成可执行文件的方式。

静态链接是在编译时进行。链接器将所有模块的代码和数据合并为一个单独的可执行文件。生成的可执行文件包含所有所需的代码和数据,形成一个完全独立的可执行文件。这样链接生成的可执行文件独立于系统上已安装的库,可以在不同的系统上运行。并且由于所有代码都被包含在可执行文件中,程序的启动和执行速度可能更快。

缺点是生成的可执行文件通常较大,因为包含了所有的代码和数据。且如果库发生变化,需要重新编译并重新链接整个程序。


动态链接是在运行时进行。链接器将程序模块与共享库的链接推迟到程序加载和运行时。生成的可执行文件包含程序的主要代码和动态链接器信息。共享库文件中包含共享的代码和数据,可以在多个程序之间共享。z这样链接生成的执行文件较小,因为只包含程序的主要代码和动态链接器信息。并且如果库发生变化,只需要更新库文件,而不需要重新编译整个程序,多个程序还可以共享同一个库,减少内存占用。

缺点是依赖于系统上已安装的共享库,可能导致兼容性和依赖性的问题。并且由于需要在运行时加载和链接共享库,可能导致一些性能开销。

因此在实践中,选择使用静态链接或动态链接取决于项目的特定需求和设计考虑。有时也可以采取混合的方式,即将一些核心的库静态链接,而其他的库动态链接。这样可以在某种程度上兼顾文件大小、独立性和更新的方便性。

动态库和静态库

动态库和静态库是两种不同的库文件类型,静态库和动态库通常是为静态链接和动态链接方式而设计的,在编译时,如果你使用静态链接,你会链接到静态库。如果你使用动态链接,你会链接到动态库。

动态库通常以 .so(在类Unix系统,如Linux上)或 .dll(在Windows上)为后缀,包含可执行代码和数据,但这些库的加载和链接是在运行时进行的。在编译时并不将库的代码和数据嵌入可执行文件中,而是在程序加载运行时由操作系统动态加载。

优点描述
共享性动态库可以多个程序可以共享同一个动态库,减少内存占用。
更新方便如果库发生变化,只需要更新库文件,而不需要重新编译整个程序。
热更新可以在程序运行时动态加载和卸载库,实现热更新的功能。
缺点描述
依赖性程序在运行时需要系统上已安装的相应动态库,可能导致兼容性和依赖性的问题。
性能开销加载和链接库的过程可能引入一些性能开销。

静态库通常以 .a(在类Unix系统上)或 .lib(在Windows上)为后缀,包含编译时需要的可执行代码和数据,它们会被静态地嵌入到可执行文件中。在编译时将库的代码和数据嵌入到可执行文件中,形成一个完全独立的可执行文件。

优点描述
独立性生成的可执行文件独立于系统上已安装的库,可以在不同的系统上运行。
性能由于所有代码都被包含在可执行文件中,程序的启动和执行速度可能更快。
缺点描述
文件大小生成的可执行文件通常较大,因为包含了所有的代码和数据。
更新困难如果库发生变化,需要重新编译并重新链接整个程序。

在实际项目中,开发者可以根据项目的需求和设计考虑选择使用动态库、静态库,或者两者混合使用。有时候,静态库和动态库的组合使用可以在一定程度上兼顾文件大小、独立性和更新的方便性。

动态库和静态库的打包

在软件开发中,打包(或者称为构建)静态库和动态库通常是通过编译器和一些构建工具完成。

打包静态库

  1. 编写源代码

    • 编写你的 C 或 C++ 源代码文件。
  2. 编译为目标文件

    • 使用编译器将源代码编译为目标文件(.o.obj)。
      gcc -c my_library.c -o my_library.o
      
  3. 打包为静态库

    • 使用 ar 工具将目标文件打包为静态库(.a.lib)。
      ar rcs libmy_library.a my_library.o
      
  4. 使用静态库

    • 在编译时,将静态库链接到可执行文件中。
      gcc my_program.c -o my_program -L. -lmy_library
      

在这里插入图片描述

打包动态库

  1. 编写源代码

    • 编写你的 C 或 C++ 源代码文件。
  2. 编译为目标文件

    • 使用编译器将源代码编译为目标文件。
      gcc -fPIC -c my_library.c -o my_library.o
      
  3. 生成动态库

    • 使用编译器将目标文件生成动态库(.so.dll)。
      gcc -shared -o libmy_library.so my_library.o
      
  4. 使用动态库

    • 在编译时,链接动态库;在运行时,系统会动态加载和链接动态库。
      gcc my_program.c -o my_program -L. -lmy_library
      

在这里插入图片描述

上述步骤中的关键点:

  • -fPIC(Position Independent Code)选项用于生成与地址无关的代码,是动态库的要求。
  • -shared选项用于生成共享库。

选项

这里的示例假设在同一目录下进行编译和链接。如果库文件位于不同目录,可能需要使用 -I-L 选项来指定头文件和库文件的搜索路径。

其中-L 选项用于指定库文件的搜索路径。编译器在链接时使用这个路径来查找库文件。-I 选项用于指定头文件的搜索路径。编译器在编译时使用这个路径来查找头文件。-l 选项用于指定链接时需要使用的库。通常与 -L 选项一起使用,指定库文件的名称。

例如:

gcc my_program.c -o my_program -L/path/to/library -lmy_library

-L/path/to/library 告诉编译器在 /path/to/library 目录下查找库文件,而 -lmy_library 则表示链接名为 libmy_library.so(或 libmy_library.a)的库文件。

gcc -I/path/to/include my_program.c -o my_program

-I/path/to/include 告诉编译器在 /path/to/include 目录下查找头文件。

-static

-static 是一个编译器选项,用于在编译时强制链接静态版本的库,而不是默认的动态版本。这个选项通常用于生成不依赖于系统上已安装的动态库的可执行文件。

当使用 -static 选项时,编译器将尽可能地链接静态库,而不是动态库。这意味着可执行文件中包含了所有所需的代码和数据,而不需要在运行时依赖于系统上已安装的动态库。这对于创建独立、可移植的可执行文件是有用的,因为它们不依赖于目标系统上已安装的共享库。

使用 -static 选项的例子:

gcc -static my_program.c -o my_program

这将编译 my_program.c 并链接到静态库,生成一个不依赖于动态库的可执行文件 my_program。请注意,使用 -static 选项可能会增加可执行文件的大小,因为它包含了所有的库代码和数据。

需要注意的是,有些库可能没有静态版本,因此在使用 -static 选项时,需要确保所需的库都有可用的静态版本。如果某个库没有静态版本,使用 -static 选项可能会导致链接错误。

总结

文章介绍了GCC工具的一些用法,包括程序到可执行文件过程中的一些细节,顺带将动静态库和动静态链接进行介绍,还介绍了一些常见的选项。希望文章内容对你有帮助。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/136164.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python之函数进阶-函数执行原理

Python之函数进阶-函数执行原理 函数执行流程 C语言中,函数的活动和栈有关。栈是后进先出的数据结构。栈是由底端向顶端生长,栈顶加入数据成为压栈、入栈、栈顶弹出数据称为出栈。 def add(x, y):r x yprint(r)return rdef main():a 1r add(a, 2)r…

Windows下Oracle安装和卸载

Windows下Oracle安装和卸载 1、Windows下安装Oracle 安装的版本:win32_11gR2_database。 解压之后双击setup.exe程序。 点击是。 配置安全更新,去掉复选框,点下一步。 提示未指定电子邮件地址,点是跳过。 配置安装选项&#xf…

【YOLOv5】【模型压缩与加速】【量化】FP32、FP16、INT8

量化是将模型参数的存储类型从高精度存储降到低精度存储,从而达到减小模型体积大小、加快模型推理速度的效果。 目录 FP32量化 FP16量化 INT8量化 FP32量化 这个直接使用yolov5的export导出32位存储的 engine格式模型即可 python export.py --weights runs/train/…

ubuntu下tensorrt环境配置

文章目录 一、Ubuntu18.04环境配置1.1 安装工具链和opencv1.2 安装Nvidia相关库1.2.1 安装Nvidia显卡驱动1.2.2 安装 cuda11.31.2.3 安装 cudnn8.21.2.4 下载 tensorrt8.4.2.4 二、编写CMakeLists.txt三、TensorRT系列教程 一、Ubuntu18.04环境配置 教程同样适用与ubuntu22.04…

Spring面试题:(五)Spring注解开发@Component,@Autowired,@Bean,@Configuration

Bean基本注解 spring提供注解的版本 Component注解替代bean标签 bean其它属性的相关注解: scope 替代scopelazy 替代lazy-initPostConstruct 替代init-methodPreDestroy 替代destroy-method 使用Component注解的前提是开启注解扫描 衍生注解Repository,Servi…

【C语言:深入理解指针一】

文章目录 1.指针存在的意义2.指针变量和地址3.指针变量类型的意义3.1指针解引用3.2指针 - 整数3.3void* 4.关键字const4.1const修饰变量4.2 const修饰指针 5.指针运算5.1指针 -整数5.2指针-指针5.3指针比较大小 6. 野指针7.assert断言8. 数组名的理解9.一维数组传参的本质 1.指…

博客积分上一万一千了

博客积分上一万一千了 充满自信,继续前进。

程序员职业生涯规划:多领域路线图一网打尽 | 开源日报 No.72

kamranahmedse/developer-roadmap Stars: 244.4k License: NOASSERTION 这是一个互动的路线图,指南和其他教育内容,旨在帮助开发人员在他们的职业生涯中成长。 提供多个不同领域 (如前端、后端、DevOps 等) 的路线图路线图可交互,并提供了详…

C语言--每日五道选择题--Day9

第一题 1、如下程序的运行结果是( ) char c[5]{a, b, \0, c, \0}; printf("%s", c); A: a b B: ab\0c\0 C: ab c D: ab 答案及解析 D 首先这是一个字符数组,我们要知道无论是字符串还是字符数组,它们遇到ASCII值为0就…

Django中如何创建表关系,请求生命周期流程图

Django中ORM创建表关系 如何创建表关系(一对一 , 一对多 , 多对多) 图书表,出版社表,作者表,作者详情表 换位思考法判断表关系 图书表和出版社表 >>> 一对多 >>> 图书表是多,出…

【Spring】@Component组件

大前提&#xff1a; 添加了相关的约束文件以及注解支持 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:…

异步编程工具Promise与Async/Await:解决前端开发中的嵌套回调地狱

文章目录 Promise&#xff1a;处理异步操作的基本工具Promise.all async/await&#xff1a;更简洁的异步编程方式Promise与async/await的比较结论 当谈及JavaScript中的异步编程时&#xff0c;两个非常常见且强大的工具是Promise和async/await。在本文中&#xff0c;我们将以实…

​软考-高级-系统架构设计师教程(清华第2版)【第3章 信息系统基础知识(p120~159)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第3章 信息系统基础知识(p120~159)-思维导图】 课本里章节里所有蓝色字体的思维导图

【Redis】String字符串类型

上一篇&#xff1a;Redis-key的使用 https://blog.csdn.net/m0_67930426/article/details/134361821?spm1001 .2014.3001.5501 目录 appen (附加&#xff09; strlen(获取字符串的长度&#xff09; incr decr getRange(获取字符串&#xff09; setRange&#xff08;替…

Flink

1. Flink简介 1.1 初识Flink Flink项目的理念是&#xff1a;“Apache Flink是为分布式、高性能、随时可用以及准确的流处理应用程序打造的开源的有状态的流处理框架”。 Apache Flink是一个框架和分布式处理引擎&#xff0c;用于对无界和有界数据流进行有状态计算。Fl…

fastbins_Double Free调试

我大哥给我出了一题pwn heap题&#xff0c;当时现场的时候没解出来&#xff0c;想岔了。事后感概自己还是理解的不够透彻。决定认真再次调试下。用的是2.23版本的how2heap中fastbins_dup.c。 简单用gcc编译下&#xff0c;然后带源码调试&#xff1a; 生成一个a.out的文件&#…

leetcode刷题日记:111. Minimum Depth of Binary Tree(二叉树的最小深度)

给我们一个二叉树&#xff0c;我们应该如何来求二叉树的最小深度呢&#xff1f; 二叉树的最小深度指的是叶子结点到所处的位置最小的&#xff0c;这就是二叉树的最小深度&#xff0c;也就是说我们要找的是离根结点最近的叶子结点。如果我们从根结点向下出发寻找叶子节点&#x…

移动硬盘和u盘的区别哪个好 移动硬盘和u盘有啥区别

在数字时代的今天&#xff0c;数据存储已经成为我们生活中的重要一环。当我们需要移动、备份或传输大量数据时&#xff0c;常常会不知道是选择移动硬盘还是U盘。其实&#xff0c;对于许多人来说&#xff0c;移动硬盘和U盘之间的区别并不清晰。下面我们就来看移动硬盘和u盘的区别…

思科9300交换机使用USB进行升级ISO

一、下载ISO 一、网址 Software Download - Cisco Systems 二、找到型号 四、选择XE 软件 五、进行下载 二、COPY 进 U盘 一、、请注意&#xff01;如果你的U盘不是Fat32文件格式则交换机读取不了&#xff0c;请先格式化再复制文件。 二、下载后将 bin文件复制到U盘。 1.扩展…

经典OJ题:重排链表

题目&#xff1a; 给定一个链表&#xff0c;在进行重排前&#xff1a; 进行重排链表后&#xff1a; 如上图所示&#xff0c;所谓的重拍链表&#xff0c;就是将第一个节点连接第倒数第一个节点&#xff0c;第二个节点连接倒数第二个节点&#xff0c;以此类推&#xff0c;最后在连…
最新文章