Linux环境下静态库和动态库制作和使用

Linux环境下静态库和动态库的制作和使用

0.前期准备

假设在test文件夹下存在tmath文件夹和test.c文件;
在tmath文件夹里面包含三个文件:tmath.h ,add.c,mul.c

tmath.h代码如下:

#ifndef T_MATH_H_
#define T_MATH_H_
/*函数的声明*/
int t_add(int,int);
int t_sub(int,int);
int t_mul(int,int);
int t_div(int,int);

/*宏定义*/
/*文件的包含*/
/*类型的定义*/
/*变量的声明*/
#endif

add.c代码如下:

#include "tmath.h"
/*包含头文件使用""和<>的区别*/
int t_add(int x,int y){
    return x + y;
}

int t_sub(int x, int y){
    return x - y;
}

mul.c代码如下:

#include "tmath.h"
int t_mul(int x,int y){
    return x * y;
}

int t_div(int x,int y){
    return x / y;
}

test.c代码如下:

#include <stdio.h>
#include "tmath/tmath.h"
typedef  int(*f_t)(int,int);

int process(f_t f,int x,int y){
    return f(x,y);
}
int main(void){
    int a=6,b=2;
    int (*func)(int,int);
    f_t fun_c[4]={t_add,t_sub,t_mul,t_div};

/*
    printf("a+b=%d\n",t_add(a,b));
    printf("a-b=%d\n",t_sub(a,b));
    printf("a*b=%d\n",t_mul(a,b));
    printf("a/b=%d\n",t_div(a,b));
*/  
    func=t_add;
    printf("a+b=%d\n",func(a,b));
    func=t_sub;
    printf("a-b=%d\n",func(a,b));
    printf("a*b=%d\n",process(t_mul,a,b));
    for(int i=0;i<4;i++){
        printf("%d\n",fun_c[i](a,b));
    }
    return 0;
}

1.静态库的制作和使用

静态库文件的命名规范为: lib+库名.a
如何制作和使用静态库文件?(举例说明,使用tmath文件夹)

1.1、将需要加到静态库里的源文件编译为目标文件

tmath$gcc -c *.c
tmath$ls
add.c add.o mul.c mul.o tmath.h

1.2、将目标文件添加到静态库里。

tmath$ar -r libtmath.a *.o
ar: creating libtmath.a
tmath$ls
add.c add.o libtmath.a mul.c mul.o tmath.h

1.3.使用静态库文件链接目标文件形成可执行文件

test$gcc test.c -Ltmath -ltmath -std=c99

-L路径 路径可以是绝对路径也可以是相对路径,指定链接器的搜索路径
-l库名 静态库或动态库的库名。

1.4.运行结果

步骤3执行结果将在文件夹test内产生执行文件a.out,
test$./a.out
执行结果如下:
a+b=8
a-b=4
a*b=12
8
4
12
3

注意:由于在for循环中定义了i,需要添加-std=c99,-std=gnu99,-std=c11 或者-std=gnu11其中之一。另外要注意test.c 文件中的#include “tmath/tmath.h” 包含语句的书写,采用相对路径表示。

2.动态库的制作和使用

动态库的命名 lib+库名.so

2.1、将需要添加到动态库里的源文件编译为与位置无关的目标文件

tmath$gcc -c -fPIC *.c
tmath$ls
add.c add.o libtmath.a mul.c mul.o tmath.h

2.2、将目标文件添加到动态库中

tmath$gcc -shared -o libtmath.so *.o
tmath$ls
add.c add.o libtmath.a libtmath.so mul.c mul.o tmath.h

2.3、使用动态库链接目标文件,生成可执行文件

tmath$ cd ..

test$gcc test.c -Ltmath -ltmath -o tt
test.c: 在函数‘main’中:
test.c:24: 错误: 只允许在 C99 模式下使用‘for’循环初始化声明
test.c:24: 附注: 使用 -std=c99 或 -std=gnu99 来编译您的代码
test$gcc test.c -Ltmath -ltmath -o tt -std=c99

