Chinaunix首页 | 论坛 | 博客
  • 博客访问: 383949
  • 博文数量: 120
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 741
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-27 18:15
文章分类

全部博文(120)

文章存档

2016年(13)

2015年(41)

2014年(66)

我的朋友

分类: LINUX

2015-07-15 16:04:22

--whole-archive\--no-whole-archive:
为ld专有的命令,需要成对出现,gcc通过-Wl选项传递给ld
--whole-archive可以把在其后面出现的静态库包含的函数和变量输出到动态库,--no-whole-archive则关掉这个特性。
example:
把liba.a libb.a libc.a输出到libabc.so
Makefile的命令如下:
libabc.so:liba.a libb.a libc.a
    
gcc -shared -o $@ -L. -Wl,--whole-archive -la -lb -lc -Wl,--no-whole-archive
NOTE:在--whole-archive作用下的库里不能有函数同名。

-l(link的意思)参数:
-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?
对于ssh库来说,其库名为ssh,其库文件名是libssh.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了。
比如我们自已要用到一个第三方提供的库名字叫libtest.so,那么我们只要把libtest.so拷贝到/usr/lib里,编译时加上-ltest参数,我们就能用上libtest.so库了(当然要用libtest.so库里的函数,我们还需要与libtest.so配套的头文件)。
链接时默认去/lib和/usr/lib和/usr/local/lib寻找库

-L(Loacation的意思)参数
指定库所在位置。
    但如果库文件没有在标准目录下(/lib和/usr/lib和/usr/local/lib),而是放在其他目录里,这时我们只用-l参数的话,链接还是会出错,出错信息大概是:“/usr/bin/ld: cannot find-lxxx”,也就是链接程序ld在那3个目录里找不到libxxx.so,
这时参数-L就派上用场了,比如常用的X11的库,它放在/usr/X11R6/lib目录下,我们编译时就要用-L/usr/X11R6/lib -lX11参数,-L参数跟着的是库文件所在的目录名。
    再比如我们把libtest.so放在/a/b/c目录下,那链接参数就是-L/aaa/bbb/ccc -ltest另外,大部分libxxxx.so只是一个链接,以RH9为例,比如libm.so它链接到/lib/libm.so.x,/lib/libm.so.6又链接到/lib/libm-2.3.2.so,
    如果没有这样的链接,还是会出错,因为ld只会找libxxxx.so,所以如果你要用到xxxx库,而只有libxxxx.so.x或者libxxxx-x.x.x.so,做一个链接就可以了ln -sf libxxxx-x.x.x.so libxxxx.so
    手工来写链接参数总是很麻烦的,还好很多库开发包提供了生成链接参数的程序,名字一般叫xxxx-config,一般放在/usr/bin目录下,比如gtk1.2的链接参数生成程序是gtk-config,执行gtk-config --libs就能得到以下输出"-L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lglib -ldl -lXi -lXext -lX11 -lm"这就是编译一个gtk1.2程序所需的gtk链接参数,
    xxx-config除了--libs参数外还有一个参数是--cflags用来生成头文件包含目录的,也就是-I参数,在下面我们将会讲到。你可以试试执行gtk-config --libs --cflags,看看输出结果。
    现在的问题就是怎样用这些输出结果了,最笨的方法就是复制粘贴或者照抄,聪明的办法是在编译命令行里加入这个`xxxx-config --libs --cflags`,
