linux把静态库加入环境变量,linux下的静态库和动态库

linux下的库文件分成静态库和动态库。库文件的产生也是有道理的。比如某些函数我经常用到,最好的办法就是放入库文件中。比如我是做科学运算的,计算最大公约数,最小公倍数,阶乘能运算经常遇到,但是每次做一个项目,我就写一份函数,那太麻烦了。那我们就可以把这些公用的,经常需要调用的函数,封装成库,供不同的项目使用。

下面是一个计算阶乘的函数,文件名为factorial.c

int factorial( int n)

{

if(n <= 1)

{

return 1;

}

else

{

return n*factorial(n-1);

}

}第二个文件是cmp.c,比较两个int型的大小。

int cmp(int a,int b)

{

return a-b;

}我们通过gcc生成对应的obj文件。

root@libin:~/program/C/testlib/lib# ll

总用量 16

drwxr-xr-x 2 root root 4096 2012-07-27 20:08 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 41 2012-07-26 22:50 cmp.c

-rw-r--r-- 1 root root 115 2012-07-27 20:07 factorial.c

root@libin:~/program/C/testlib/lib# gcc -c *.c

root@libin:~/program/C/testlib/lib# ll

总用量 24

drwxr-xr-x 2 root root 4096 2012-07-27 20:08 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 41 2012-07-26 22:50 cmp.c

-rw-r--r-- 1 root root 679 2012-07-27 20:08 cmp.o

-rw-r--r-- 1 root root 115 2012-07-27 20:07 factorial.c

-rw-r--r-- 1 root root 764 2012-07-27 20:08 factorial.o看到了我们生成了cmp.o和factoria.o文件。现在我们用ar命令将两个obj文件打包。

root@libin:~/program/C/testlib/lib# ar rs libmymath.a *.o

ar: creating libmymath.a

root@libin:~/program/C/testlib/lib# ll

总用量 28

drwxr-xr-x 2 root root 4096 2012-07-27 20:19 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 41 2012-07-26 22:50 cmp.c

-rw-r--r-- 1 root root 679 2012-07-27 20:08 cmp.o

-rw-r--r-- 1 root root 115 2012-07-27 20:07 factorial.c

-rw-r--r-- 1 root root 764 2012-07-27 20:08 factorial.o

-rw-r--r-- 1 root root 1658 2012-07-27 20:19 libmymath.a已经生成了静态库。如果我们拿到了一个静态库,想知道它是哪些obj文件打包而成,可以使用如下命令:

root@libin:~/program/C/testlib/lib# ar tv libmymath.a

rw-r--r-- 0/0    679 Jul 27 20:08 2012 cmp.o

rw-r--r-- 0/0    764 Jul 27 20:08 2012 factorial.o

用户如果libpthread.a的是有那些库打包生成的可以使用同样的命令观看。太多了,我就不列了。

ar是打包的命令,既然打包,必然也有对应的解包:

root@libin:~/program/C/testlib/lib# rm *.o

root@libin:~/program/C/testlib/lib# ll

总用量 20

drwxr-xr-x 2 root root 4096 2012-07-27 20:24 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 41 2012-07-26 22:50 cmp.c

-rw-r--r-- 1 root root 115 2012-07-27 20:07 factorial.c

-rw-r--r-- 1 root root 1658 2012-07-27 20:19 libmymath.a我们看到,已经将所有的obj文件删除。 现在从静态库中将obj文件解出来

root@libin:~/program/C/testlib/lib# ar x libmymath.a

root@libin:~/program/C/testlib/lib# ll

总用量 28

drwxr-xr-x 2 root root 4096 2012-07-27 20:42 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 41 2012-07-26 22:50 cmp.c

-rw-r--r-- 1 root root 679 2012-07-27 20:42 cmp.o

-rw-r--r-- 1 root root 115 2012-07-27 20:07 factorial.c

