Category 皮肤鉴赏馆

前言在C、C++中我们使用过标准库,比如在使用strerror、vector、string等时,都只是调用了这些函数接口,这些都是需要具体的实现。

让我们来看看C语言库:

将来运行程序,需要二进制文件和库文件

看下C++标准库:

在Linux系统中,.so结尾是动态库,以.a结尾是静态库;

在Windows中,.dll结尾是动态库,lib结尾是静态库。

静态库静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。

.c文件可形成一个.o文件,将这些.o文件链接形成可执行文件,头文件是一个手册,提供函数声明,告诉用户如何使用,.o文件提供实现,我们只需要补充一个main文件,调用头文件提供的方法,然后和.o文件进行连接,就能形成可执行文件。

静态库制作简单制作一个静态库

代码语言:javascript代码运行次数:0运行复制// add.h

#pragma once

int add(int x, int y);代码语言:javascript代码运行次数:0运行复制// add.c

#include "add.h"

int add(int x, int y)

{

return x + y;

}代码语言:javascript代码运行次数:0运行复制// sub.h

#pragma once

int sub(int x, int y);代码语言:javascript代码运行次数:0运行复制// sub.c

#include "sub.h"

int sub(int x, int y)

{

return x - y;

}静态库的生成静态库生成指令:ar -rc lib静态库名.a 需要形成静态库的文件,ar是gnu归档工具,rc表示replace and create

静态库的形成本质上是将所有的.o文件打包,因此需要先生成.o文件

发布静态库发布静态库就是自己的lib拷贝给比人

例如上图是我自己制作的一个简单静态库,只需要将mylib拷贝给别人即可。

使用静态库将自己的mylib拷贝到一个test文件夹中,然后写一个main.c文件,用于测试静态库的使用

mian.c:

代码语言:javascript代码运行次数:0运行复制#include "add.h"

#include "sub.h"

#include

int main()

{

printf("1 + 2 = %d\n", add(1, 2));

printf("1 - 2 = %d\n", sub(1, 2));

return 0;

} 编译:

这里报错了,说找不到对应的头文件

头文件一般有以下两种方式来包含头文件:

使用<>来包含头文件,表示到系统指定目录下去查找头文件使用" "来包含头文件,这种方式一般用于包含自己所写的头文件中,表示在当前源文件的统计目录下查找头文件,找到了就用,没找到再去系统指定目录下进行查找,所以对于库提供的头文件我们也可以使用 " " 进行包含。在main.c文件中,就是使用" "来包含我所写的头文件,但是还是会报错,理由:使用" "所包含的头文件,会告诉编译器在main.c同级目录下(即test目录下)查找对应的头文件,但是add.h、sub.h文件在test文件中的mylib文件中,因此无法找到。

解决上述有三种方式:

将头文件直接拷贝到当前目录下在代码中头文件的路劲补全,如:#include " /mylib/include/add.h " 在执行 gcc 指令编译的时候加上 -I 选项,指定编译器搜索头文件的路径

系统默认的指定路劲:/usr/include

使用方法3:gcc main.c -I ./mylib/include

此时依然没有编译成功,此时不是找不到头文件,而是链接错误。gcc在编译的时候,只会去默认路径下查找打包的头文件,不会去/mylib/include中查找,编译器在gcc是就找不到我的酷libmyc.a,也就是编译链接失败。

此时可以形成main.o文件:

解决此错误有两种方法:

将我们的库拷贝到系统的指定路径下,并不能完全解决,还需要指定库的名称在使用 gcc 的时候添加对应的选项-L 指定库路径-l 指定库名为什么在搜索头文件的时候仅需指定路径呢?当你编译程序时,编译器会首先在这些默认路径下搜索所需的头文件。

在代码中已经写了头文件的具体名称,所以仅需指定头文件的路径即可。而一个路径下可以有多个库,如果只指定路劲,编译器还是不知道该去链接哪个库,因此还要在后面使用 -l 选项指定待链接的库的具体名称。

注意:去掉前缀 lib 和 后缀 .a 才是一个库的名称,建议 -l 后面紧跟库的名称。一般在使用第三方库的时候,可能不需要带 -I 或者 -L,但是 -l 指定库的名称是一定需要到,因为 gcc 默认只能找到系统调用和语言层面的库。

安装静态库静态库的安装本质上就拷贝到系统的特定目录下。

卸载静态库卸载静态库本质是将.h文件和自己的静态库从默认的路劲中删除,此时就无法通过静态库来运行程序。

动态库动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

动态库的制作简单制作一个动态库

代码语言:javascript代码运行次数:0运行复制// add.h

#pragma once

int add(int x, int y);代码语言:javascript代码运行次数:0运行复制// add.c

#include "add.h"

int add(int x, int y)

{

return x + y;

}代码语言:javascript代码运行次数:0运行复制// sub.h

#pragma once

int sub(int x, int y);代码语言:javascript代码运行次数:0运行复制// sub.c

#include "sub.h"

int sub(int x, int y)

{

return x - y;

}动态库的生成fPIC:产生位置无关码(position independent code)shared: 表示生成共享库格式库名规则:libxxx.solibmyc.so就是生成的动态库

动态库的发布将动态库拷贝到刚刚我们静态库的位置

使用动态库mian.c:

代码语言:javascript代码运行次数:0运行复制#include "add.h"

#include "sub.h"

#include

int main()

{

printf("1 + 2 = %d\n", add(1, 2));

printf("1 - 2 = %d\n", sub(1, 2));

return 0;

} 按照静态库的使用方法,来使用静态库:

虽然生成了可执行文件,但是可执行文件出错了

使用ldd a.out时,发现libmyc.so => not found,动态库没有被找到,编译期间已经告诉系统对应的头文件以及库的位置,但是这是告诉编译器,没有告诉操作系统,因此编译通过,但是无法运行。

动态库要在程序运行的时候要找到动态库加载运行。静态库为什么没有这个问题?因为静态库在编译期间已经将库中的代码拷贝到可执行程序内部了,加载和库就没有关系了。

解决该问题,有以下四种方法:

将库文件拷贝到系统默认的库路(/lib64、/usr/lib64),不推荐使用这种方法,因为修改了系统规定的库,降低了系统的健康指数在系统默认的库路径(/lib64、/usr/lib64)下建立软链接

将自己库所在的路径,添加到系统的环境变量 LD_LIBRARY_PATH 中,该环境变量就是专门用来搜索动态库的

但是重新启动系统后,就找不到该环境变量,如果想让系统启动时自动添加该路径到 LD_LIBRARY_PATH 环境变量中,可以通过修改 ~/.bash_profile 中的配置去实现,但是不推荐这么写,不建议修改环境变量。

如果想让我们的库和系统、语言自带的库一样,在程序运行的时候可以自动被找到,那我们可以/etc/ld.so.conf.d 路径下添加一个 .conf 结尾的配置文件

该配置文件里面的内容就是我们自己动态库所在的路径。添加完后执行 ldconfig 指令,将所有的配置文件重现加载一下,然后程序就能够正常运行。

此时程序就可以正常运行:

动态库VS静态库动静态库同时存在时,默认连接的是动态库:

此时对应的可执行程序的体积很小:

那么如何使用静态库?

只需在后面加一个-static

此时对应的可执行文件体积很大:

如果你没有使用-static并且只提供.a,只能静态库连接当前的.a库,其他库正常动态连接。

-static的意义是什么呢?

必须强制的将程序进行静态连接,这就要求连接的任何库都必须提供对应的静态库版本。

top
Copyright © 2088 英雄新物攻略库 - MOBA游戏活动智库 All Rights Reserved.
友情链接