Linux下生成和使用C++的静态库和动态库

一、什么是库

windows平台和linux平台下都大量存在着库。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
由于windows和linux的平台不同(主要是编译器、汇编器和连接器的不同),因此二者库的二进制是不兼容的。本文仅限于介绍linux下的库。

二、库的种类

Linux下的库有两种:静态库和共享库(动态库)。二者的不同点在于代码被载入的时刻不同。静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。共享库的代码是在可执行程序运行时才载入内存的, 在编译过程中仅简单的引用, 因此代码
体积较小。

三、在linux下,库文件是如何产生的

1、静态库的后缀是.a,它的产生分两步
Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表
Step 2.ar命令将很多.o转换成.a,成为静态库

2、动态库的后缀是.so,它由gcc加特定参数编译产生。
具体方法参见后文实例


在linux下,库文件一般放在/usr/lib和/lib下,静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称;
动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本;

四、如何知道一个可执行程序依赖哪些库

ldd命令可以查看一个可执行程序依赖的共享库,
例如# ldd  /bin/lnlibc.so.6

=>/lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2
=>/lib/ld- linux.so.2 (0×40000000

 五、在新安装一个库之后如何让系统能够找到它

如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。
如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下:

.1、编辑/etc/ld.so.conf文件,加入库文件所在目录的路径
 2、运行ldconfig,该命令会重建/etc/ld.so.cache文件

六、实例

有如下三个文件

hello.h

#ifndef HELLO_H
#define HELLO_H

void hello(const char *name);

#endif

hello.c

#include 

void hello(const char *name){

    printf("Hello%s!\n",name);
}

main.c

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

这里有三种思路:
1) 通过编译多个源文件,直接将目标代码合成一个.o文件。
2) 通过创建静态链接库libmyhello.a,使得main函数调用hello函数时可调用静态链接库。
3) 通过创建动态链接库libmyhello.so,使得main函数调用hello函数时可调用动态链接库
思路一:

输入以下命令得到hello.o文件

# gcc -c hello.c

同理理编译main.c

# gcc –c main.c

将两个文件链接成一个.o文件

# gcc hello.o main.o –o hello

运行

./hello

解析:

使用-c是什么意思呢?这涉及到gcc 编译选项的常识。我们通常使用的gcc –o 是将.c源文件编译成为一个可执行的二进制代码(-o选项其实是制定输出文件文件名, 如果不加-c选项, gcc默认会编译连接生成可执行文件, 文件的名称由-o选项指定),这包括调用作为GCC内的一部分真正的C编译器( ccl),以及调用GNU-C编译器的输出中实际可执行代码的外部GNU汇编器( as)和连接器工具( ld)。

而gcc –c是使用GNU汇编器将源文件转化为目标代码之后就结束,在这种情况下,只调用了C编译器( ccl)和汇编器( as), 而连接器(ld)并没有被执行, 所以输出的目标文件不会包含作为Linux程序在被装载和执行时所必须的包含信息,但它可以在以后被连接到一个程序。

 思路二

首先,编译hello.o

# gcc -c hello.c

在系统提示符下键入以下命令将创建静态库文件libmyhello.a。

# ar rcs libmyhello.a hello.o

静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明, 然后再用GCC命令生成目标文件时指定的静态库名,GCC就会从静态库中将公用函数连接到目标文件中。注意, GCC会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件,因此, 我们在写需要连接的库时, 只写名字就可以,如libmyhello.a的库,只写:-lmyhello

# gcc -o hello main.c -L. -lmyhello

# ./hello

思路三

在编译时添加fPIC,得到hello.o文件

# gcc -c -fPIC hello.c

输入以下命令得到动态库文件libmyhello.so

 # gcc -shared -fPIC -o libmyhello.so hello.o

解析:”PIC” 命令行标记告诉GCC产生的代码不要包含对函数和变量具体内存位置的引用,这是因为现在还无法知道使用该消息代码的应用程序会将它连接到哪一段内存地址空间。这样编译出的hello.o可以被用于建立共享链接库。建立共享链接库只需要用GCC的” -shared"标记即可。 

生成hello可执行文件

# gcc -o hello main.c -L. -lmyhello

解析:使用” -lmyhello” 标记来告诉GCC驱动程序在连接阶段引用共享函数库libmyhello.so。” -L.”标记告诉GCC函数库可能位于当前目录。否则GNU连接器会查找标准系统函数目录:它会先后搜索

1.elf文件的 DT_RPATH段

2.环境变量LD_LIBRARY_PATH

3./etc/ld.so.cache文件列表

4. /lib/,/usr/lib目录找到库文件后将其载入内存,

但是我们生成的共享库在当前文件夹下,并没有加到上述的4个路径的任何一个中,因此,执行./hello 后 会出现错误.

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

正确的方式是以下四种:

1、直接执行

# LD_LIBRARY_PATH=. ./hello

2、我们将文件 libmyhello.so复制到目录/usr/lib中,再试试./hello

# cp libmyhello.so /usr/lib

3、或者我们可以将这个环境变量设置成当前目录

# export LD_LIBRARY_PATH=$(pwd)

4、或者执行

# ldconfig /usr/zhsoft/lib

解析:用户在某个目录下面创建或拷贝了一个动态链接库,若想使其被系统共享,可以执行一下"ldconfig 目录名" 这个命令.此命令的功能在于让 ldconfig将指定目录下的动态链接库被系统共享起来,意即:在缓存文件/etc/ld.so.cache中追加进指定 目录下的共享库.本例让系统共享了/usr/zhsoft/lib目录下的动态链接库.该命令会重建/etc/ld.so.cache文件

最后执行./hello


七、静态库与动态库的执行顺序

7.1 静态库链接时搜索路径顺序
1.1d会去找GCC命令中的参数-L
2.再找gcc的环境变量 LIBRARY PATH
3.再找内定目录/1ib/usr/lib/usr/ local/lib这是当初 compile gcc时写在程序内的


7.2 动态链接时、执行时搜索路径顺序
1.编译目标代码时指定的动态库搜索路径
2.环境变量 LD LIBRARY PATH指定的动态库搜索路径
3.配置文件/etc/ld.so.conf中指定的动态库搜索路径:
4.默认的动态库搜索路径/1ib
5.默认的动态库搜索路径/usr/lib。

参考:

linux命令之ar—创建静态库.a文件_chenglinhust的专栏-CSDN博客_ar生成静态库
Linux-(C/C++)生成并使用静态库/动态库_佛系程序猿-CSDN博客_c++ 编译静态库

你可能感兴趣的:(Cmake,c++,容器,开发语言)