-rw-r--r-- 1 root root 764 2012-07-27 20:42 factorial.o

-rw-r--r-- 1 root root 1658 2012-07-27 20:19 libmymath.a如果要保留obj文件的原始属性,比如时间那么需要o选项 ,即:

root@libin:~/program/C/testlib/lib# ar xo libmymath.a

root@libin:~/program/C/testlib/lib# ll

总用量 28

drwxr-xr-x 2 root root 4096 2012-07-27 20:42 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 41 2012-07-26 22:50 cmp.c

-rw-r--r-- 1 root root 679 2012-07-27 20:08 cmp.o

-rw-r--r-- 1 root root 115 2012-07-27 20:07 factorial.c

-rw-r--r-- 1 root root 764 2012-07-27 20:08 factorial.o

-rw-r--r-- 1 root root 1658 2012-07-27 20:19 libmymath.aOK,我们已经得到了静态库,那么开始调用静态库,来做一些事情。

#include

#include

int main(int argc ,char* argv[])

{

int a = 4;

int b = 5;

int f_a = factorial(a);

int f_b = factorial(b);

while(1)

{

if(cmp(f_a,f_b))

{

printf("f_a is bigger than f_b\n");

}

else

{

printf("f_a is not bigger than f_b\n");

}

sleep(100);

}

return 0;

}下面我们看下不使用静态库能否编译通过。

root@libin:~/program/C/testlib/use# gcc -o test test.c

/tmp/ccZM4LMy.o: In function `main':

test.c:(.text+0x21): undefined reference to `factorial'

test.c:(.text+0x31): undefined reference to `factorial'

test.c:(.text+0x49): undefined reference to `cmp'

collect2: ld returned 1 exit status链接的时候报错了,原因是找不到factorial和cmp两个函数的定义。下面我们使用静态库

root@libin:~/program/C/testlib/use# gcc -o test test.c -L ../lib/ -lmymath

root@libin:~/program/C/testlib/use# ll

总用量 20

drwxr-xr-x 2 root root 4096 2012-07-27 21:01 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rwxr-xr-x 1 root root 7307 2012-07-27 21:01 test*

-rw-r--r-- 1 root root 405 2012-07-26 23:12 test.c-L选项是告诉gcc,去什么目录下找库文件,默认查找路径是

/lib/

/usr/lib

/usr/local/lib

对这个问题感兴趣的可以去看俞甲子的程序员的自我修养第八章的内容。如果我们不使用-L就会出现:

root@libin:~/program/C/testlib/use# gcc -o test test.c -lmymath

/usr/bin/ld: cannot find -lmymath

collect2: ld returned 1 exit status

root@libin:~/program/C/testlib/use#链接器找不到这个库文件。

当然,链接器并不知道它找的是libmymath.a,它会优先找动态库libmymath.so,找不到了,才会寻找libmymath.a。不管怎么说,我们使用静态库生成了可执行文件.

不用静态库,直接使用obj文件,一样也是可以生成最终的可执行文件。

root@libin:~/program/C/testlib/use# rm test

root@libin:~/program/C/testlib/use# ll

总用量 12

drwxr-xr-x 2 root root 4096 2012-07-27 21:29 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 405 2012-07-26 23:12 test.c

root@libin:~/program/C/testlib/use# gcc -o test test.c ../lib/cmp.o ../lib/factorial.o

root@libin:~/program/C/testlib/use# ll

总用量 20

drwxr-xr-x 2 root root 4096 2012-07-27 21:29 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rwxr-xr-x 1 root root 7307 2012-07-27 21:29 test*

-rw-r--r-- 1 root root 405 2012-07-26 23:12 test.c     注意,对于静态库生成的可执行文件,里面包含了静态库打包的obj文件对应汇编代码换句话说,就是你删除了静态库,生成的test一样可以顺利的执行。因为,factorial.c和cmp.c定义的函数,在test可执行文件里面都有汇编代码。这也是使用静态库被人诟病的地方。如果静态库非常大,那么生成的可执行文件也会比较大。

