GCC编译使⽤动态链接库和静态链接库--及先后顺序----及环境
变量设置总结
阅读⽬录
1 库的分类
根据链接时期的不同,库⼜有静态库和动态库之分。
静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以⽣成的可执⾏⽂件就不受库的影响了,即使库被删除了,程序依然可以成功运⾏。
有别于静态库,动态库的链接是在程序执⾏的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序运⾏时调⽤。(TODO:链接动态库时链接阶段到底做了什么)
2 静态库和动态库的⽐较
链接静态库其实从某种意义上来说也是⼀种粘贴复制,只不过它操作的对象是⽬标代码⽽不是源码⽽已。因为静态库被链接后库就直接嵌⼊可执⾏⽂件中了,这样就带来了两个问题。
⾸先就是系统空间被浪费了。这是显⽽易见的,想象⼀下,如果多个程序链接了同⼀个库,则每⼀个⽣成的可执⾏⽂件就都会有⼀个库的副本,必然会浪费系统空间。
再者,⼈⾮圣贤,即使是精⼼调试的库,也难免会有错。⼀旦发现了库中有bug,挽救起来就⽐较⿇烦了。必须⼀⼀把链接该库的程序出来,然后重新编译。
⽽动态库的出现正弥补了静态库的以上弊端。因为动态库是在程序运⾏时被链接的,所以磁盘上只须保留⼀份副本,因此节约了磁盘空间。如果发现了bug或要升级也很简单,只要⽤新的库把原来的替换掉就⾏了。
那么,是不是静态库就⼀⽆是处了呢?
答⽈:⾮也⾮也。不是有句话么:存在即是合理。静态库既然没有湮没在滔滔的历史长河中,就必然有它的⽤武之地。想象⼀下这样的情况:如果你⽤libpcap库编了⼀个程序,要给被⼈运⾏,⽽他的系统上没有装pcap库,该怎么解决呢?最简单的办法就是编译该程序时把所有要链接的库都链接它们的静态库,这样,就可以在别⼈的系统上直接运⾏该程序了。
所谓有得必有失,正因为动态库在程序运⾏时被链接,故程序的运⾏速度和链接静态库的版本相⽐必然会打折扣。然⽽瑕不掩瑜,动态库的不⾜相对于它带来的好处在现今硬件下简直是微不⾜道的,所以链接程序在链接时⼀般是优先链接动态库的,除⾮⽤-static参数指定链接静态库。
动态链接库
1. 创建动态链接库
1. #include<stdio.h>
2. void hello()
3. {
4. printf("hello world/n");
5. }
⽤命令gcc -shared hello.c -o libhello.so编译为动态库。可以看到,当前⽬录下多了⼀个⽂件libhello.so。
2. 再编辑⼀个测试⽂件test.c,内容如下
1. #include<stdio.h>
2. int main()
3. {
4. printf("call hello()");
5. hello();
6. }
编译 gcc test.c -lhello
-l 选项告诉编译器要使⽤hello这个库。奇怪的地⽅是动态库的名字是libhello.so,这⾥却使⽤hello.
但这样还不⾏,编译会出错。
In function `main':
test.c:(.text+0x1d): undefined reference to `hello'
collect2: ld returned 1 exit status
这是因为hello这个库在我们⾃⼰的路径中,编译器不到。
需要使⽤-L选项,告诉hello库的位置
gcc test.c -lhello -L. -o test
-L .告诉编译器在当前⽬录中查库⽂件
3. 编译成功后执⾏./test, 仍然出错
说不到库
有两种⽅法:
⼀、可以把当前路径加⼊ /etc/f中然后运⾏ldconfig,或者以当前路径为参数运⾏ldconfig(要有root权限才⾏)。
⼆、把当前路径加⼊环境变量LD_LIBRARY_PATH中
当然,如果你觉得不会引起混乱的话,可以直接把该库拷⼊/lib,/usr/lib/等位置(⽆可避免,这样做也要有权限),这样链接器和加载器就都可以准确的到该库了。
我们采⽤第⼆种⽅法:
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
这样,再执⾏就成功了。
下⾯再讲讲静态链接库
仍使⽤刚才的hello.c和test.c。
1. gcc -c hello.c 注意这⾥没有使⽤-shared选项
2. 把⽬标⽂件归档 ar -r libhello.a hello.o
程序 ar 配合参数 -r 创建⼀个新库 libhello.a 并将命令⾏中列出的对象⽂件插⼊。采⽤这种⽅法,如果库不存在的话,参数 -r 将创建⼀个新的库,⽽如果库存在的话,将⽤新的模块替换原来的模块。
3. 在程序中链接静态库
gcc test.c -lhello -L. -static -o hello.static
或者 gcc test.c libhello.a -L. -o hello.static
⽣成的hello.static就不再依赖libhello.a了
file和ldd命令
file程序是⽤来判断⽂件类型的,在file命令下,所有⽂件都会原形毕露的。
顺便说⼀个技巧。有时在 windows下⽤浏览器下载或tar.bz2⽂件,后缀名会变成奇怪的tar.tar,到有些新⼿就不知怎么解压了。但Linux下的⽂件类型并不受⽂件后缀名的影响,所以我们可以先⽤命令file xxx.tar.tar看⼀下⽂件类型,然后⽤tar加适当的参数解压。
另外,还可以借助程序ldd实⽤程序来判断。
ldd是⽤来打印⽬标程序(由命令⾏参数指定)所链接的所有动态库的信息的,如果⽬标程序没有链接动态库,则打印“not a dynamic executable”,ldd的⽤法请参考manpage。
1,如何⽣成静态库
静态库只是⼀堆object对象的集合,使⽤ar命令可以将.o⽂件打包成.a静态库。
假设gcc已经⽣成了a.o, b.o, c.o,使⽤下⾯的命令即可⽣成libmylib.a
java设置环境变量的方法代码#ar rcs libmylib.a a.o b.o c.o
2,如何⽣成动态库
动态库的⽣成由gcc直接⽣成。
假设a.c, b.c两个⽂件,通过下⾯的命令可⽣成libmylib.so
#gcc a.c b.c -o libmylib.so --shared
3,如何使⽤库
gcc中关于库的参数有:
-L 指定搜寻库的⽬录
如指定当前⽬录 gcc -L .
-l 指定要链接的库的名称
加⼊库的名称是libmylib.a,则gcc -l mylib,即去头去尾。
--static 组织在链接时使⽤动态库
-
-shared ⽣成动态库
--static-libgcc 链接静态libgcc库
--shared-libgcc 链接动态libgcc库
可见对动态库和静态库的使⽤⽅法是⼀样的,同⼀个库如果同时存在动态库和静态库,优先链接动态库,除⾮使⽤--static强制使⽤静态库。
gcc -lXXX 如何选择静态库还是动态库?
库标准路径下存在libABC.a和libABC.so使⽤gcc -lABC如何选择连接静态连接库或者动态连接库?通过--hare --static选项?
答:如果在同⼀路径下⾯,并且两种库同名,这样会选择动态库。
gcc 混合连接动态库和静态库
问:gcc 同时连接 静态库和动态库现在有 libmy.a & libmy.so两个库,其中的函数供调⽤要在可执⾏⽂件中同时连接这两个库gcc -g -lstdc++ -g -L. -lmy -l ./libmy.a - // 报不到libmy.a,可是在当前⽬录下已经有这个⽂件了gcc -g -
lstdc++ -g -L. -l libmy.so -l ./libmy.a - // 报不到libmy.so,在当前⽬录下也有这个⽂件⽤了 -static 选线,则报动态库中的函数没定义请问⼤家有什么招不?感激
答:记得静态库混合动态库要加特殊指令的,你可以试试这样:gcc -g -lstdc++ -g -WI,-Bdynamic -L. -lmy -WI,-Bstatic -L. -lmy -
gcc优先链接动态库,不到,才链接静态库
gcc链接时 -l 参数可否连接动态库?
g++编译时, ⽤-labc 选项后, 编译器会⾃动按照命名规则去搜索 libabc.a 库⽂件, 但如果我想使⽤动态链接库链接应如何指定参数?
优先链接共享库。共享库不到,才链接静态库。
可是如果我在 -l 选项后添加共享库, 则链接时报告库⽂件不存在, 共享库和静态库的命名规则是否⼀样?
例如我有⼀个名为 libabc.so, 我应采⽤什么格式的选项才可以在gcc命令中到它?
使⽤ -l 选项指定静态库和动态库的格式都是⼀样的,如果库⽂件名为libabc.so,那么就⽤ -labc 即可。
链接时会去搜索这个库⽂件,如果不是系统库,那么你需要告诉链接器它的路径。有两种⽅法:⼀种是在参数中⽤ -L 选项指定库⽂件搜索路径,可以并列多个。例如:gcc -L /home/ddd -L/home/ddd/lib。 另⼀种⽅法是在环境变量中设置LD_LIBRARY_PATH 包含有你的动态库⽂件所在的路径。这个环境变量⽤在Sorlarise和Linux,如果你是在HP-UX下,是SHLIB_PATH。
共享库⽂件在/usr/lib/⽬录下, 但是程序运⾏的时候还是不到是为什么?
allen@xps:~/Downloads/N-GenIC$ mpiexec -np 8 ./N-GenIC ics.param
/usr/local/bin/hydra_pmi_proxy: error while loading shared libraries: libcr.so.0: cannot open shared object file: No such file or directory
allen@xps:~$ locate libcr.so.0
/usr/lib/libcr.so.0
/usr/lib/libcr.so.0.5.5
已经尝试过ldconfig和LD_LIBRARY_PATH="/usr/lib" && export LD_LIBRARY_PATH但是都没⽤
现在通过google到了⼀种解决⽅法,就是sudo apt-get install libcr-dev,执⾏之后程序就正常运⾏了. 但是查共享库libcr.so.0的结果还是
allen@xps:~$ locate libcr.so.0
/usr/lib/libcr.so.0
/usr/lib/libcr.so.0.5.5
不知道这中间发⽣了什么? 请解释⼀下
2 个回答
执⾏locate前先sudo updatedb⼀下。。
============
你试试把LIBRARY_PATH也设为那个⽬录,然后重新make⼀下。
export LIBRARY_PATH=/usr/lib:$LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论