0


你了解Linux编译器gcc的使用吗?

❤️我们先通过两张图来简单解释一下整个运行的过程!

❤️从上图我们可以看出整个翻译又分为四个过程:预处理(预编译)、编译、汇编、链接

补充:直接编译

❤️比如:我们写了一个在test.c文件,里面写入代码:

❤️直接编译,默认生成a.out可执行文件;也可以加上-o参数,自己命名生成的可执行程序的名字

❤️无论是a.out 还是mytest直接./a.out或者./mytest都是可以直接就运行的!

❤️在预处理阶段主要包括:a.头文件的展开、b.去注释、c.宏替换、d.条件编译;

  1. ⭐️我们主要使用**-E参数**
  2. ⭐️gcc -E test.c -o test.i 第一步走完,停下!临时内容写入.i文件

❤️这里我们也有两种方法进行预编译

⭐️(1)我们再利用-o参数命名tes.i,把结果放到test.i文件里

  1. ⭐️(2)利用>重定向到test.i文件中

❤️预处理过后结果还是C语言;我们不妨打开test.i进行查看

❤️在编译阶段主要是把C语言变成汇编语言;

❤️对于编译我们需要用到**-S参数;**我们利用第一步的结果test.i继续往后编译;它会默认生成test.s文件:

❤️当然我们也可以再用-o选项,进行自己命名:gcc -S test.i -o test.s;也是可以的;

  1. ⭐️gcc -S test.i -o test.s 第二步走完,停下!临时内容写入.s文件

❤️在汇编阶段主要是把汇编语言转换成机器指令(.o目标二进制文件,二进制不可执行);

❤️对于汇编我们需要用到**-c参数;**我们利用第二步的结果test.s继续往后汇编;它会默认生成test.o文件:

❤️当然我们也可以再用-o选项,进行自己命名:gcc -c test.s -o test.o;也是可以的;

  1. ⭐️gcc -c test.s -o test.o 第三步走完,停下!临时内容写入.o文件;
  2. ⭐️这个二进制文件我们看不懂,所以需要一个工具readelfreadelf -s test.o就可以正常阅读;也可以用od命令,以八进制形式打开;

❤️链接阶段本质上引入我们在代码中常用的第三方库(C库);

❤️对于链接我们不需要参数,直接利用第三步生成的test.o二进制文件;去链接C库,最终生成可执行文件,默认是a.out;也可以用-o自己命名;

❤️gcc会根据文件,进行默认链接(由编译器和文件共同决定);

❤️怎么验证链接的就是C库?我们可以用ldd命令去查看a.out所依赖的库

⭐️静态库和动态库:libc-2.17.so以.so结尾叫动态库;libc.a以.a结尾叫静态库 ;

⭐️库的真正名字:是去掉lib,去掉第一个点(.),.XXX以后的的内容;剩下的就是库名字;

⭐️所以对于libc.so.6这个动态库,真正的名字就是C库(libc.so.6);验证链接的就是C库!

❤️这里我们在补充一下gcc编译器的其它参数和函数库的一些知识点!便于我们的理解!

⭐️**-E** 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面;
⭐️**-S ** 编译到汇编语言不进行汇编和链接;
⭐️**-c** 编译到目标代码;
⭐️**-o **文件输出到 文件;
⭐️-static 此选项对生成的文件采用静态链接;默认生成的是链接,想要生成静态链接,就多加一个参数 -static就可以了;
⭐️-g 生成调试信息。GNU 调试器可利用该信息;
⭐️-shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库;
⭐️-O0、-O1、-O2、-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,

-O3优化级别最高;
⭐️-w 不生成任何警告信息。
⭐️-Wall 生成所有警告信息。

gcc选项记忆

❤️对于我们常用的无非就时编译阶段的参数-E、-S、-c;与对应生成的.i、.s、.o文件!

⭐️对于编译时参数-E、-S、-c;我们就想到vim编译器里,按Esc可以回退到命令模式;这里的Esc不就刚好对应着-E、-S、-c?只需要注意的是,前两大写,最后一个小写;

⭐️对于生成的文件.i、.s、.o;我们就对比下载Centos镜像时,后缀是不是就是.iso?

gcc中多文件的操作

❤️这一次我们的.c文件只有一个;那如果像在VS中写成项目的模式,最终有多个.c文件,怎么链接成一个可执行文件呢?

  1. ⭐️(1)比如有3个.c文件:test.ctest1.ctest2.c我们链接成一个可执行文件;首先要先生成.o目标文件;gcc -c test.cgcc -c test1.cgcc -c test2.c会默认生成test.otest1.otest2.o文件;
  2. ⭐️(2)怎么把test.otest1.otest2.o链接起来生成一个可执行文件呢?
  3. 直接执行:gcc test.o test1.o test2.o -o a.out

❤️总结:对于多文件情况,最好是将多文件统一编译成.o文件,然后把所有的.o文件链接生成可执行文件!当然直接把.c文件直接链接也是可以的!

⭐️当.c文件有几千的的时候,我们非要把所有的文件生成.o文件吗?当然不是,这就需要make和makefile,后面会讲解;

❤️我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
❤️解释:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用!

❤️静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”;

❤️动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库;
❤️gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示:gcc hello.o -o hello
❤️gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。

标签: linux 运维

本文转载自: https://blog.csdn.net/m0_61933976/article/details/124663654
版权归原作者 @每天都要敲代码 所有, 如有侵权,请联系我们删除。

“你了解Linux编译器gcc的使用吗?”的评论:

还没有评论