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.hqwc.cn/news/169438.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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

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

Ubuntu虚拟机设置静态IP

目录 1 确定网络信息2 配置网络文件3 更新配置4 验证 网上很多方案都是 sudo vi /etc/network/interfaces 但是在Ubuntu20.04中我的目录i已经没有这个文件夹了,好像就算自己新建通过这种方式也是不能达到静态ip的目的。整理了下面的这种方式,实测最终有效…

游戏平台采集数据

首先,你需要在你的项目中添加Kotlin的网络库,例如OkHttp。你可以在你的build.gradle文件中添加以下依赖: dependencies {implementation com.squareup.okhttp3:okhttp:4.9.0 }然后,你可以使用以下代码来创建一个基本的网络爬虫&a…

PHP中传值与引用的区别

在PHP中,变量的传递方式主要分为传值和传引用两种。这两种方式在操作中有一些重要的区别,影响着变量在函数调用或赋值操作中的表现。下面详细解释一下这两种传递方式的区别。 传值(By Value) 传值是指将变量的值复制一份传递给函…

10道高频Vuex面试题快问快答

※其他的快问快答,看这里! 10道高频Qiankun微前端面试题快问快答 10道高频webpack面试题快问快答 20道高频CSS面试题快问快答 20道高频JavaScript面试题快问快答 30道高频Vue面试题快问快答 面试中的快问快答 快问快答的情景在面试中非常常见。 在面试过…

如何提升管理组织能力?

组织能力能力属于管理能力中的一部分,所以也称之为管理组织能力,组织是将人和事物的组合,有效的梳理和导向结果的能力。每个人都有组织能力,只是能力和效率上存在较大的差异。 一人的组织能力从学生时代就能体现出来,…

HDMI之编码篇

概述 HDMI 2.0b(含)以下版本,采用3个Channel方式输出。传输又分为3三种周期,视频数据,数据岛以及控制周期。视频传输采用8/10编码。数据岛采用4/10编码(TERC4)。控制周期采用2/10。编码都拓展成了10bits。 上图中,Pixel component(e.g.B)->D[7:0]表示视频数据周期…

链表OJ题【环形链表】(3)

目录 环形问题的思考 ❓Q1 ❓Q2 🙂Q2 ❓Q3 ❓Q4 8.环形链表 9.环形链表Ⅱ 今天接着链表的经典问题环形问题。大家一定要自己动手多写写。🙂 快慢指针(保持相对距离/保持相对速度)野指针考虑为NULL的情况带环链表&#x…

(离散数学)逻辑连接词

异或可以理解为不同为1相同为0 P->Q的前件和后件满足0->1的其中一个就为真 <—>可以看做 &#xff0c;相同为1不同为0 异或与等价相反

Radius是什么意思? 安当加密

Radius是什么意思&#xff1f; RADIUS&#xff08;Remote Authentication Dial In User Service&#xff09;是一种远程用户拨号认证系统&#xff0c;它由RFC 2865和RFC 2866定义&#xff0c;是应用最广泛的AAA&#xff08;Authentication、Authorization、Accounting&#xf…

在任何机器人上实施 ROS 导航堆栈的指南

文章目录 路径规划参考 路径规划 路径规划是导航的最终目标。这允许用户向机器人给出目标姿势&#xff0c;并让它在给定的环境中自主地从当前位置导航到目标位置。这是我们迄今为止所做的一切&#xff08;地图绘制和本地化&#xff09;的汇集点。ROS 导航堆栈已经为我们完成了…

No183.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…