我们证明下test中一定会有cmp函数和factorial函数的汇编指令。

root@libin:~/program/C/testlib/use# gcc -o test test.c -L ../lib/ -lmymath

root@libin:~/program/C/testlib/use# ll

总用量 20

drwxr-xr-x 2 root root 4096 2012-07-27 21:36 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rwxr-xr-x 1 root root 7307 2012-07-27 21:36 test*

-rw-r--r-- 1 root root 405 2012-07-26 23:12 test.c

root@libin:~/program/C/testlib/use# objdump -S test

。。。

08048490 :

8048490:55                   push   %ebp

8048491:89 e5                mov    %esp,%ebp

8048493:8b 45 0c             mov    0xc(%ebp),%eax

8048496:8b 55 08             mov    0x8(%ebp),%edx

8048499:89 d1                mov    %edx,%ecx

804849b:29 c1                sub    %eax,%ecx

804849d:89 c8                mov    %ecx,%eax

804849f:5d                   pop    %ebp

80484a0:c3                   ret

80484a1:90                   nop

80484a2:90                   nop

80484a3:90                   nop

080484a4 :

80484a4:55                   push   %ebp

80484a5:89 e5                mov    %esp,%ebp

80484a7:83 ec 18             sub    $0x18,%esp

80484aa:83 7d 08 01          cmpl   $0x1,0x8(%ebp)

80484ae:7f 07                jg     80484b7

80484b0:b8 01 00 00 00       mov    $0x1,%eax

80484b5:eb 12                jmp    80484c9

80484b7:8b 45 08             mov    0x8(%ebp),%eax

80484ba:83 e8 01             sub    $0x1,%eax

80484bd:89 04 24             mov    %eax,(%esp)

80484c0:e8 df ff ff ff       call   80484a4

80484c5:0f af 45 08          imul   0x8(%ebp),%eax

80484c9:c9                   leave

80484ca:c3                   ret

80484cb:90                   nop

80484cc:90                   nop

80484cd:90                   nop

80484ce:90                   nop

80484cf:90                   nop删除了libmymath.a,一样可以正常的跑

root@libin:~/program/C/testlib/use# rm ../lib/libmymath.a

root@libin:~/program/C/testlib/use# ./test

f_a is bigger than f_b----------------------------------------------------------------------------------------------------------------------

OK,我们可以考虑下动态库了。动态库出现的要比静态库晚,是为了解决每个使用到静态库的程序,都会有的一份库拷贝,我们上面也看到了,删掉静态库也不影响程序的执行,原因就是程序中已经有了静态库的拷贝,objdump出的内容可以证明这一点。

动态库可以被多个程序共享,如果程序是链接动态库生成的,如果动态库被删除,那么自己的程序就无法运行。

先生成动态库再说。

root@libin:~/program/C/testlib/lib# ll

总用量 16

drwxr-xr-x 2 root root 4096 2012-07-27 21:44 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 41 2012-07-26 22:50 cmp.c

-rw-r--r-- 1 root root 115 2012-07-27 20:07 factorial.c

root@libin:~/program/C/testlib/lib# gcc -shared -o libmymath.so *.c

root@libin:~/program/C/testlib/lib# ll

总用量 24

drwxr-xr-x 2 root root 4096 2012-07-27 21:44 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 41 2012-07-26 22:50 cmp.c

-rw-r--r-- 1 root root 115 2012-07-27 20:07 factorial.c

-rwxr-xr-x 1 root root 6688 2012-07-27 21:44 libmymath.so*还有一个选项是地址无关选项-fPIC。打开这个选项生成的动态库具有地址无关的特点,方便多个进程共享一份动态库对应的指令。这个不是我们关心的内容,如果看官感兴趣的话,可以阅读俞甲子的著作。

下面用动态库来生成我们的程序,还是使用test.c

