gcc编译
程序从源代码生成可执行程序过程:预处理,编译,汇编,链接。
g++/gcc命令将“预处理,编译,汇编,链接”四个步骤融合成整体,默认只会生成最终的可执行文件,中间文件不会生成。
单步编译:
//将hello.cpp生成默认名称额可执行文件(a.exe)
g++ hello.cpp
//将hello.cpp生成可执行文件hello
//-o 选项用于指定要生成的文件名
g++ hello.cpp -o hello
//g++在编译的过程中保留预处理,编译,汇编中间文件-save-temps
g++ hello.cpp -o hello -save-temps
分步编译详解:
分步命令说明:(一下四个命令均可携带-O参数执行生成的文件名称)
g++ -E : 预处理
g++ -S : 编译
g++ -c : 汇编
g++ :预处理+编译+汇编+链接(携带参数)
分步编译完整流程:
g++ -E demo.cpp -o demo.i
g++ -S demo.i
g++ -c demo.s
g++ demo.o
./a.out
预处理
主要处理内容如下:
- 处理文件中以“#”开头的内容,包括include展开、宏定义展开、条件编译命令处理。(例外:#pamgram不处理)
- 删除代码注释。
- 添加行号和文件名标识。
生成.i文件。
编译
对预处理文件进行词法分析、语法分析、语义分析,优化后生成汇编代码。生成.s文件。
g++ -S main.i -o maim.s
或者
g++ -S main.cpp -o demo.s
汇编
将汇编代码转换为机器指令,即生成目标文件(.o或者.obj文件)。
g++ -c main.s -o main.o
链接
汇编生成的可执行文件,由于某些函数和全局变量的地址未找到,不能执行。链接就是来找到这些地址。
链接的本质就是通过符号找到对应地址,使得模块与模块之间能够相互调用。
程序在运行之前确定符号地址的过程叫静态链接。
程序在运行期间确定符号地址的过程叫动态链接。.dll和.so等库实在程序运行期间确定的,是动态链接库。
链接库说明
库文件:
-
等价为压缩包文件,该文件内部通常包含不止一个目标文件(也就是二进制文件)。
-
库文件中每个目标文件存储的代码,并非完整的程序,而是一个个实用的功能模块。
-
所有的库文件都提供有相应的头文件作为调用它的接口。
-
库文件是无法直接使用的,只能通过头文件间接调用。
编译器提供2种实现链接的方式:
-
静态链接=》静态链接库
-
动态链接=》动态链接库
静态链接库:
-
gcc编译器将链接库模板代码直接复制程序文件制定位置生成可执行文件。
-
生成的可执行文件不再需要任何静态库文件的支持就可以独立运行(可移植性强)。
-
如果程序文件中多次调用库中的同一功能模块,则该模块代码势必就会被复制多次。
-
在 Linux 发行版系统中,静态链接库文件的后缀名通常用 .a 表示;在 Windows 系统中,静态链接库文件的后缀名为 .lib。
// 汇编sub.c add.c div.c和test.h为目标文件
[root@bogon demo]# gcc -c sub.c add.c div.c
[root@bogon demo]# ls
add.c add.o div.c div.o main.c sub.c sub.o test.h
// 将目标文件链接生成静态链接库libmymath.a
[root@bogon demo]# ar rcs libmymath.a add.o sub.o div.o
[root@bogon demo]# ls
add.c add.o div.c div.o libmymath.a main.c sub.c sub.o test.h
// 将main.c汇编生成目标文件
[root@bogon demo]# gcc -c main.c
[root@bogon demo]# ls
add.c div.c libmymath.a main.o sub.c
test.h add.o div.o main.c sub.o
// 链接静态链接库和
[root@bogon demo]# gcc -static main.o libmymath.a
[root@bogon demo]# ls
add.c a.out div.o main.c sub.c test.h
add.o div.c libmymath.a main.o sub.o
动态链接库:
-
gcc编译器不直接把功能模板代码拷贝到目标文件中,只记录功能模板代码的调用位置生成可执行文件。
-
此方式生成的可执行文件无法独立运行,必须借助相应的库文件。
-
即便功能模块被调用多次,使用的都是同一份实现代码。
-
在 Linux 发行版系统中,动态链接库的后缀名通常用 .so 表示;在 Windows 系统中,动态链接库的后缀名为 .dll。
//生成动态链接库文件
[root@bogon demo]# ls
add.c div.c main.c sub.c test.h
[root@bogon demo]# gcc -fpic -shared add.c sub.c div.c -o libmymath.so
[root@bogon demo]# ls
add.c div.c libmymath.so main.c sub.c test.h
//使用动态链接库
[root@bogon demo]# gcc main.c libmymath.so -o main.exe
[root@bogon demo]# ls
add.c div.c libmymath.so main.c main.exe sub.c test.h
//查看动态链接库是否成功
[root@bogon demo]# ldd main.exe
linux-vdso.so.1 => (0x00007fff06fb3000)
libmymath.so => /lib64/libmymath.so (0x00007f65b2a62000)
libc.so.6 => /lib64/libc.so.6 (0x00000037e2c00000)
/lib64/ld-linux-x86-64.so.2 (0x00000037e2800000)
运行由动态链接库生成的可执行文件时,必须确保程序在运行时可以找到这个动态链接库。常用的解决方案有如下几种:
- 将链接库文件移动到标准库目录下(例如 /usr/lib、/usr/lib64、/lib、/lib64);
- 在终端输入
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx
,其中 xxx 为动态链接库文件的绝对存储路径(此方式仅在当前终端有效,关闭终端后无效); - 修改~/.bashrc 或~/.bash_profile 文件,即在文件最后一行添加
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx
(xxx 为动态库文件的绝对存储路径)。保存之后,执行source .bashrc
指令(此方式仅对当前登陆用户有效)。