先关注两个gcc编译选项:
-c 编译且汇编,但是不链接
-S 只编译,不汇编也不链接
-c选项产出的就是经常看到的.o文件,也是一般用来创建静态库的文件。
用如下的命令可以将多个.o文件打包为一个静态库文件:ar crs libtest.a src/test1.o src/test2.o
现在完成了静态库创建工作,我们怎么在链接一个可执行程序的时候使用这个静态库呢?
有三种方式:
1. gcc -o test main.c libtest.a
2. gcc -o test main.c –ltest –L./
3. gcc -o test main.c -Xlinker “-(” libtest.a -Xlinker “-)”
其中一、二其实是同一种使用方式,第三种方式稍有不同,这个不同之处是什么呢?
第三种方式其实是多传了两个参数给链接器:”-(”和”-)”。传这个两个参数有什么作用吗?
上面的使用中还看不出来传给链接器的两个参数的作用。
但是假设我们需要用到两个静态库:libtest1.a和libtest2.a,其中libtest2.a中又使用了libtest1.a中的接口。
那么我们可以这样使用:(原来三种使用方式中的1、2其实是一种,后面只列出其中之一)
1. gcc –o test main.c libtest2.a libtest1.a
2. gcc -o test main.c -Xlinker “-(” libtest1.a libtest2.a -Xlinker “-)”
需要注意的是:第一种使用方式中静态库出现的顺序,libtest2.a必须在libtest1.a之前,否则会有”undefined reference to ***”的链接错误,其中***就是libtest2.a中使用的libtest1.a的接口。
如果libtest1.a在前,为什么会有链接错误呢?
原因是gcc在链接的时候,对于多个静态库或者.o文件是从前往后依次处理的,如果当前的静态库或.o文件中没有使用的符号,则往后继续寻找,而不会再往前查找。
下面是man gcc看到的说明:
- -l library
- Search the library named library when linking. (The second alternative with the library as a separate argument is
- only for POSIX compliance and is not recommended.)
- It makes a difference where in the command you write this option; the linker searches and processes libraries and
- object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before
- bar.o. If bar.o refers to functions in z, those functions may not be loaded.
所以在使用一些依赖关系比较复杂的静态库时,我们可能会看到这样的使用方式:gcc –o test main.c libtest1.a libtest2.a libtest1.a。在链接序列中,一个静态库可能出现多次,以解决一些循环依赖。
那么如果是gcc -o test main.c -Xlinker “-(” libtest1.a libtest2.a -Xlinker “-)”的使用方式,还需要考虑顺序么?
答案是不需要。
因为Xlinker选项是将参数传给链接器,而man ld我们可以看到这样一段说明:
- -( archives -)
- --start-group archives --end-group
- The archives should be a list of archive files. They may be either explicit file names, or -l options.
- <strong>The specified archives are searched repeatedly until no new undefined references are created.</strong> Normally, an archive is
- searched only once in the order that it is specified on the command line. If a symbol in that archive is needed to
- resolve an undefined symbol referred to by an object in an archive that appears later on the command line, the linker
- would not be able to resolve that reference. By grouping the archives, they all be searched repeatedly until all pos-
- sible references are resolved.
- Using this option has a significant performance cost. It is best to use it only when there are unavoidable circular
- references between two or more archives.
链接器在处理”-(”和”-)”之间的静态库时,是会重复查找这些静态库的,所以就解决了静态库查找顺序问题。不过,man里面也说明了,这种方式比人工提供了链接顺序的方式效率会低很多。