感谢支持
我们一直在努力

Linux 中的静态库和动态库简介及生成过程示例

在实际的软件开发项目中,不是每一行代码都需要我们亲自写。在我们的软件产品中,有一些代码(尤其是函数)的出现频率很高,它们可以被当作公共代码来反复使用。为了避免重复劳动,我们就把这些公共代码编译为库文件,供需要的程序调用。在Linux中,库分为静态库和动态库两种。

本文对静态库和动态库进行了详细的介绍,并用实际的C代码演示了这两种库的生成过程。

 

一、静态库和动态库简介

众所周知,程序一般需要经过预处理、编译、汇编和链接这几个步骤才能变成可执行的程序。在实际的软件开发中,对于一些需要被许多模块反复使用的公共代码,我们就将它们编译为库文件。

库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。Linux支持的库分为静态库和动态库,动态库又称共享库。一般说来,Linux中的一些重要的库是存放在lib目录下的。

静态库文件的后缀为.a,在Linux下一般命名为libxxx.a。在链接步骤中,连接器将从静态库文件中取得所需的代码,复制到生成的可执行文件中。因此,整个库中的所有函数都被编译进了目标代码中。

动态库文件的后缀为.so,在Linux下一般命名为libxxx.so。相对于静态库,动态库在编译的时候并没有被编译进目标代码中,而是程序执行到相关函数时才调用库中对应的函数。

可以看到,静态库的优点是编译后的执行程序不需要外部的函数库支持,缺点是如果静态函数库改变了,那么你的程序必须重新编译;而动态库在多个应用程序都要使用同一函数库的时候就非常适合,但前提是程序的运行环境中必须提供相应的库。
不管是静态库,还是动态库,都是由*.o目标文件生成的。

 

二、静态库生成示例

 

1.单个文件生成静态库示例

我们编写如下简单的三个程序文件:test.h、test.c和main.c,在main.c中要调用test.c中实现的函数test。
test.h文件内容:

  1. #include<stdio.h>
  2. voidtest();

test.c文件内容:

  1. #include"test.h"
  2. voidtest()
  3. {
  4. printf("this is in test......\n");
  5. }

main.c文件内容:

  1. #include"test.h"
  2. int main()
  3. {
  4. test();
  5. return0;
  6. }

将此三个文件上传到Linux机器上,编译生成静态库文件,之后调用库文件的整个过程如下所示:

  1. ~/zhouzhaoxiong/zzx/mytest/a/singlell
  2. -rw-------1 zhou dba 53Nov  416:04 main.c
  3. -rw-------1 zhou dba 80Nov  416:04test.c
  4. -rw-------1 zhou dba 36Nov  416:04test.h
  5. ~/zhouzhaoxiong/zzx/mytest/a/singlegcc-c test.c
  6. ~/zhouzhaoxiong/zzx/mytest/a/single> ll
  7. -rw-------1 zhou dba   53Nov  416:04 main.c
  8. -rw-------1 zhou dba   80Nov  416:04test.c
  9. -rw-------1 zhou dba   36Nov  416:04test.h
  10. -rw-rw-rw-1 zhou dba 1624Nov  416:06test.o
  11. ~/zhouzhaoxiong/zzx/mytest/a/singlear -r libtest.a test.o
  12. ar: creating libtest.a
  13. ~/zhouzhaoxiong/zzx/mytest/a/singlell
  14. -rw-------1 zhou dba   53Nov  416:04 main.c
  15. -rw-rw-rw-1 zhou dba 1766Nov  416:06 libtest.a
  16. -rw-------1 zhou dba   80Nov  416:04test.c
  17. -rw-------1 zhou dba   36Nov  416:04test.h
  18. -rw-rw-rw-1 zhou dba 1624Nov  416:06test.o
  19. ~/zhouzhaoxiong/zzx/mytest/a/singlegcc-o test main.c libtest.a
  20. ~/zhouzhaoxiong/zzx/mytest/a/singlell
  21. -rw-------1 zhou dba    52Nov  416:09 main.c
  22. -rwxrwxrwx 1 zhou dba 11876Nov  416:09test
  23. -rw-rw-rw-1 zhou dba  1766Nov  416:06 libtest.a
  24. -rw-------1 zhou dba    80Nov  416:04test.c
  25. -rw-------1 zhou dba    36Nov  416:04test.h
  26. -rw-rw-rw-1 zhou dba  1624Nov  416:06test.o
  27. ~/zhouzhaoxiong/zzx/mytest/a/single> ./test
  28. thisisintest......

我们可以看到,生成库文件的命令是“ar -r libtest.a test.o”,而将静态库文件编译进代码的命令是“gcc -o test main.c libtest.a”。

