关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » HTML5 »Linux 中的静态库和动态库简介及生成过程示例

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

    2015-11-07 00:00:00 出处:w3ctech
    分享

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

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

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

    一、静态库和动态库简介

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

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

    #include <stdio.h>
    
    void test();

    test.c文件内容:

    #include "test.h"
    
    void test()
    {
        printf("this is in test....../n");
    }

    main.c文件内容:

    #include "test.h"
    
    int main()
    {
        test();
        return 0;
    }

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

    ~/zhouzhaoxiong/zzx/mytest/a/single> ll
    -rw------- 1 zhou dba 53 Nov  4 16:04 main.c
    -rw------- 1 zhou dba 80 Nov  4 16:04 test.c
    -rw------- 1 zhou dba 36 Nov  4 16:04 test.h
    ~/zhouzhaoxiong/zzx/mytest/a/single> gcc -c test.c
    ~/zhouzhaoxiong/zzx/mytest/a/single> ll
    -rw------- 1 zhou dba   53 Nov  4 16:04 main.c
    -rw------- 1 zhou dba   80 Nov  4 16:04 test.c
    -rw------- 1 zhou dba   36 Nov  4 16:04 test.h
    -rw-rw-rw- 1 zhou dba 1624 Nov  4 16:06 test.o
    ~/zhouzhaoxiong/zzx/mytest/a/single> ar -r libtest.a test.o
    ar: creating libtest.a
    ~/zhouzhaoxiong/zzx/mytest/a/single> ll
    -rw------- 1 zhou dba   53 Nov  4 16:04 main.c
    -rw-rw-rw- 1 zhou dba 1766 Nov  4 16:06 libtest.a
    -rw------- 1 zhou dba   80 Nov  4 16:04 test.c
    -rw------- 1 zhou dba   36 Nov  4 16:04 test.h
    -rw-rw-rw- 1 zhou dba 1624 Nov  4 16:06 test.o
    ~/zhouzhaoxiong/zzx/mytest/a/single> gcc -o test main.c libtest.a
    ~/zhouzhaoxiong/zzx/mytest/a/single> ll
    -rw------- 1 zhou dba    52 Nov  4 16:09 main.c
    -rwxrwxrwx 1 zhou dba 11876 Nov  4 16:09 test
    -rw-rw-rw- 1 zhou dba  1766 Nov  4 16:06 libtest.a
    -rw------- 1 zhou dba    80 Nov  4 16:04 test.c
    -rw------- 1 zhou dba    36 Nov  4 16:04 test.h
    -rw-rw-rw- 1 zhou dba  1624 Nov  4 16:06 test.o
    ~/zhouzhaoxiong/zzx/mytest/a/single> ./test
    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文件内容:

    #include <stdio.h>
    
    void test_1();
    void test_2();
    void test_3();

    test_1.c文件内容:

    #include "test.h"
    
    void test_1()
    {
        printf("this is in test_1....../n");
    }

    test_2.c文件内容:

    #include "test.h"
    
    void test_2()
    {
        printf("this is in test_2....../n");
    }

    test_3.c文件内容:

    #include "test.h"
    
    void test_3()
    {
        printf("this is in test_3....../n");
    }

    main.c文件内容:

    #include "test.h"
    
    int main()
    {
        test_1();
        test_2();
        test_3();
        return 0;
    }

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

    ~/zhouzhaoxiong/zzx/mytest/a/more> ll
    -rw------- 1 zxin10 dba 96 Nov  4 16:11 main.c
    -rw------- 1 zxin10 dba 70 Nov  4 16:04 test.h
    -rw------- 1 zxin10 dba 84 Nov  4 16:04 test_1.c
    -rw------- 1 zxin10 dba 84 Nov  4 16:04 test_2.c
    -rw------- 1 zxin10 dba 84 Nov  4 16:04 test_3.c
    ~/zhouzhaoxiong/zzx/mytest/a/more> gcc -c test_1.c test_2.c test_3.c
    ~/zhouzhaoxiong/zzx/mytest/a/more> ll
    -rw------- 1 zxin10 dba   96 Nov  4 16:11 main.c
    -rw------- 1 zxin10 dba   70 Nov  4 16:04 test.h
    -rw------- 1 zxin10 dba   84 Nov  4 16:04 test_1.c
    -rw-rw-rw- 1 zxin10 dba 1624 Nov  4 16:15 test_1.o
    -rw------- 1 zxin10 dba   84 Nov  4 16:04 test_2.c
    -rw-rw-rw- 1 zxin10 dba 1624 Nov  4 16:15 test_2.o
    -rw------- 1 zxin10 dba   84 Nov  4 16:04 test_3.c
    -rw-rw-rw- 1 zxin10 dba 1624 Nov  4 16:15 test_3.o
    ~/zhouzhaoxiong/zzx/mytest/a/more> ar -r libtest.a test_1.o test_2.o test_3.o
    ar: creating libtest.a
    ~/zhouzhaoxiong/zzx/mytest/a/more> ll
    -rw------- 1 zxin10 dba   96 Nov  4 16:11 main.c
    -rw-rw-rw- 1 zxin10 dba 5158 Nov  4 16:15 libtest.a
    -rw------- 1 zxin10 dba   70 Nov  4 16:04 test.h
    -rw------- 1 zxin10 dba   84 Nov  4 16:04 test_1.c
    -rw-rw-rw- 1 zxin10 dba 1624 Nov  4 16:15 test_1.o
    -rw------- 1 zxin10 dba   84 Nov  4 16:04 test_2.c
    -rw-rw-rw- 1 zxin10 dba 1624 Nov  4 16:15 test_2.o
    -rw------- 1 zxin10 dba   84 Nov  4 16:04 test_3.c
    -rw-rw-rw- 1 zxin10 dba 1624 Nov  4 16:15 test_3.o
    ~/zhouzhaoxiong/zzx/mytest/a/more> gcc -o test main.c libtest.a
    ~/zhouzhaoxiong/zzx/mytest/a/more> ll
    -rw------- 1 zxin10 dba    96 Nov  4 16:11 main.c
    -rwxrwxrwx 1 zxin10 dba 12008 Nov  4 16:16 test
    -rw-rw-rw- 1 zxin10 dba  5158 Nov  4 16:15 libtest.a
    -rw------- 1 zxin10 dba    70 Nov  4 16:04 test.h
    -rw------- 1 zxin10 dba    84 Nov  4 16:04 test_1.c
    -rw-rw-rw- 1 zxin10 dba  1624 Nov  4 16:15 test_1.o
    -rw------- 1 zxin10 dba    84 Nov  4 16:04 test_2.c
    -rw-rw-rw- 1 zxin10 dba  1624 Nov  4 16:15 test_2.o
    -rw------- 1 zxin10 dba    84 Nov  4 16:04 test_3.c
    -rw-rw-rw- 1 zxin10 dba  1624 Nov  4 16:15 test_3.o
    ~/zhouzhaoxiong/zzx/mytest/a/more> ./test
    this is in test_1......
    this is in test_2......
    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文件内容:

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

    test_a.c文件内容:

    #include "so_test.h"
    
    void test_a()
    {
        printf("this is in test_a.../n");
    }

    test.c文件内容:

    #include "so_test.h"
    
    int main()
    {
        test_a();
    
        return 0;
    }

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

    ~/zhouzhaoxiong/zzx/mylib/so> ll
    -rw------- 1 zxin10 dba  95 Nov  4 17:37 so_test.h
    -rw------- 1 zxin10 dba 109 Nov  4 17:37 test.c
    -rw------- 1 zxin10 dba  84 Nov  4 10:57 test_a.c
    ~/zhouzhaoxiong/zzx/mylib/so> gcc test_a.c -fPIC -shared -o libtest.so
    ~/zhouzhaoxiong/zzx/mylib/so> ll
    -rwxrwxrwx 1 zxin10 dba 8181 Nov  4 17:43 libtest.so
    -rw------- 1 zxin10 dba   95 Nov  4 17:37 so_test.h
    -rw------- 1 zxin10 dba  109 Nov  4 17:37 test.c
    -rw------- 1 zxin10 dba   84 Nov  4 10:57 test_a.c
    ~/zhouzhaoxiong/zzx/mylib/so> gcc test.c -L. -ltest -o test
    ~/zhouzhaoxiong/zzx/mylib/so> ll
    -rwxrwxrwx 1 zxin10 dba  8181 Nov  4 17:43 libtest.so
    -rw------- 1 zxin10 dba    95 Nov  4 17:37 so_test.h
    -rwxrwxrwx 1 zxin10 dba 11805 Nov  4 17:44 test
    -rw------- 1 zxin10 dba   109 Nov  4 17:37 test.c
    -rw------- 1 zxin10 dba    84 Nov  4 10:57 test_a.c
    ~/zhouzhaoxiong/zzx/mylib/so> ./test
    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文件内容:

    #include <stdio.h>
    
    void test_a();
    void test_b();
    void test_c();

    test_a.c文件内容:

    #include "so_test.h"
    
    void test_a()
    {
        printf("this is in test_a.../n");
    }

    test_b.c文件内容:

    #include "so_test.h"
    
    void test_b()
    {
        printf("this is in test_b.../n");
    }

    test_c.c文件内容:

    #include "so_test.h"
    
    void test_c()
    {
        printf("this is in test_c.../n");
    }

    test.c文件内容:

    #include "so_test.h"
    
    int main()
    {
        test_a();
        test_b();
        test_c();
    
        return 0;
    }

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

    ~/zhouzhaoxiong/zzx/mylib/test_so> ll
    -rwxrwxrwx 1 zxin10 dba 8309 Nov  5 09:12 libtest
    -rw------- 1 zxin10 dba   70 Nov  5 13:44 so_test.h
    -rw------- 1 zxin10 dba  105 Nov  4 15:25 test.c
    -rw------- 1 zxin10 dba   84 Nov  4 15:25 test_a.c
    -rw------- 1 zxin10 dba   84 Nov  4 15:25 test_b.c
    -rw------- 1 zxin10 dba   84 Nov  4 15:25 test_c.c
    ~/zhouzhaoxiong/zzx/mylib/test_so> gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so
    ~/zhouzhaoxiong/zzx/mylib/test_so> gcc test.c -L. -ltest -o test
    ~/zhouzhaoxiong/zzx/mylib/test_so> ll
    -rwxrwxrwx 1 zxin10 dba  8309 Nov  5 13:46 libtest.so
    -rw------- 1 zxin10 dba    70 Nov  5 13:44 so_test.h
    -rwxrwxrwx 1 zxin10 dba 11883 Nov  5 13:46 test
    -rw------- 1 zxin10 dba   105 Nov  4 15:25 test.c
    -rw------- 1 zxin10 dba    84 Nov  4 15:25 test_a.c
    -rw------- 1 zxin10 dba    84 Nov  4 15:25 test_b.c
    -rw------- 1 zxin10 dba    84 Nov  4 15:25 test_c.c
    ~/zhouzhaoxiong/zzx/mylib/test_so> ./test
    this is in test_a...
    this is in test_b...
    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命令可以查看一个可执行程序依赖的共享库,该命令的使用示例如下所示:

    ~/zhouzhaoxiong/zzx/mylib/test_so> ldd test
            linux-vdso.so.1 =>  (0x00007fff1db6e000)
            libtest.so => /home/zhou/lib/libtest.so (0x00007fdbfff21000)
            libc.so.6 => /lib64/libc.so.6 (0x00007fdbffb95000)
            /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

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    Cornell大神Kleinberg的经典教材《算法设计》是最好入门的算法教材

    从 Microsoft 下载中心安装 Windows 7 SP1 和 Windows Server 2008 R2 SP1 之前要执行的步骤

    Llama 2基于UCloud UK8S的创新应用

    火山引擎DataTester:如何使用A/B测试优化全域营销效果

    腾讯云、移动云继阿里云降价后宣布大幅度降价

    字节跳动数据平台论文被ICDE2023国际顶会收录,将通过火山引擎开放相关成果

    这个话题被围观超10000次,火山引擎VeDI如此解答

    误删库怎么办?火山引擎DataLeap“3招”守护数据安全

    IT头条

    平替CUDA!摩尔线程发布MUSA 4性能分析工具

    00:43

    三起案件揭开侵犯个人信息犯罪的黑灰产业链

    13:59

    百度三年开放2.1万实习岗,全力培育AI领域未来领袖

    00:36

    工信部:一季度,电信业务总量同比增长7.7%,业务收入累计完成4469亿元

    23:42

    Gartner:2024年全球半导体营收6559亿美元,AI助力英伟达首登榜首

    18:04

    技术热点

    iOS 8 中如何集成 Touch ID 功能

    windows7系统中鼠标滑轮键(中键)的快捷应用

    MySQL数据库的23个特别注意的安全事项

    Kruskal 最小生成树算法

    Ubuntu 14.10上安装新的字体图文教程

    Ubuntu14更新后无法进入系统卡在光标界面解怎么办?

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。