root@libin:~/program/C/testlib/use# ll

总用量 12

drwxr-xr-x 2 root root 4096 2012-07-27 21:57 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 405 2012-07-26 23:12 test.c

root@libin:~/program/C/testlib/use# gcc -o test test.c -L ../lib/ -lmymath

root@libin:~/program/C/testlib/use# ll

总用量 20

drwxr-xr-x 2 root root 4096 2012-07-27 21:57 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rwxr-xr-x 1 root root 7265 2012-07-27 21:57 test*

-rw-r--r-- 1 root root 405 2012-07-26 23:12 test.c

root@libin:~/program/C/testlib/use# ./test

./test: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory前面提到了,用动态库生成的程序,程序中并没有动态库中函数的汇编指令。看下面的证明:

root@libin:~/program/C/testlib/use# objdump -d test

test: file format elf32-i38

....

08048564 :

8048564:    55     push %ebp

8048565:    89 e5     mov %esp,%ebp

8048567:    83 e4 f0     and $0xfffffff0,%esp

804856a:    83 ec 20     sub $0x20,%esp

804856d:    c7 44 24 1c 04 00 00     movl $0x4,0x1c(%esp)

8048574:    00

8048575:    c7 44 24 18 05 00 00     movl $0x5,0x18(%esp)

804857c:    00

804857d:    8b 44 24 1c     mov 0x1c(%esp),%eax

8048581:    89 04 24     mov %eax,(%esp)

8048584:    e8 f3 fe ff ff     call 804847c

8048589:    89 44 24 14     mov %eax,0x14(%esp)

804858d:    8b 44 24 18     mov 0x18(%esp),%eax

8048591:    89 04 24     mov %eax,(%esp)

8048594:    e8 e3 fe ff ff     call 804847c

8048599:    89 44 24 10     mov %eax,0x10(%esp)

804859d:    8b 44 24 10     mov 0x10(%esp),%eax

80485a1:    89 44 24 04     mov %eax,0x4(%esp)

80485a5:    8b 44 24 14     mov 0x14(%esp),%eax

80485a9:    89 04 24     mov %eax,(%esp)

80485ac:    e8 bb fe ff ff     call 804846c

80485b1:    85 c0     test %eax,%eax

80485b3:    74 0e     je 80485c3

80485b5:    c7 04 24 a0 86 04 08     movl $0x80486a0,(%esp)

80485bc:    e8 db fe ff ff     call 804849c

80485c1:    eb 0c     jmp 80485cf

80485c3:    c7 04 24 b7 86 04 08     movl $0x80486b7,(%esp)

80485ca:    e8 cd fe ff ff     call 804849c

80485cf:    c7 04 24 64 00 00 00     movl $0x64,(%esp)

80485d6:    e8 b1 fe ff ff     call 804848c

80485db:    eb c0     jmp 804859d

80485dd:    90     nop

80485de:    90     nop

80485df:    90     nop

....cmp@plt这个表示的是我的这个指令码不在本文件,plt是延迟绑定,感兴趣的可以阅读本人的。

现在的问题是,找不到动态库。系统搜索动态库的默认是:

/lib/

/usr/lib

将我们的动态库搬到默认搜索路径,这是一个办法:

root@libin:~/program/C/testlib/use# mv ../lib/libmymath.so /usr/lib/

root@libin:~/program/C/testlib/use# ./test

f_a is bigger than f_b另一种可行的办法是修改/etc/ld.so.conf文件,在文件中加入我们动态库所在的目录。

root@libin:~/program/C/testlib/use# cat /etc/ld.so.conf