这样生成了静态库文件libtest.a之后,如果还有其他程序要调用test.c中实现的函数,只需要将test.h和libtest.a拷贝到对应的代码工程中,然后执行类似“gcc -o test main.c libtest.a”这样的命令即可。

 

2.多个文件生成静态库示例

我们编写如下简单的五个程序文件:test.h、test_1.c、test_2.c、test_3.c和main.c,在main.c中要调用test_1.c、test_2.c、test_3.c中实现的函数test_1、test_2、test_3。

test.h文件内容:

  1. #include<stdio.h>
  2. void test_1();
  3. void test_2();
  4. void test_3();

test_1.c文件内容:

  1. #include"test.h"
  2. void test_1()
  3. {
  4. printf("this is in test_1......\n");
  5. }

test_2.c文件内容:

  1. #include"test.h"
  2. void test_2()
  3. {
  4. printf("this is in test_2......\n");
  5. }

test_3.c文件内容:

  1. #include"test.h"
  2. void test_3()
  3. {
  4. printf("this is in test_3......\n");
  5. }

main.c文件内容:

  1. #include"test.h"
  2. int main()
  3. {
  4. test_1();
  5. test_2();
  6. test_3();
  7. return0;
  8. }

将此五个文件上传到Linux机器上,编译生成静态库文件,之后调用库文件的整个过程如下所示:

  1. ~/zhouzhaoxiong/zzx/mytest/a/more> ll
  2. -rw-------1 zxin10 dba 96Nov  416:11 main.c
  3. -rw-------1 zxin10 dba 70Nov  416:04test.h
  4. -rw-------1 zxin10 dba 84Nov  416:04 test_1.c
  5. -rw-------1 zxin10 dba 84Nov  416:04 test_2.c
  6. -rw-------1 zxin10 dba 84Nov  416:04 test_3.c
  7. ~/zhouzhaoxiong/zzx/mytest/a/moregcc-c test_1.c test_2.c test_3.c
  8. ~/zhouzhaoxiong/zzx/mytest/a/more> ll
  9. -rw-------1 zxin10 dba   96Nov  416:11 main.c
  10. -rw-------1 zxin10 dba   70Nov  416:04test.h
  11. -rw-------1 zxin10 dba   84Nov  416:04 test_1.c
  12. -rw-rw-rw-1 zxin10 dba 1624Nov  416:15 test_1.o
  13. -rw-------1 zxin10 dba   84Nov  416:04 test_2.c
  14. -rw-rw-rw-1 zxin10 dba 1624Nov  416:15 test_2.o
  15. -rw-------1 zxin10 dba   84Nov  416:04 test_3.c
  16. -rw-rw-rw-1 zxin10 dba 1624Nov  416:15 test_3.o
  17. ~/zhouzhaoxiong/zzx/mytest/a/morear -r libtest.a test_1.o test_2.o test_3.o
  18. ar: creating libtest.a
  19. ~/zhouzhaoxiong/zzx/mytest/a/more> ll
  20. -rw-------1 zxin10 dba   96Nov  416:11 main.c
  21. -rw-rw-rw-1 zxin10 dba 5158Nov  416:15 libtest.a
  22. -rw-------1 zxin10 dba   70Nov  416:04test.h
  23. -rw-------1 zxin10 dba   84Nov  416:04 test_1.c
  24. -rw-rw-rw-1 zxin10 dba 1624Nov  416:15 test_1.o
  25. -rw-------1 zxin10 dba   84Nov  416:04 test_2.c
  26. -rw-rw-rw-1 zxin10 dba 1624Nov  416:15 test_2.o
  27. -rw-------1 zxin10 dba   84Nov  416:04 test_3.c
  28. -rw-rw-rw-1 zxin10 dba 1624Nov  416:15 test_3.o
  29. ~/zhouzhaoxiong/zzx/mytest/a/moregcc-o test main.c libtest.a
  30. ~/zhouzhaoxiong/zzx/mytest/a/more> ll
  31. -rw-------1 zxin10 dba    96Nov  416:11 main.c
  32. -rwxrwxrwx 1 zxin10 dba 12008Nov  416:16test
  33. -rw-rw-rw-1 zxin10 dba  5158Nov  416:15 libtest.a
  34. -rw-------1 zxin10 dba    70Nov  416:04test.h
  35. -rw-------1 zxin10 dba    84Nov  416:04 test_1.c
  36. -rw-rw-rw-1 zxin10 dba  1624Nov  416:15 test_1.o
  37. -rw-------1 zxin10 dba    84Nov  416:04 test_2.c
  38. -rw-rw-rw-1 zxin10 dba  1624Nov  416:15 test_2.o
  39. -rw-------1 zxin10 dba    84Nov  416:04 test_3.c
  40. -rw-rw-rw-1 zxin10 dba  1624Nov  416:15 test_3.o
  41. ~/zhouzhaoxiong/zzx/mytest/a/more>./test
  42. thisisin test_1......
  43. thisisin test_2......
  44. thisisin test_3......
  45.  

