linux生成静态库与动态库

静态库与动态库的分析

1、什么是库?

库(library)是一种可执行代码的二进制形式,通常把一些常用的函数制作成各种函数库,然后被系统载入内存中运行。库内一般都是各种标准程序、子程序、相关文件以及目录等的集合,内置一些经常用的程序。主要有:

1)标准子程序:例如三角函数、反三角函数等

2)标准程序:例如解常微分方程等

3)服务性程序:例如输入、输出、磁盘操作、调试等。

由于windows与linux系统不同,因此二者的二进制库是不兼容的。

Linux系统下的库分为静态库与动态库两种。二者的不同点是在载入时间的不同。

静态库在程序编译时的链接阶段被链接到目标代码中,运行程序时将不再需要静态库。编译后的可执行程序体积较大。

动态库在程序编译时并不会马上链接到目标代码中,而是在执行阶段才被程序载入,因此编译后的可执行程序体积较小,但是需要系统动态库存在。

库是前辈高手写好的成熟的可以直接复用的代码,只需遵守使用协议即可。不可能所有人的编程学习都是从零开始,库的存在使得程序开发变得更加简易。而且如果不同的应用程序调用同样的库,那么内存内只需有一份该库的实例即可,节省了存储空间。

 

2、制作一个静态库

我们可以使用GNU下的ar工具来制作一个静态库

ar是类似gcc的一个GNU工具包内的工具,作用是建立、修改、提取归档文件。归档文件是包含多个文件内容的一个大文件,被包含文件的原始内容、权限、时间戳、所有者等属性都保存于归档文件中,并且可以通过“提取”来还原该文件。

示例:自己制作一个静态库,库函数的功能是传递一个字符串并输出。

第一步:需要准备3个文件:hello.h、hello.c、test.c。其中hello.h和hello.c用于制作静态库,test.c是测试程序主函数

//文件hello.h

#ifndef __HELLO_H__

#define __HELLO_H__

#include<stdio.h>

void hello(const char *name);

#endif

 

//文件hello.c

#include"hello.h"

void hello(const char *name)

{

printf("Hello %s, You are handsome!\n",name);

}

 

//文件test.c

#include"hello.h"

int main()

{

hello("LiLaoShi");//调用自己制作的库

return 0;

}

第二步:将hello.c编译生成目标文件hello.o

gcc hello.c -c -o hello.o

第三步:使用ar将hello.o制作成静态库

ar crs libmyhello.a hello.o

ar参数解析:

1.c:表示无提示方式创建文件包

2.r:在文件包中替代文件

3.s:强制重新生成文件包的符号表

这样就制作了一个名为libmyhello.a的文件包(即静态库)

第四步:编译test.c,将刚制作的静态库加载至程序内

gcc test.c -L. -lmyhello -o hello

gcc参数解析:

1.-L:表示增加目录,让编译器可以在该目录下寻找库文件。后面的 . 表示当前目录;

2.-l:表示加载libXXX.a/libXXX.so库文件。

这样我们就生成了一个hello的可执行文件。执行该文件,会输出"Hello LiLaoShi, You are handsome!",这样我们就成功制作了一个库函数hello。

练习:将libmyhello.a文件删除,再次执行hello程序查看

若我们删除库(即libmyhello.a文件),再次执行该程序仍然可以得到正确的结果。这是因为静态库在链接阶段已经和程序整合到一起,即使原始库文件不存在,程序依然可以成功执行。

 

3、制作一个动态库

我们可以使用gcc工具来制作一个动态库

示例:自己制作一个动态库,库函数的功能是传递一个字符串并输出。

第一步:需要准备3个文件:hello.h、hello.c、test.c。其中hello.h和hello.c用于制作动态库,test.c是测试程序主函数

//代码同上,略

第二步:使用gcc编译生成动态库

gcc hello.c -fPIC -c -o hello.o

gcc hello.o -shared -o libmyhello.so

(或者直接一步:gcc hello.c -fPIC -shared -o libmyhello.so)

gcc参数解析:

1.-fPIC(或-fpic):表示编译为位置独立的代码。位置独立的代码即位置无关代码,在可执行程序加载的时候可以存放在内存内的任何位置。若不使用该选项则编译后的代码是位置相关的代码,在可执行程序加载时是通过代码拷贝的方式来满足不同的进程的需要,没有实现真正意义上的位置共享。

2.-shared:指定生成动态链接库

此时我们就生成了动态库libmyhello.so。

若此时编译文件时加载库

gcc test.c -L. -lmyhello -o hello

运行文件hello时会发现报错:

./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

这是因为Linux系统还无法定位到我们自己制作的库的位置,即我们暂时还无法使用该动态库。

对于Linux系统而言,在可执行程序加载动态库的时候,不仅要知道该库的名字,还需要知道其绝对路径。

我们可以使用ldd指令查看某个可执行程序加载库的情况

ldd hello

linux-gate.so.1 => (0xb77b0000)

libmyhello.so => not found

libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75f6000)

/lib/ld-linux.so.2 (0xb77b1000)

第三步:定位自己制作的动态库

要想让自己制作的动态库生效,我们需要了解正常情况下系统是如何加载一个动态库的。以我们熟悉的stdio库为例,系统在加载标准输入输出库时遵循以下几个步骤:

1.执行./hello指令,终端解释该指令,终端指示应加载动态库stdio,寻找存放动态库的配置文件。

2.存放动态库的配置文件默认目录为/etc/ld.so.conf.d/以及下属的众多子目录内的配置文件。配置文件指示该库的绝对路径在/usr/lib或/lib下。

3.去往/usr/lib或/lib,将存储的stdio库加载到程序hello中。

为了让系统能成功找到自己制作的动态库,需要定位到该动态库的位置。参照正常加载动态库的方式,我们可以有三种方式:

1)把自己制作的库拷贝到/usr/lib和/lib下。

2)在LD_LIBRARY_PATH环境变量中添加自己制作的库所在的位置。

3)添加/etc/ld.so.conf.d/XXX.conf文件(XXX需要自己命名),把库所在的路径添加到文件末尾并执行ldconfig刷新。

注意:练习这三种方法时尽量清除上一种方法的效果影响保证三种方法是独立生效的。

第一种:将库拷贝到/usr/lib和/lib下。

sudo cp libmyhello.so /usr/lib

sudo cp libmyhello.so /lib

此时再执行./hello即可得到正确的显示结果。

第二种:修改LD_LIBRARY_PATH环境变量

sudo vim /etc/bash.bashrc

在文件最后,添加:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/linux/file/dongtaiku

保存退出,重启终端,此时再执行./hello即可得到正确的显示结果。

第三种:添加/etc/ld.so.conf.d/XXX.conf文件

sudo vim /etc/ld.so.conf.d/my.conf

在文件内添加动态库的目录

/home/linux/file/dongtaiku

保存退出,执行ldconfig使设置生效

sudo ldconfig

此时再执行./hello即可得到正确的显示结果。

思考:使用静态库与动态库时,加载库的指令是相同的(都是gcc test.c -L. -lmyhello -o hello)。若静态库与动态库重名(例如libmyhello.a和libmyhello.so),则系统会以哪个库为准?

练习:验证静态库与动态库重名时的加载库的情况。

提示:使用同样的代码分别编译成静态库与动态库,两个库的名称相同,但是不配置动态库的路径。然后编译生成可执行程序,若该程序可以执行则表示以静态库为准,若无法执行则表示以动态库为准。

 

从程序hello的执行结果可以看出,当静态库与动态库重名时,系统会以动态库为准。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值