Date

先关注两个gcc编译选项:

  1. -c 编译且汇编,但是不链接
  2. -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 xxx"的链接错误,其中xxx就是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里面也说明了,这种方式比人工提供了链接顺序的方式效率会低很多。