我们可以看到,生成静态库文件的命令是“ar -r libtest.a test_1.o test_2.o test_3.o”,而将静态库文件编译进代码的命令是“gcc -o test main.c libtest.a”。

这样生成了静态库文件libtest.a之后,如果还有其他程序要调用test_1.c、test_2.c、test_3.c中实现的函数,只需要将test.h和libtest.a拷贝到对应的代码工程中,然后执行类似“gcc -o test main.c libtest.a”这样的命令即可。

 

三、动态库生成示例

 

1.单个文件生成动态库示例

我们编写如下简单的三个程序文件:so_test.h、test_a.c和test.c,在test.c中要调用test_a.c中实现的函数test_a。
so_test.h文件内容:

  1. #include<stdio.h>
  2. void test_a();

test_a.c文件内容:

  1. #include"so_test.h"
  2. void test_a()
  3. {
  4. printf("this is in test_a...\n");
  5. }

test.c文件内容:

  1. #include"so_test.h"
  2. int main()
  3. {
  4. test_a();
  5. return0;
  6. }

将此三个文件上传到Linux机器上,编译生成动态库文件,之后调用库文件的整个过程如下所示:

  1. ~/zhouzhaoxiong/zzx/mylib/so> ll
  2. -rw-------1 zxin10 dba  95Nov  417:37 so_test.h
  3. -rw-------1 zxin10 dba 109Nov  417:37test.c
  4. -rw-------1 zxin10 dba  84Nov  410:57 test_a.c
  5. ~/zhouzhaoxiong/zzx/mylib/sogcc test_a.c -fPIC -shared -o libtest.so
  6. ~/zhouzhaoxiong/zzx/mylib/so> ll
  7. -rwxrwxrwx 1 zxin10 dba 8181Nov  417:43 libtest.so
  8. -rw-------1 zxin10 dba   95Nov  417:37 so_test.h
  9. -rw-------1 zxin10 dba  109Nov  417:37test.c
  10. -rw-------1 zxin10 dba   84Nov  410:57 test_a.c
  11. ~/zhouzhaoxiong/zzx/mylib/sogcctest.c -L.-ltest -o test
  12. ~/zhouzhaoxiong/zzx/mylib/so> ll
  13. -rwxrwxrwx 1 zxin10 dba  8181Nov  417:43 libtest.so
  14. -rw-------1 zxin10 dba    95Nov  417:37 so_test.h
  15. -rwxrwxrwx 1 zxin10 dba 11805Nov  417:44test
  16. -rw-------1 zxin10 dba   109Nov  417:37test.c
  17. -rw-------1 zxin10 dba    84Nov  410:57 test_a.c
  18. ~/zhouzhaoxiong/zzx/mylib/so>./test
  19. thisisin test_a...

注意,“./test”命令执行成功的前提是在环境变量中添加了.so文件所在的路径,这个路径可以在“.bash_profile”文件的“LD_LIBRARY_PATH”变量的值中添加。

我们可以看到,生成动态库文件的命令是“gcc test_a.c -fPIC -shared -o libtest.so”,而将动态库文件编译进代码的命令是“gcc test.c -L. -ltest -o test”(-L.表示当前路径)。

这样生成了动态库文件libtest.so之后,如果还有其他程序要调用test_a.c中实现的函数,只需要将so_test.h和libtest.so拷贝到对应的代码工程中,然后执行类似“gcc test.c -L. -ltest -o test”这样的命令即可(前提是libtest.so所在的路径在环境变量中设置正确)。

 

2.多个文件生成动态库示例

我们编写如下简单的五个程序文件:so_test.h、test_a.c、test_b.c、test_c.c和test.c,在test.c中要调用test_a.c、test_b.c、test_c.c中实现的函数test_a、test_b、test_c。

so_test.h文件内容:

  1. #include<stdio.h>
  2. void test_a();
  3. void test_b();
  4. void test_c();

test_a.c文件内容:

  1. #include"so_test.h"
  2. void test_a()
  3. {
  4. printf("this is in test_a...\n");
  5. }

test_b.c文件内容:

  1. #include"so_test.h"
  2. void test_b()
  3. {
  4. printf("this is in test_b...\n");
  5. }

