Linux 上GCC的静态编译和动态编译

时间:2021-12-21 17:25:53

静态编译

常规编译示例:

$gcc xxx.c yyy.c zzz.c -o rslt

注明: gcc编译器会对源文件min.c进行预处理, 编译, 以及链接, 最后生成可执行文件

$gcc -c xxx.c yyy.c zzz.c

注明:gcc编译器会对源文件min.c进行预处理, 编译, 不进行链接, 最后生成的是object file (目标文件)

链接操作示例:

$ar rs libstack.a stack.o push.o pop.o is_empty.o

ar命令类似于tar命令,起一个打包的作用,但是把目标文件打包成静态库只能用ar命令而不能用tar命令。选项r表示将后面的文件列表添加到文件包,如果文件包不存在就创建它,如果文件包中已有同名文件就替换成新的。s是专用于生成静态库的,表示为静态库创建索引,这个索引被链接器使用。ranlib命令也可以为静态库创建索引,以上命令等价于:

$ ar r libstack.a stack.o push.o pop.o is_empty.o

$ ranlib libstack.a

最后编译demo时链接静态库:

$gcc main.c -L. -lstack -Istack -o main

符号注明:-I 头文件目录 -L库目录 -l链接库名称

链接动态库和静态库优先级说明:编译器会首先找有没有共享库libstack.so,如果有就链接它,如果没有就找有没有静态库libstack.a,如果有就链接它。所以编译器是优先考虑共享库的,如果希望编译器只链接静态库,可以指定-static选项。

动态编译

组成共享库的目标文件和一般的目标文件有所不同,在编译时要加-fPIC和-share选项,例如:

$gcc -fPIC -shared testa.c testb.c testc.c -o libtest.so

-f后面跟一些编译选项,PIC是其中一种,表示生成位置无关代码(Position Independent Code)。

-shared该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

最后编译demo时链接动态库,和静态库链接一样:

$gcc main.c -L. -lstack -Istack -o main

如果运行main找不到*.so时候,使用ldd命令查看链接库。

动态库目录搜索优先级:

我们知道一个程序要想在内存中运行,除了编译之外还要经过链接和装入这两个步骤。当然linux中动态链接也是经过这三个过程。Linux 使用这个ld-linux.so*中的来装载(其实这只是一个链接)其他库。所以这个库必须放在linux中/lib下。对于其他,通常我们共享库放在/lib这个路径下,而且也是系统默认的搜索路径。
Linux共享库的搜索路径先后顺序:
1、编译目标代码时指定的动态库搜索路径:在编译的时候指定-Wl,-rpath=路径
2、环境变量LD_LIBRARY_PATH指定的动态库搜索路径
3、配置文件/etc/ld.so.conf中指定的动态库搜索路径
4、默认的动态库搜索路径/lib
5、默认的动态库搜索路径 /usr/lib

临时设置2的命令是:export LD_LIBRARY_PATH=.