test$ls
a.out tt test.c tmath/

test$./tt
./tt: error while loading shared libraries: libtmath.so: cannot open shared object file: No such file or directory
出错的原因是加载器在指定的路径下找不到tt程序依赖的动态库文件。
可以使用ldd命令察看可执行文件依赖的动态库文件如下:

test$ldd tt
linux-vdso.so.1 => (0x00007fff999fe000)
libtmath.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa6da22a000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa6da5fe000)
上面结果显示找不到libtmath.so动态库文件。

test$nm tt
截取部分结果如下:
0000000000400620 T _init
00000000004006a0 T _start
00000000004007dc T main
U printf@@GLIBC_2.2.5
00000000004007b8 T process
0000000000400730 t register_tm_clones
U t_add
U t_div
U t_mul
U t_sub
注意:其中T表示在执行文件tt中有具体的实现代码,而U表示不存在具体的实现代码,依赖于动态库文件libtmath.so。也就是说t_add,t_div,t_mul,t_sub依赖动态库文件。题外话,_start是程序的入口函数,它会调用封装main函数,而main函数只是C语言程序入口函数,此话不作强制理解,了解即可。

2.3 举两例具体解决方案+附带送一例
2.3.1 使用环境变量LD_LIBRARY_PATH

在test文件夹下指定加载器的寻找路径如下所示:
test$export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./tmath/

执行结果如下:
test$./tt
a+b=8
a-b=4
a*b=12
8
4
12
3
到此第一种方案已经解决成功了。

2.3.2 将test.c中的#include “tmath/tmath.h”改成 #include “tmath.h”

重新编译链接动态库文件:
gcc test.c -Ltmath -ltmath -I tmath -v -std=c99 -o tt2
截取部分结果可以看到tmath文件家在#include<…>搜索路径下了:
#include “…” search starts here:
#include <…> search starts here:
tmath
/usr/lib/gcc/x86_64-linux-gnu/4.9/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/4.9/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.

执行结果./tt2成果上面法1一样。

2.3.3 直接换成系统指定命令<>

将上述前期准备中的add.c,mul.c, test.c中的包含tmath.h的头文件包含指令为

#include <tmath.h>

将tmath文件夹下的tmath.h文件移动到系统指定目录下如/usr/include目录中,命令如下:
tmath$sudo mv tmath.h /usr/include
其余的步骤全部按照最先生成动态库和可执行文件的步骤一样。
结果也是OK的。

3.写静态库和动态库的初衷

自从拜读了大牛王老师的课程,很深受王老的启发,所以想着把学习心得记录下来,一方面作为对学习之后的总结和整理,另一方面或许也能帮助和自己曾经一样迷惑的Linux学习者。其实很早就想写下来这篇学习笔记,由于各种原因推迟到了今天,总算还是写了。言归正传,学习完静态库和动态库能使我更好的理解如何使用静态库和动态库,并且能够明白它们之间底层实现的不同。也能让我们更好的明白静态链接和动态链接之间的区别,比如动态库文件生成的可执行文件依赖于动态库,而静态库文件生成的可执行文件不依赖于静态库,可直接交付客户使用,因此动态库生成的可执行文件比静态库文件生成的可执行文件小很多。以前不能够理解的有了深入理解,比如病毒库的更新,其实该病毒库就是一种动态库,它的更新不会影响依赖于动态库的执行程序,即该执行程序不用做任何的修改。
补充:
(1)如果指定路径目录下同时存在静态库文件libtmath.a 和动态库文件libtmath.so时候,链接采用的是静态链接还是动态链接?在链接的时候加上参数-static表示静态链接。默认采用的是动态链接。
(2)改变动态库里函数的内容,但是不改变test.c里面的main函数里的内容,可以更好的实现框架。

由于本人水平有限,难免有所遗漏之处。如果你碰到问题的不能解决,欢迎留言与我讨论~

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值