include /etc/ld.so.conf.d/*.conf

/home/libin/program/C/testlib/lib/

root@libin:~/program/C/testlib/use# mv /usr/lib/libmymath.so ../lib/

root@libin:~/program/C/testlib/use# ll ../lib/

cmp.c factorial.c libmymath.so

root@libin:~/program/C/testlib/use# ll ../lib/

总用量 24

drwxr-xr-x 2 root root 4096 2012-07-27 22:25 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 41 2012-07-26 22:50 cmp.c

-rw-r--r-- 1 root root 115 2012-07-27 20:07 factorial.c

-rwxr-xr-x 1 root root 6688 2012-07-27 21:44 libmymath.so*

root@libin:~/program/C/testlib/use# ll

总用量 20

drwxr-xr-x 2 root root 4096 2012-07-27 22:05 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rwxr-xr-x 1 root root 7265 2012-07-27 21:57 test*

-rw-r--r-- 1 root root 405 2012-07-26 23:12 test.c执行以下,看下结果:

root@libin:~/program/C/testlib/use# ll

总用量 20

drwxr-xr-x 2 root root 4096 2012-07-27 22:05 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rwxr-xr-x 1 root root 7265 2012-07-27 21:57 test*

-rw-r--r-- 1 root root 405 2012-07-26 23:12 test.c

root@libin:~/program/C/testlib/use# ./test

./test: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory还是不行,原因是执行ldconfig,刚才的修改没有生效:

root@libin:~/program/C/testlib/use# ldconfig

root@libin:~/program/C/testlib/use# ./test

f_a is bigger than f_b还有在一种方式是修改LD_LIBRARY_PATH,这种方式不被推荐使用,我就不写它了。最后一种方式是最好的,编译链接的时候,指定Run-time path.

gcc 有选项为 -Wl,-rpath,  这个是指定Run-time path的,注意是小写的字母L,不是数字1. 另外,-Wl,rpath之间不能有空格。

root@libin:~/program/C/testlib/use# rm test

root@libin:~/program/C/testlib/use# ll

总用量 12

drwxr-xr-x 2 root root 4096 2012-07-28 00:30 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rw-r--r-- 1 root root 405 2012-07-26 23:12 test.c

root@libin:~/program/C/testlib/use# gcc -o test test.c -L ../lib/ -lmymath -Wl,-rpath, ../lib/libmymath.so

root@libin:~/program/C/testlib/use# ll

总用量 20

drwxr-xr-x 2 root root 4096 2012-07-28 00:30 ./

drwxr-xr-x 5 root root 4096 2012-07-27 19:05 ../

-rwxr-xr-x 1 root root 7265 2012-07-28 00:30 test*

-rw-r--r-- 1 root root 405 2012-07-26 23:12 test.c

root@libin:~/program/C/testlib/use# ./test

f_a is bigger than f_b想深入了解这个共享库的可以阅读Ulrich Drepper大神的How to write shared library。

给出搜索路径的优先级

1.编译目标代码时指定的动态库搜索路径;//-wl.-rpath

2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;//不推荐使用

3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;//本文提到了

4.默认的动态库搜索路径/lib;

5.默认的动态库搜索路径/usr/lib。

注:64位机器自动找lib64库

如何查看一个可执行文件需要那些动态库的支持呢?ldd命令

root@libin:~/program/C/testlib/use# ldd test

linux-gate.so.1 => (0x002dd000)

libmymath.so => /home/libin/program/C/testlib/lib/libmymath.so (0x00d81000)

libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00110000)

/lib/ld-linux.so.2 (0x00f9e000)

————————————————————————————————————————————

题外话,不知道各位看管注意到没有,本文没有头文件的包含,也就说说我虽然定义了factorial 函数和cmp函数,但是我在test.c并没有包含头文件,也没有声明这两个函数。这和我们平时的编程习惯是不符合的。想想我们编写多线程代码,一般都为#include ,链接的时候 -lpthread。这才是common的流程。

WHY?这是下一篇文章的主题。我们真的需要头文件吗?

参考文献:

1 俞甲子等的程序员的自我修养

2 Ulrich Drepper大神的 How to write shared library

3 Why LD_LIBRARY_PATH is bad

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值