UDN-企业互联网技术人气社区

板块导航

浏览  : 1141
回复  : 0

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

[复制链接]
哥屋恩的头像 楼主
发表于 2016-10-15 17:57:37 | 显示全部楼层 |阅读模式
  在实际的软件开发项目中,不是每一行代码都需要我们亲自写。在我们的软件产品中,有一些代码(尤其是函数)的出现频率很高,它们可以被当作公共代码来反复使用。为了避免重复劳动,我们就把这些公共代码编译为库文件,供需要的程序调用。在Linux中,库分为静态库和动态库两种。

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

084332sz9yrmcgheh03ju5.jpg


  一、静态库和动态库简介

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

  库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。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

  2.   void test();
复制代码


  test.c文件内容:

  1.   #include "test.h"

  2.   void test()

  3.   {

  4.   printf("this is in test....../n");

  5.   }
复制代码


  main.c文件内容:

  1.   #include "test.h"

  2.   int main()

  3.   {

  4.   test();

  5.   return 0;

  6.   }
复制代码


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

  1.   ~/zhouzhaoxiong/zzx/mytest/a/single> ll

  2.   -rw------- 1 zhou dba 53 Nov 4 16:04 main.c

  3.   -rw------- 1 zhou dba 80 Nov 4 16:04 test.c

  4.   -rw------- 1 zhou dba 36 Nov 4 16:04 test.h

  5.   ~/zhouzhaoxiong/zzx/mytest/a/single> gcc -c test.c

  6.   ~/zhouzhaoxiong/zzx/mytest/a/single> ll

  7.   -rw------- 1 zhou dba 53 Nov 4 16:04 main.c

  8.   -rw------- 1 zhou dba 80 Nov 4 16:04 test.c

  9.   -rw------- 1 zhou dba 36 Nov 4 16:04 test.h

  10.   -rw-rw-rw- 1 zhou dba 1624 Nov 4 16:06 test.o

  11.   ~/zhouzhaoxiong/zzx/mytest/a/single> ar -r libtest.a test.o

  12.   ar: creating libtest.a

  13.   ~/zhouzhaoxiong/zzx/mytest/a/single> ll

  14.   -rw------- 1 zhou dba 53 Nov 4 16:04 main.c

  15.   -rw-rw-rw- 1 zhou dba 1766 Nov 4 16:06 libtest.a

  16.   -rw------- 1 zhou dba 80 Nov 4 16:04 test.c

  17.   -rw------- 1 zhou dba 36 Nov 4 16:04 test.h

  18.   -rw-rw-rw- 1 zhou dba 1624 Nov 4 16:06 test.o

  19.   ~/zhouzhaoxiong/zzx/mytest/a/single> gcc -o test main.c libtest.a

  20.   ~/zhouzhaoxiong/zzx/mytest/a/single> ll

  21.   -rw------- 1 zhou dba 52 Nov 4 16:09 main.c

  22.   -rwxrwxrwx 1 zhou dba 11876 Nov 4 16:09 test

  23.   -rw-rw-rw- 1 zhou dba 1766 Nov 4 16:06 libtest.a

  24.   -rw------- 1 zhou dba 80 Nov 4 16:04 test.c

  25.   -rw------- 1 zhou dba 36 Nov 4 16:04 test.h

  26.   -rw-rw-rw- 1 zhou dba 1624 Nov 4 16:06 test.o

  27.   ~/zhouzhaoxiong/zzx/mytest/a/single> ./test

  28.   this is in test......
复制代码


  我们可以看到,生成库文件的命令是“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

  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.   return 0;

  8.   }
复制代码


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

  1.   ~/zhouzhaoxiong/zzx/mytest/a/more> ll

  2.   -rw------- 1 zxin10 dba 96 Nov 4 16:11 main.c

  3.   -rw------- 1 zxin10 dba 70 Nov 4 16:04 test.h

  4.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_1.c

  5.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_2.c

  6.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_3.c

  7.   ~/zhouzhaoxiong/zzx/mytest/a/more> gcc -c test_1.c test_2.c test_3.c

  8.   ~/zhouzhaoxiong/zzx/mytest/a/more> ll

  9.   -rw------- 1 zxin10 dba 96 Nov 4 16:11 main.c

  10.   -rw------- 1 zxin10 dba 70 Nov 4 16:04 test.h

  11.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_1.c

  12.   -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_1.o

  13.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_2.c

  14.   -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_2.o

  15.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_3.c

  16.   -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_3.o

  17.   ~/zhouzhaoxiong/zzx/mytest/a/more> ar -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 96 Nov 4 16:11 main.c

  21.   -rw-rw-rw- 1 zxin10 dba 5158 Nov 4 16:15 libtest.a

  22.   -rw------- 1 zxin10 dba 70 Nov 4 16:04 test.h

  23.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_1.c

  24.   -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_1.o

  25.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_2.c

  26.   -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_2.o

  27.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_3.c

  28.   -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_3.o

  29.   ~/zhouzhaoxiong/zzx/mytest/a/more> gcc -o test main.c libtest.a

  30.   ~/zhouzhaoxiong/zzx/mytest/a/more> ll

  31.   -rw------- 1 zxin10 dba 96 Nov 4 16:11 main.c

  32.   -rwxrwxrwx 1 zxin10 dba 12008 Nov 4 16:16 test

  33.   -rw-rw-rw- 1 zxin10 dba 5158 Nov 4 16:15 libtest.a

  34.   -rw------- 1 zxin10 dba 70 Nov 4 16:04 test.h

  35.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_1.c

  36.   -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_1.o

  37.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_2.c

  38.   -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_2.o

  39.   -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_3.c

  40.   -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_3.o

  41.   ~/zhouzhaoxiong/zzx/mytest/a/more> ./test

  42.   this is in test_1......

  43.   this is in test_2......

  44.   this is in test_3......
