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文件内容:

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

时间: 2024-11-08 18:12:23

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

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

在实际的软件开发项目中,不是每一行代码都需要我们亲自写.在我们的软件产品中,有一些代码(尤其是函数)的出现频率很高,它们可以被当作公共代码来反复使用.为了避免重复劳动,我们就把这些公共代码编译为库文件,供需要的程序调用.在Linux中,库分为静态库和动态库两种. 本文对静态库和动态库进行了详细的介绍,并用实际的C代码演示了这两种库的生成过程. 一.静态库和动态库简介 众所周知,程序一般需要经过预处理.编译.汇编和链接这几个步骤才能变成可执行的程序.在实际的软件开发中,对于一些需要被许多模块反复使

关于Linux静态库和动态库的分析

原文:http://linux.chinaunix.net/techdoc/net/2009/02/04/1060670.shtml 1.什么是库 在windows平台和linux平台下都大量存在着库.本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的本质不同,因此二者库的二进制是不兼容的. 本文仅限于介绍linux下的库.2.库的种类linux下的库有两种:静态库和共享库(动态库). 二者的不同点在于代码被载入的时刻不同.静态库的代码在编译

Linux静态库和动态库的编写和使用

Linux静态库和动态库的编写和使用 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种.   1  静态库和动态库的区别 1.1. 静态函数库    (1)静态函数库的名字一般是lib[name].a (2)利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,它的优点是编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了.这给它带来的缺点为如果静态函数库改变了,那么你的程序必须重新编译. 1.2. 动态

自己在linux上编译、链接、动态库和静态库的学习笔记

在平常的项目中,我们都是使用公司要求的makefile.makedebug一类的文件,因此,在编译.链接.生成和链接动态库与静态库的时候,我们只是简单的使用一些已经设置的变量,只是简单的修改.添加一些文件名,或许这次我们编译通过了,但是,在某一个时候,可能出现了一个问题,无论简单与否,因为平常没有留意,导致的结果可能是花了好长时间才能解决.而如果平常只是简单的留一下心,或许这些问题都是可以避免的. 因此,今天我自己使用几个文件,编译动态库.静态库以及动态库和静态库的嵌套调用等问题,尽量还原我在项

Linux静态库和动态库的分析及实现

1.什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的本质不同,因此二者库的二进制是不兼容的. 本文仅限于介绍linux下的库. 2.库的种类 linux下的库有两种:静态库和共享库(动态库). 二者的不同点在于代码被载入的时刻不同. 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大. 共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体

深入探讨Linux静态库与动态库的详解(一看就懂)_C 语言

库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. 一.静态库和动态库的区别1. 静态函数库这类库的名字一般是libxxx.a:利用静态函数库编译成的文件比较大--空间,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了.当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译.2. 动态函数库这类库的名字一般是libxxx.so;相对于静态

Linux下如何用GCC编译动态库

  本文主要解决以下几个问题 1 为什么要使用库? 2 库的分类 3 创建自己的库 或许大家对自己初学 Linux时的情形仍记忆尤新吧.如果没有一个能较好的解决依赖关系的包管理器,在Linux下安装软件将是一件及其痛苦的工作.你装a包时,可能会提示你要先装b包,当你费尽心力找到b包时,可能又会提示你要先安装c包.我就曾被这样的事搞的焦头烂额,至今一提起rpm仍心有余悸,头皮发麻.说是一朝被蛇咬,十年怕井绳怕也不为过. Linux下之所以有这许多的依赖关系,其中一个开发原则真是功不可没.这个原则就

C++静态库与动态库

C++静态库与动态库 这次分享的宗旨是--让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择.这里不深入介绍静态库.动态库的底层格式,内存布局等,有兴趣的同学,推荐一本书<程序员的自我修养--链接.装载与库>. 什么是库 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.库有两种:静态库(.a..lib

静态库和动态库的区别以及使用

问题描述 静态库和动态库的区别以及使用 什么是动态链接库和静态链接库?它们有什么区别?它们分别如何使用? 解决方案 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种.? 静态库和动态库的区别 静态函数库 ??? 这类库的名字一般是libxxx.a:利用静态函数库编译成的文件比较大,因为整个 函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了.当然这也会成为他的....