编译、汇编、链接过程 和g++编译选项

从 C/C++ 源代码 到 可执行文件 需要经过4个步骤:

  1. 预处理,由后缀为.c/.cpp的源程序生成后缀为.i的预处理文件,预处理文件本质也是c/cpp源程序,只是进行了头文件展开和宏替换;
  2. 编译,由后缀为.i的预处理文件生成后缀为.s的汇编文件,这一步是将源程序转化为汇编指令;
  3. 汇编,由后缀为.s的汇编文件生成后缀为.o的机器代码,即二进制文件,但是这时候还不可以执行;
  4. 链接,把大量的后缀为.o的机器代码(Object File)合成执行文件,这个动作叫作链接(link)

链接:https://www.jianshu.com/p/4f524d837716

https://blog.csdn.net/guaiguaihenguai/article/details/81160310

gcc 与 g++ 是将从 C/C++ 源代码 变成 可执行文件的工具,两者区别如下,一般直接都是用g++。

(1)gcc和g++都是GNU(组织)的一个编译器。

(2)后缀名为.c的程序和.cpp的程序g++都会当成是c++的源程序来处理。而gcc不然,gcc会把.c的程序处理成c程序。

(3)对于.cpp的程序,编译可以用gcc/g++,而链接可以用g++或者gcc -lstdc++。(个人觉得这条是最重要的)

1. 编译选项

编译选项

描述

-E

只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面.

-S

只激活预处理和编译,就是指把文件编译成为汇编代码。

-C -c

只激活预处理,编译,和汇编,也就是他只把程序做成obj文件

-o

注意,此处是小写的o

制定目标名称,缺省的时候,gcc 编译出来的文件是a.out

-w

-W

-Wall

-w 关闭编译警告。平时编写c/c++代码如果不规范,编译的时候会抛出很多警告。但是一般的警告都是可以忽略的,比如类型转换。编译的时候可以加-w关闭警告

-W 也是关闭编译警告,但是比-w智能一些,它只会显示编辑器认为会出错的警告

-Wall, 显示所有警告。

-g

产生调试信息,如果要使用gdb进行调试,必须加-g选项

-O1 -O2

-O3 -Os

-O系列选项主要用于优化代码。注意,此处是大写的O

-O和-O1是等价的,不影响编译速度,并且会采用一些优化算法,降低代码大小并提高代码运行速度。

-O2,会降低编译速度,但是除了包含-O1的优化算法之外,还会采用一些其他的优化算法来提高代码运行速度。

-O3,除了包含-O2所有的优化外,会采取一些向量化算法,提高代码的并行执行程度,使之更充分地利用现代cpu的流水线和cache。

-Os,-O3即使是增加代码的大小,也要提高运行速度。而这个选项在-O2的基础上,尽量减少目标的大小,这个经常用于存储量比较小的设备。

-m32 

-m64

m32指定编译为32位应用程序(可执行文件),

-pthread

用gcc编译使用了POSIX thread的程序时通常需要加额外的选项,以便使用thread-safe的库及头文件

编译选项中指定 -pthread 会附加一个宏定义 -D_REENTRANT ,该宏会导致 libc 头文件选择那些thread-safe的实现;链接选项中指定 -pthread 则同 -lpthread 一样,只表示链接 POSIX thread 库。由于 libc 用于适应 thread-safe 的宏定义可能变化,因此在编译和链接时都使用 -pthread 选项而不是传统的 -lpthread 能够保持向后兼容,并提高命令行的一致性。

编译systemc/TLM 的code时,必须添加-pthread的编译选项

-I

注意此处是大写的I,表示include,指定头文件的路径地址

在你用#include"file"的时候,gcc/g++会先在当前目录查找你所制定的头文件,如果没有找到,他回到缺省的头文件目录找,如果使用-I制定了目录,他会先在你所制定的目录查找,然后再按常规的顺序去找.

对于#include<file>,gcc/g++会到-I制定的目录查找,查找不到,然后将到系统的缺省的头文件目录查找

-L

注意此处是大写的L,指定库文件的路径地址

-l

注意此处是小写的l,指定动态库的名字

-D

Define,源文件中有定义#ifdef DEFINE_NAME  #ifndef   #else  #endif,根据-D编译选项进行选择

如果有定义多个define ,需要分别-D指示,如-D DEFINE_1 –D DEFINE_2

 

 

2. 添加头文件 -I

例如在/home/work/include/目录下有编译foo.c所需头文件def.h,为了让GCC能找到它们,就需要使用-I选项:

$ gcc foo.c def.h -I/home/work/include -o foo

3. 库文件

       在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(LibraryFile),也就是.lib文件,在UNIX下,是Archive File,也就是.a文件。

      库文件在链接(静态库和共享库)和运行(仅限共享库的程序,静态库会和可执行编译到一起)时被使用,其搜索路径是在系统中进行设置的。一般 Linux 系统把 /lib 和 /usr/lib 两个目录作为默认的库搜索路径,所以使用这两个目录中的库时不需要进行设置搜索路径即可直接使用。对于处于默认库搜索路径之外的库,需要将库的位置添加到 库的搜索路径之中。

      设置库文件的搜索路径总的来说有以下几种:

  1. LIBRARY_PATH、LD_LIBRARY_PATH等 环境变量:指定连接、运行时库文件路径;
  2. /etc/ld.so.conf 文件:添加链接时库文件的搜索路径,运行时还需要使用ldconfig命令将路径刷新到ld.so.cache中;
  3. g++/gcc编译参数-L、-l :指定链接时库文件的路径、名字;

原文链接:https://blog.csdn.net/liuxiao723846/java/article/details/9761768

4. 添加库文件:-L

例如在/home/work/lib/目录下有链接所需库文件libdef.so,为了让GCC能找到它们,就需要使用-L选项:

$ gcc foo.c –L/home/work/lib –ldef.so –o foo

说明:-l选项指示GCC去连接库文件libdef.so。Linux下的库文件命名有一个约定,即库文件以lib三个字母开头,因为所有的库文件都遵循这个约定,故在用-l选项指定链接的库文件名时可以省去lib三个字母。

Linux下的库文件分为动态链接库(.so文件)和静态链接库(.a文件)。GCC默认为动态库优先,若想在动态库和静态库同时存在的时候链接静态库需要指明为-static选项。比如上例中如还有一个libdef.a而你想链接libdef.a时候命令如下:

$ gcc foo.c –L/home/work/lib –static –ldef.a –o foo

 

5. 创建静态库.a文件

创建静态库.a文件的方法:

ar rcs libxxx.a xx1.o xx2.o

ranlib libxxx.a

其中,ar 用于创建静态库,Ranlib用于更新静态库的符号索引表,在增加静态库成员.o 文件 的时候使用。libxxx.a 为静态库名字,必须以lib开头。

参考 <https://blog.csdn.net/eastonwoo/article/details/8241693>

<https://blog.csdn.net/qq_34595352/article/details/88027689>

猜你喜欢

转载自blog.csdn.net/zgcjaxj/article/details/107371174