复制代码


  我们可以看到,生成静态库文件的命令是“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

  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.   return 0;

  6.   }
复制代码


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

  1.   ~/zhouzhaoxiong/zzx/mylib/so> ll

  2.   -rw------- 1 zxin10 dba 95 Nov 4 17:37 so_test.h

  3.   -rw------- 1 zxin10 dba 109 Nov 4 17:37 test.c

  4.   -rw------- 1 zxin10 dba 84 Nov 4 10:57 test_a.c

  5.   ~/zhouzhaoxiong/zzx/mylib/so> gcc test_a.c -fPIC -shared -o libtest.so

  6.   ~/zhouzhaoxiong/zzx/mylib/so> ll

  7.   -rwxrwxrwx 1 zxin10 dba 8181 Nov 4 17:43 libtest.so

  8.   -rw------- 1 zxin10 dba 95 Nov 4 17:37 so_test.h

  9.   -rw------- 1 zxin10 dba 109 Nov 4 17:37 test.c

  10.   -rw------- 1 zxin10 dba 84 Nov 4 10:57 test_a.c

  11.   ~/zhouzhaoxiong/zzx/mylib/so> gcc test.c -L. -ltest -o test

  12.   ~/zhouzhaoxiong/zzx/mylib/so> ll

  13.   -rwxrwxrwx 1 zxin10 dba 8181 Nov 4 17:43 libtest.so

  14.   -rw------- 1 zxin10 dba 95 Nov 4 17:37 so_test.h

  15.   -rwxrwxrwx 1 zxin10 dba 11805 Nov 4 17:44 test

  16.   -rw------- 1 zxin10 dba 109 Nov 4 17:37 test.c

  17.   -rw------- 1 zxin10 dba 84 Nov 4 10:57 test_a.c

  18.   ~/zhouzhaoxiong/zzx/mylib/so> ./test

  19.   this is in 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

  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.   }

  6.   test_b.c文件内容:

  7.   #include "so_test.h"

  8.   void test_b()

  9.   {

  10.   printf("this is in test_b.../n");

  11.   }
复制代码


  test_c.c文件内容:

  1.   #include "so_test.h"

  2.   void test_c()

  3.   {

  4.   printf("this is in test_c.../n");

  5.   }

  6.   test.c文件内容:

  7.   #include "so_test.h"

  8.   int main()

  9.   {

  10.   test_a();

  11.   test_b();

  12.   test_c();

  13.   return 0;

  14.   }
复制代码


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

  1.   ~/zhouzhaoxiong/zzx/mylib/test_so> ll

  2.   -rwxrwxrwx 1 zxin10 dba 8309 Nov 5 09:12 libtest

  3.   -rw------- 1 zxin10 dba 70 Nov 5 13:44 so_test.h

  4.   -rw------- 1 zxin10 dba 105 Nov 4 15:25 test.c

  5.   -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_a.c

  6.   -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_b.c

  7.   -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_c.c

  8.   ~/zhouzhaoxiong/zzx/mylib/test_so> gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so

  9.   ~/zhouzhaoxiong/zzx/mylib/test_so> gcc test.c -L. -ltest -o test

  10.   ~/zhouzhaoxiong/zzx/mylib/test_so> ll

  11.   -rwxrwxrwx 1 zxin10 dba 8309 Nov 5 13:46 libtest.so

  12.   -rw------- 1 zxin10 dba 70 Nov 5 13:44 so_test.h

  13.   -rwxrwxrwx 1 zxin10 dba 11883 Nov 5 13:46 test

  14.   -rw------- 1 zxin10 dba 105 Nov 4 15:25 test.c

  15.   -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_a.c

  16.   -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_b.c

  17.   -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_c.c

  18.   ~/zhouzhaoxiong/zzx/mylib/test_so> ./test

  19.   this is in test_a...

  20.   this is in test_b...

  21.   this is in 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> ldd test

  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目录下。

  参考资料:

  1. http://blog.chinaunix.net/uid-26833883-id-3219335.html

  2. http://blog.csdn.net/bat603/article/details/1438408

  3. http://blog.sina.com.cn/s/blog_795ed1810101789t.html

原文作者:佚名  来源:开发者头条

相关帖子

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部