test_c.c文件内容:

  1. #include"so_test.h"
  2. void test_c()
  3. {
  4. printf("this is in test_c...\n");
  5. }

test.c文件内容:

  1. #include"so_test.h"
  2. int main()
  3. {
  4. test_a();
  5. test_b();
  6. test_c();
  7. return0;
  8. }

将此五个文件上传到Linux机器上,编译生成动态库文件,之后调用库文件的整个过程如下所示:

  1. ~/zhouzhaoxiong/zzx/mylib/test_so> ll
  2. -rwxrwxrwx 1 zxin10 dba 8309Nov  509:12 libtest
  3. -rw-------1 zxin10 dba   70Nov  513:44 so_test.h
  4. -rw-------1 zxin10 dba  105Nov  415:25test.c
  5. -rw-------1 zxin10 dba   84Nov  415:25 test_a.c
  6. -rw-------1 zxin10 dba   84Nov  415:25 test_b.c
  7. -rw-------1 zxin10 dba   84Nov  415:25 test_c.c
  8. ~/zhouzhaoxiong/zzx/mylib/test_sogcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so
  9. ~/zhouzhaoxiong/zzx/mylib/test_sogcctest.c -L.-ltest -o test
  10. ~/zhouzhaoxiong/zzx/mylib/test_so> ll
  11. -rwxrwxrwx 1 zxin10 dba  8309Nov  513:46 libtest.so
  12. -rw-------1 zxin10 dba    70Nov  513:44 so_test.h
  13. -rwxrwxrwx 1 zxin10 dba 11883Nov  513:46test
  14. -rw-------1 zxin10 dba   105Nov  415:25test.c
  15. -rw-------1 zxin10 dba    84Nov  415:25 test_a.c
  16. -rw-------1 zxin10 dba    84Nov  415:25 test_b.c
  17. -rw-------1 zxin10 dba    84Nov  415:25 test_c.c
  18. ~/zhouzhaoxiong/zzx/mylib/test_so>./test
  19. thisisin test_a...
  20. thisisin test_b...
  21. thisisin test_c...

注意,“./test”命令执行成功的前提仍然是在环境变量中添加了.so文件所在的路径,这个路径可以在“.bash_profile”文件的“LD_LIBRARY_PATH”变量的值中添加。

我们可以看到,多个文件生成动态库文件的命令是“gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so”,而将动态库文件编译进代码的命令是“gcc test.c -L. -ltest -o test”(-L.表示当前路径)。

这样生成了动态库文件libtest.so之后,如果还有其他程序要调用test_a.c、test_b.c、test_c.c中实现的函数,只需要将so_test.h和libtest.so拷贝到对应的代码工程中,然后执行类似“gcc test.c -L. -ltest -o test”这样的命令即可(前提是libtest.so所在的路径在环境变量中设置正确)。

 

四、总结

有关生成静态库和动态库的命令,说明如下:

第一,在本文中,我们使用的生成静态库的命令形如“ar -r test.a test.o”,其中,-r是replace的意思,表示如果当前插入的模块名已经在库中存在,则替换同名的模块。我们也可以用形如“ar -cr test.a test.o”的命令来生成静态库,其中-c是create的意思,表示生成。

第二,在本文中,我们使用的生成动态库文件的命令形如“gcc test_a.c -fPIC -shared -o libtest.so”,其中,fPIC表示编译为位置独立的代码,shared表示生成的库为共享库。将动态库文件编译进代码的命令是“gcc test.c -L. -ltest -o test”,-L指定库查找的位置(注意L后面还有’.’),表示在当前目录下查找(如果在当前目录下的lib目录下查找,可以写成-L./lib);-l则指定函数库名,其中的lib和.so省略(如这里的libtest.so就简写为test)。

第三,使用ldd命令可以查看一个可执行程序依赖的共享库,该命令的使用示例如下所示:

  1. ~/zhouzhaoxiong/zzx/mylib/test_so>lddtest
  2.         linux-vdso.so.1=>  (0x00007fff1db6e000)
  3.         libtest.so =>/home/zhou/lib/libtest.so (0x00007fdbfff21000)
  4.         libc.so.6=>/lib64/libc.so.6(0x00007fdbffb95000)
  5.         /lib64/ld-linux-x86-64.so.2(0x00007fdc00124000)

可以看到,可执行文件test依赖于四个共享库,其中libtest.so位于当前用户的lib目录下。

本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-11/124864.htm

赞(0) 打赏
转载请注明出处:服务器评测 » Linux 中的静态库和动态库简介及生成过程示例
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