比如编译一个gtk程序:gcc gtktest.c `gtk-config --libs --cflags`这样
就差不多了。注意`不是单引号,而是1键左边那个键。

--start-group\--end-group参数:
gcc -shared -o test -Wl,--start-group -lblahlib -Wl,--end-group
-Wl in gcc is to call “ld” from gcc
–start-group and –end-group are for repeatedly search lib for circular dependency.
注: Wl和--start-group / --end-group 之间不能有空格。

更详细的说明:
    -( archives -) or --start-group archives --end-group
    The archives should be a list of archive files. They may be either explicit file names, or -l options.
The specified archives are searched repeatedly until no new undefined references are created. 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 possible 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.

-Bsymbolic参数:
示强制采用本地的全局变量定义,这样就不会出现动态链接库的全局变量定义被应用程序/动态链接库中的同名定义给覆盖了!

-soname参数
指定动态库的soname(简单共享名,Short for shared object name),实际上为动态库建立一个软链接,链接名字为-soname所指定的名字
-soname的关键功能是它提供了兼容性的标准:
    当要升级系统中的一个库时,并且新库的soname和老库的soname一样,用旧库链接生成的程序使用新库依然能正常运行。这个特性使得在Linux下,升级使得共享库的程序和定位错误变得十分容易。

    在Linux中,应用程序通过使用soname,来指定所希望库的版本,库作者可以通过保留或改变soname来声明,哪些版本是兼容的,这使得程序员摆脱了共享库版本冲突问题的困扰。
    需要配合-fPIC参数来使用,不然不能成soname库。
    可以通过readelf -d来查看每个动态库的SONAME
1. 声明libto.so.1,并生成libto.so.1.2

点击(此处)折叠或打开

  1. [root@localhost c]# gcc -fPIC -shared -Wl,-soname,libto.so.1 -o libto.so.1.2 to.c
  2. [root@localhost c]# ls -lh
  3. -rwxr-xr-x 1 root root 4268 Jan 10 17:22 libto.so.1.2
  4. [root@localhost c]# ldconfig -n ./
  5. lrwxrwxrwx 1 root root 12 Jan 10 17:23 libto.so.1 -> libto.so.1.2
  6. -rwxr-xr-x 1 root root 4.2K Jan 10 17:22 libto.so.1.2

  7. [root@localhost c]# readelf -d libto.so.1.2
  8.  
  9. Dynamic section at offset 0x504 contains 21 entries:
  10.   Tag          Type           Name/Value
  11.  0x00000001    (NEEDED)      Shared library: [libc.so.6]
  12.  0x0000000e    (SONAME)      Library soname: [libto.so.1]
  13.  0x0000000c    (INIT)      0x2cc
  14.  0x0000000d    (FINI)      0x4c4
  15.  0x6ffffef5    (GNU_HASH)      0xb4
  16.  0x00000005    (STRTAB)      0x1b4
  17.  0x00000006    (SYMTAB)      0xf4
  18.  0x0000000a    (STRSZ)      150 (bytes)
  19.  0x0000000b    (SYMENT)      16 (bytes)
  20.  0x00000003    (PLTGOT)      0x15d8
  21.  0x00000002    (PLTRELSZ)      24 (bytes)
  22.  0x00000014    (PLTREL)      REL
  23.  0x00000017    (JMPREL)      0x2b4
  24.  0x00000011    (REL)      0x294
  25.  0x00000012    (RELSZ)      32 (bytes)
  26.  0x00000013    (RELENT)      8 (bytes)
  27.  0x6ffffffe    (VERNEED)      0x264
  28.  0x6fffffff    (VERNEEDNUM) 1
  29.  0x6ffffff0    (VERSYM)      0x24a
  30.  0x6ffffffa    (RELCOUNT) 1
  31.  0x00000000    (NULL)      0x0

2. 声明libto.so.1,并生成libto.so.1.3

点击(此处)折叠或打开

  1. [root@localhost c]# gcc -fPIC -shared -Wl,-soname,libto.so.1 -o libto.so.1.3 to.c
  2. [root@localhost c]# ls -lh
  3. lrwxrwxrwx 1 root root 12 Jan 10 17:23 libto.so.1 -> libto.so.1.2
  4. -rwxr-xr-x 1 root root 4.2K Jan 10 17:22 libto.so.1.2
  5. -rwxr-xr-x 1 root root 4.2K Jan 10 17:23 libto.so.1.3
  6. [root@localhost c]# ldconfig -n ./
  7. lrwxrwxrwx 1 root root 12 Jan 10 17:24 libto.so.1 -> libto.so.1.3 #重新ldconfig,指向新的库文件
  8. -rwxr-xr-x 1 root root 4.2K Jan 10 17:22 libto.so.1.2
  9. -rwxr-xr-x 1 root root 4.2K Jan 10 17:23 libto.so.1.3

  10. [root@localhost c]# readelf -d libto.so.1.3
  11.  
  12. Dynamic section at offset 0x504 contains 21 entries:
  13.   Tag      Type          Name/Value
  14.  0x00000001 (NEEDED)      Shared library: [libc.so.6]
  15.  0x0000000e (SONAME)      Library soname: [libto.so.1]
  16.  0x0000000c (INIT) 0x2cc
  17.  0x0000000d (FINI) 0x4c4
  18.  0x6ffffef5 (GNU_HASH) 0xb4
  19.  0x00000005 (STRTAB) 0x1b4
  20.  0x00000006 (SYMTAB) 0xf4
  21.  0x0000000a (STRSZ) 150 (bytes)
  22.  0x0000000b (SYMENT) 16 (bytes)
  23.  0x00000003 (PLTGOT) 0x15d8
  24.  0x00000002 (PLTRELSZ) 24 (bytes)
  25.  0x00000014 (PLTREL) REL
  26.  0x00000017 (JMPREL) 0x2b4
  27.  0x00000011 (REL) 0x294
  28.  0x00000012 (RELSZ) 32 (bytes)
  29.  0x00000013 (RELENT) 8 (bytes)
  30.  0x6ffffffe (VERNEED) 0x264
  31.  0x6fffffff (VERNEEDNUM) 1
  32.  0x6ffffff0 (VERSYM) 0x24a
  33.  0x6ffffffa (RELCOUNT) 1
  34.  0x00000000 (NULL) 0x0
    从1、2可以看出来,应用程序依赖的libto.so.1的名字没有变化,但是实际指向的库改变了,从libto.so.2变成了libto.so.3,这样就完成了库的升级,而不用重新编译应用程序。

3. 声明libto.so.2,并生成libto.so.1.4

点击(此处)折叠或打开

  1. [root@localhost c]# gcc -fPIC -shared -Wl,-soname,libto.so.2 -o libto.so.1.4 to.c
  2. [root@localhost c]# ls -lh
  3. lrwxrwxrwx 1 root root 12 Jan 10 17:24 libto.so.1 -> libto.so.1.3
  4. -rwxr-xr-x 1 root root 4.2K Jan 10 17:22 libto.so.1.2
  5. -rwxr-xr-x 1 root root 4.2K Jan 10 17:23 libto.so.1.3
  6. -rwxr-xr-x 1 root root 4.2K Jan 10 17:24 libto.so.1.4
  7. [root@localhost c]# ldconfig -n ./
  8. lrwxrwxrwx 1 root root 12 Jan 10 17:24 libto.so.1 -> libto.so.1.3 #重新ldconfig,不指向新的库文件,因为新库(1.4)的soname为libto.so.2
  9. -rwxr-xr-x 1 root root 4.2K Jan 10 17:22 libto.so.1.2
  10. -rwxr-xr-x 1 root root 4.2K Jan 10 17:23 libto.so.1.3
  11. -rwxr-xr-x 1 root root 4.2K Jan 10 17:24 libto.so.1.4
  12. lrwxrwxrwx 1 root root 12 Jan 10 17:24 libto.so.2 -> libto.so.1.4

  13. [root@localhost c]# readelf -d libto.so.1.4
  14.   
  15.   
  16. Dynamic section at offset 0x504 contains 21 entries:
  17.   Tag          Type          Name/Value
  18.  0x00000001 (NEEDED)          Shared library: [libc.so.6]
  19.  0x0000000e (SONAME)          Library soname: [libto.so.2]
  20.  0x0000000c (INIT) 0x2cc
  21.  0x0000000d (FINI) 0x4c4
  22.  0x6ffffef5 (GNU_HASH) 0xb4
  23.  0x00000005 (STRTAB) 0x1b4
  24.  0x00000006 (SYMTAB) 0xf4
  25.  0x0000000a (STRSZ) 150 (bytes)
  26.  0x0000000b (SYMENT) 16 (bytes)
  27.  0x00000003 (PLTGOT) 0x15d8
  28.  0x00000002 (PLTRELSZ) 24 (bytes)
  29.  0x00000014 (PLTREL) REL
  30.  0x00000017 (JMPREL) 0x2b4
  31.  0x00000011 (REL) 0x294
  32.  0x00000012 (RELSZ) 32 (bytes)
  33.  0x00000013 (RELENT) 8 (bytes)
  34.  0x6ffffffe (VERNEED) 0x264
  35.  0x6fffffff (VERNEEDNUM) 1
  36.  0x6ffffff0 (VERSYM) 0x24a
  37.  0x6ffffffa (RELCOUNT) 1
  38.  0x00000000 (NULL) 0x0
总结:程式库主要的升级会破坏相容性;而次要的升级则可能不会;那麽以下面的方式来连结,所有的一切就都会相安无事了。
gcc -shared -Wl,-soname,libfoo.so.major -o libfoo.so.major.minor
copy form:http://blog.csdn.net/gohome520/article/details/7259450


-c参数
编译或汇编源文件,不做连接。
g++ -c test.cpp输出test.o

-o参数:  
-o file:制定输出文件为file  

-Wall参数
输出所有编译警告(最好加上)
 
-Dmacro参数:
-Dmacro=XXX:定义宏。
 
-shared参数:
生成一个共享库文件
g++ -shared -o libtest.so test.o
 
-fPIC参数
生成位置无关目标代码,适用于动态连接。
 
-g参数:
产生调试信息
 
-olevel参数
优化级别,一般用o2

文件后缀名简述:
.o:目标文件,经过预编译、汇编、编译生成的文件
.a:静态库,由需要的.o文件组成,链接时拷贝到程序
.so:动态库,有需要的.o文件组成,运行时挂接到程序
    挂接so库有两种方式,一种是生成可执行程序时使用-l选项指定需要挂接的动态库(指定之后执行程序时,由内核自动open),第二种就是在程序运行时使用dlopen来打开库。两种方法都能成功使用so,只是使用需求不一样。前者主要是在依赖关系比较稳定的情况下使用,后者主要是依赖关系不稳定时使用,假设你的程序百分之百要使用到liba.so库,那么建议用-l选项,如果你的程序需要一个第三方库来实现某一个功能,有很多三方库可以实现这个功能,此时程序中就最好用dlopen来打开库,这样如果要换第三方库时,就不用重新编译应用程序了,只需要拿到新的三方库,拷贝到指定路劲,并重命名即可。

常用命令:
readelf:可以通过readelf -d来查看每个动态库的SONAME
ldd:显示程序依赖的同台共享库。  
file:查看文件格式信息。  
ldconfig:在搜寻目录下搜索出可以共享的动态链接库
ar:解压.a文件
nm:查看.so的符号
objdump:反汇编 -D
阅读(1334) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~