制作静态库和动态库

这篇具有很好参考价值的文章主要介绍了制作静态库和动态库。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

制作静态库

ar命令

使用makefile制作静态库

如何发布自己的静态库给别人呢?

如何使用静态库呢?

方法一

方法二

制作动态库

使用动态库遇到的问题

上面的问题如何解决呢?(如何使用动态库)

1.方法一

2.方法二

3.方法三

4.方法四

搜索优先级

Linux默认头文件的搜索顺序

Linux默认库文件的搜索顺序

链接动态库和静态库的顺序

为什么要有库?


制作静态库

ar命令

问题:如果得到别人的.o文件,我们是可以使用这个文件里的方法的,但如果.o文件过多,比如有1000个,那Linux中使用gcc命令链接这些二进制文件的时候岂不是要将1000个文件的名称都写出来?更何况文件多了之后还容易漏掉个别文件,所以这种方法不可取,那该怎么办呢?

答案:使用ar命令将这些.o文件打包(正式的说法叫归档),这个归档的过程就叫制作静态库。将所有 .o文件(即目标二进制文件)归档即可制作一个静态库出来。可以得到一个结论,静态库中全是.o文件,没有.h文件。

注意事项:

1.归档后的静态库的名称前3个字符必须是lib,文件后缀名必须是.a,其他的自定义即可,如下图的libhello.a。

2. ar -rc,这里的r表示replace(替换),c表示create(创建)。

makefile编译静态库,Linux,linux,运维,服务器

使用makefile制作静态库

makefile编译静态库,Linux,linux,运维,服务器

如何发布自己的静态库给别人呢?

创建一个发布目录文件,里面包含目录文件include和目录文件lib。include文件里包含了库的所有头文件,lib文件中包含了所有的静态库文件,如下图中的 libhello.a文件,并且因为 lib目录中包含了静态库文件,那么一堆.o文件也就不需要了。最后将这个发布目录文件交给别人,这就是发布的过程。注意只要是库,头文件也必须给别人,不然谁知道可以使用哪些方法,所以发布目录文件里存在include目录

如下图就是模拟发布的过程(创建发布目录文件的过程)

代码如下

makefile编译静态库,Linux,linux,运维,服务器

 ​​​​​​运行结果如下

makefile编译静态库,Linux,linux,运维,服务器

​​​​​​​

如何使用静态库呢?

方法一

makefile编译静态库,Linux,linux,运维,服务器

1.首先将include目录的所有文件拷贝到系统寻找头文件的默认路径中,如下图。

makefile编译静态库,Linux,linux,运维,服务器

2.然后将静态库文件拷贝到系统寻找静态库文件的默认路径中,如下图(注意系统寻找静态库文件的默认路径就是/lib64,而不是/usr/lib64。/是根目录,lib64和usr一样,都是根目录中的一个目录文件)。

makefile编译静态库,Linux,linux,运维,服务器

遇到的问题:经过前面的步骤后,使用gcc编译下面代码失败,为什么呢?

代码如下

makefile编译静态库,Linux,linux,运维,服务器

运行结果如下

​​​​​​​​​​​​​makefile编译静态库,Linux,linux,运维,服务器

答案如下:

  • 如果libhello.a是系统库,为了保证程序能在系统下正常运行,则gcc会自动链接libhello.a库,那么此时自然可以通过编译并运行;如果是C语言提供的静态库,由于gcc是C语言编写的,所以编译时会自动帮我们链接C语言提供的静态库,所以上图代码自然也可以通过编译并运行。但问题在于libhello.a这个静态库既不是系统提供的,也不是语言提供的,是我们自己编写并新增到OS中的,属于第三方库,所以不满足条件,所以无法通过编译并运行。
  • 然后要知道gcc在进行链接时,并不会将所有可见的静态库都进行链接,否则会造成代码冗余。现在的情况是:虽然经过我们手动添加,libhello.a已经在系统寻找静态库的默认路径中,但libhello.a毕竟不是系统库,也不是C语言库,即不是一个必须存在的库,所以如果没有指定gcc链接libhello.a静态库,则gcc为了避免代码冗余的可能性存在,是不会将该库进行链接的,所以说到这里结果已经显而易见,编译失败是因为没有告诉gcc需要链接哪个静态库,所以都没有链接到libhello.a,此时使用静态库libhello.a里的方法自然是不行的。那么如何链接libhello.a呢?请往下看。

3.然后链接想要使用的静态库。如下图,gcc后面加上 -l 选项和静态库的名称。注意这里文件的名称需要去掉前缀 lib 和后缀 .a才行,如下图将静态库libhello.a拆解成了hello。

makefile编译静态库,Linux,linux,运维,服务器

4.最后成功地使用了静态库libhello.a编译出可执行文件a.out。(由于编译时没有带生成文件的名称,所以生成文件的名称为a.out)

makefile编译静态库,Linux,linux,运维,服务器

总结一下:在本种方法中是靠将库文件和头文件的路径加载进系统的默认搜索路径中实现了让OS和gcc找到该库文件和头文件;是靠在gcc命令中加了-l(小写的L)选项(如上图2中的gcc main.c -lhello)实现了让gcc知道该链接哪个库文件(因为库文件的路径被加载进系统默认的搜索路径中,所以gcc能找到库文件的位置,所以能链接成功)

上面的操作将我们自己写的库拷贝到了系统搜索库的默认路径中,这就叫做库的安装。最好不要将自己写的库拷贝进OS寻找库的默认路径中,会造成系统的污染,所以想要使用静态库还有更好的方法。

方法二

直接在编译时带上头文件所在的路径和静态库所在的路径即可,如下图。 注意 -I(为大写的i,不是小写的L)表示include,-L表示lib(library)。

注意 -I 和 -L 选项分别用于指定头文件的搜索路径和库文件的搜索路径,但它们并不直接告诉编译器在链接时要链接哪个库,这些选项只是告诉编译器在指定路径中查找头文件和库文件,指定路径中的库文件可能有多个,真正告诉编译器在链接时要链接哪个库的是 -l 选项(为小写的 L,而不是大写的 i ),如下图的 -lhello。

makefile编译静态库,Linux,linux,运维,服务器

错误示例:

1.下图红框处没有带具体的静态库的名称,所以编译出错。因为./hello/lib路径下可能有很多个静态库文件,如不加入具体的名称,会不知道链接哪一个。

makefile编译静态库,Linux,linux,运维,服务器

2.下图中只有头文件的路径,没有静态库的路径和名称。makefile编译静态库,Linux,linux,运维,服务器

3.gcc在编译时,根据上文的搜索文件的顺序,编译器搜索头文件和静态库所在的路径的顺序先是当前路径,但此时当前路径中不存在main.c里包的头文件,也不存在包含main.c里使用的方法的静态库,所以编译失败。

makefile编译静态库,Linux,linux,运维,服务器

总结一下:在本种方法中是靠【将头文件和库文件的路径通过-I(大写的i)和-L选项告诉了gcc】实现了让gcc找到该库文件和头文件;是靠在gcc命令中加了-l(小写的L)选项实现了让gcc知道该链接哪个库文件(因为库文件的路径在使用gcc命令时通过-L选项告诉了gcc,所以gcc能找到库文件的位置,所以能链接成功)。

制作动态库

1.首先生成若干个需要的 .o 文件,注意有选项-fPIC,如下图。

makefile编译静态库,Linux,linux,运维,服务器

2.然后生成动态库即可,注意有选项-shared,如果没有这个选项,编译器则会认为你是要生成可执行文件,而不是动态库,然后生成失败,因为我们写的动态库文件中没有main函数,生成不了可执行文件。makefile编译静态库,Linux,linux,运维,服务器

如下图是使用makefile同时编译动态库和静态库

makefile编译静态库,Linux,linux,运维,服务器

使用动态库遇到的问题

makefile编译静态库,Linux,linux,运维,服务器

问题:首先创建一个包含动态库的发布目录文件,如上图的output文件。由于gcc默认采用动态链接,所以当动态库和静态库同名并同时存在时,gcc会链接动态库。gcc编译成功后生成了下图的可执行文件a.out(也就是编译成功了),但当运行a.out的时候会发生报错(也就是运行失败了),错误信息是找不到该动态库,所以无法将动态库加载进内存,为什么会这样呢?​​​​​​​

​​​​​​​makefile编译静态库,Linux,linux,运维,服务器

答案:动态库libhello.so是一个独立的文件,和可执行文件a.out是通过分批加载的方式加载进内存,所以运行失败的原因就是因为此时OS不知道动态库libhello.so在哪,导致OS无法将该动态库加载进内存。这又是为什么呢?或者换句话说,我不是已经通过在gcc命令处加上了-L选项告诉了OS动态库文件的路径吗,为什么OS会不知道动态库libhello.so在哪呢?说一下,在gcc命令中添加-I 和 -L 选项只会告诉编译器在哪里查找头文件和库文件,这些选项只在编译阶段起作用,而不会在运行时起作用,这两个选项不会自动将库文件路径添加到系统的动态链接库的默认搜索路径中,所以OS就不知道动态库libhello.so在哪,所以OS就没法将动态库加载进内存。在编译阶段,编译器使用 -I 和 -L 选项来查找头文件和库文件的位置,以便能够正确编译你的代码。但在运行时,当你的程序试图加载动态库时,操作系统需要知道动态库文件的位置,否则就无法将其加载进内存。

问题:为什么运行链接静态库的可执行程序时不会出现上述的问题呢?

答案:因为静态库的代码是以拷贝的形式填充进了可执行程序,所以不会分批加载,所以不会产生上述问题。

上面的问题如何解决呢?(如何使用动态库)

1.方法一

既然上面问题出现的原因是因为OS不知道动态库文件的所在路径,找不到动态库文件,那么解决的方法也就可以和使用静态库的方法一相同,直接将动态库文件和头文件添加到系统搜索库文件和头文件的默认路径中,之后运行可执行文件a.out时,需要的动态库文件自然就可以被系统找到并加载进内存中了。但依然不建议使用此方法,容易污染系统的生态。

总结一下:因为在上面说过,gcc中的-I(大写的i)和-L选项只能让gcc知道头文件和动态库文件在哪,无法让OS知道头文件和动态库文件在哪,所以在本种方法中是靠将动态库文件和头文件的路径加载进系统的默认搜索路径中实现了让OS能够找到该库文件和头文件,以此在运行通过这些动态库实现的可执行程序时让OS能够将动态库分批加载进内存;是靠在gcc命令中加了-I(大写的i)和-L选项让gcc知道头文件和动态库文件在哪;是靠在gcc命令中加了-l(是小写的L)选项实现了让gcc知道该链接哪个库文件(因为库文件的路径在使用gcc命令时通过-L选项告诉了gcc,所以gcc能找到库文件的位置,所以能链接成功)

然后说一下,其实这里方法1中有一步是多余的:如果直接将动态库文件和头文件添加到系统搜索库文件和头文件的默认路径中,那么此时gcc和OS就都能找到该动态库文件和头文件,所以使用gcc指令进行链接时就不需要再加上-I(大写的i)和-L选项让gcc知道该动态库文件和头文件在哪了,因为gcc直接在系统搜索库文件和头文件的默认路径中就能找到它们。但注意,虽然不需要加上-I(大写的i)和-L选项让gcc知道该动态库文件和头文件在哪,但一定是需要加上-l(小写的L)选项告诉gcc需要进行链接的动态库文件是哪一个的。举个例子,假如有个动态库文件叫libhello.so,那么使用该动态库时,只要将该动态库文件和头文件添加到系统搜索库文件和头文件的默认路径中后,在使用gcc编译时,直接gcc xxx.c -o xxx -lhello就可以将包含libhello.so动态库文件的可执行程序xxx给生成出来并且能成功使用了。

2.方法二

修改环境变量LD_LIBRARY_PATH,LD表示load(加载),LIBRARY表示lib(库)。

makefile编译静态库,Linux,linux,运维,服务器

如上图,在冒号( : )的后面加入库所在的路径即可,路径最后不需要带库本身的名称。注意不要将之前的环境变量覆盖掉了,所以上图中等于号(=)的后面是 $LD_LIBRARY_PATH:,而不是直接的一条路径。

此种方式有一个缺点:环境变量是内存级的变量,所以每次登录时,环境变量都会从某个配置文件中读取数据,所以退出登录后再次登录,之前用户在shell中设置的环境变量就失效了。

总结一下:因为在上面说过,gcc中的-I(大写的i)和-L选项只能让gcc知道头文件和动态库文件在哪,无法让OS知道头文件和动态库文件在哪,所以在本种方法中是靠将动态库文件的路径加载进环境变量LD_LIBRARY_PATH中实现了让OS能够找到该动态库文件,以此在运行通过这些动态库实现的可执行程序时让OS能够将动态库分批加载进内存;是靠在gcc命令中加了-I(大写的i)和-L选项让gcc知道头文件和动态库文件在哪;是靠在gcc命令中加了-l(是小写的L)选项实现了让gcc知道该链接哪个库文件(因为库文件的路径在使用gcc命令时通过-L选项告诉了gcc,所以gcc能找到库文件的位置,所以能链接成功)

3.方法三

改进方法二的弊端,本种方法就是修改配置文件。如果觉得自己写的库很重要,但又不想加载到系统搜索库文件的默认路径中,防止污染系统的生态,就可以使用本种方法。

makefile编译静态库,Linux,linux,运维,服务器

首先在上图的路径中创建一个普通文件,文件名无所谓,但后缀名必须是.conf,如下图。

makefile编译静态库,Linux,linux,运维,服务器

然后用vim编辑器,将动态库的路径写进105.conf,注意路径中不需要动态库本身的名称。(前面不一定非要使用vim编辑器,只要你能把路径写进配置文件就行)

配置文件编写完毕后,最后在shell命令行中使用ldconfig指令,让配置文件105.conf生效即可,如下图。注意修改配置文件一般需要较高权限,所以加sudo。

makefile编译静态库,Linux,linux,运维,服务器

上面操作完成后,此时就算环境变量LD_LIBRARY_PATH中不存在动态库所在的路径,也可以正常运行可执行程序。

容易陷入的误区:

makefile编译静态库,Linux,linux,运维,服务器

有时候发现删除了配置文件105.conf,但需要105.conf文件里写的路径上的动态库的可执行程序依然可以正常运行,这是因为有缓存的存在,此时再次sudo ldconfig将缓存更新,需要对应动态库的可执行程序就运行不了了。

总结一下:因为在上面说过,gcc中的-I(大写的i)和-L选项只能让gcc知道头文件和动态库文件在哪,无法让OS知道头文件和动态库文件在哪,所以在本种方法中是靠将动态库文件的路径加载进配置文件中实现了让OS能够找到该动态库文件,以此在运行通过这些动态库实现的可执行程序时让OS能够将动态库分批加载进内存;是靠在gcc命令中加了-I(大写的i)和-L选项让gcc知道头文件和动态库文件在哪;是靠在gcc命令中加了-l(是小写的L)选项实现了让gcc知道该链接哪个库文件(因为库文件的路径在使用gcc命令时通过-L选项告诉了gcc,所以gcc能找到库文件的位置,所以能链接成功)

4.方法四

软连接方案,感兴趣自行探索。

搜索优先级

Linux默认头文件的搜索顺序

(如果阅读完上文,这里是很容易理解的)

在Linux系统中,头文件的搜索顺序通常遵循以下规则:

  1. 当前目录(.:首先,编译器会搜索当前工作目录中的头文件。这通常是你正在编写代码的目录。

  2. 系统默认的标准头文件目录:编译器会搜索系统默认的标准头文件目录,这些目录通常包含C标准库和C++标准库的头文件。具体的目录可能会因Linux发行版和编译器而异,但通常就是 /usr/include 或者 /usr/local/include

  3. 使用-I选项指定的目录:如果你在编译时使用 -I 选项明确指定了头文件的搜索路径,编译器将搜索这些指定的目录。

  4. 环境变量:编译器还会考虑环境变量 C_INCLUDE_PATH 和 CPLUS_INCLUDE_PATH 中指定的目录。这些环境变量可以用来指定额外的头文件搜索路径。

  5. 编译器内置路径:编译器通常有一些内置的默认搜索路径,这些路径是编译器的默认设置,通常包括一些常见的头文件和库文件位置。

注意,上述搜索顺序是通常情况下的规则,具体实现可能会因不同的编译器和Linux发行版而有所不同。你可以使用 -v 选项来查看编译器的详细搜索路径。例如,使用 gcc -v 来查看GCC编译器的搜索路径。

总之,在编写代码时,确保你的头文件能够被编译器找到,可以使用 -I 选项指定自定义的头文件搜索路径,或者将头文件放在系统默认的标准头文件目录中。

Linux默认库文件的搜索顺序

(如果阅读完上文,这里是很容易理解的)

在Linux系统中,库文件的搜索顺序通常遵循一定的规则,以确保动态链接器能够找到所需的库文件。默认的库文件搜索顺序通常如下:

  1. 编译目标代码时指定的动态库搜索路径:如果在gcc或者g++编译代码时使用了 -L 选项来指定库文件的搜索路径,编译器会优先搜索这些指定的路径。

  2. 环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径:你可以使用 LD_LIBRARY_PATH 环境变量来指定额外的动态库搜索路径。这个环境变量允许你在运行时指定库文件的搜索路径,但它通常被认为是一个不太安全的方式,不推荐在生产环境中使用。

  3. 配置文件 /etc/ld.so.conf 中指定的动态库搜索路径:在这个文件中,系统管理员可以为系统指定默认的动态库搜索路径。如果你的库文件位于这些路径下,动态链接器会自动找到它们。

  4. 默认的系统库路径:如果以上步骤都没有找到所需的库文件,动态链接器会搜索默认的系统库路径,即/lib64 (注意/是根目录)。

这些是Linux系统中库文件的默认搜索顺序。你可以通过它们来更改库文件的搜索路径,以满足你的特定需求。在编译时,一般可以使用 -L 选项来指定自定义的库文件搜索路径。

链接动态库和静态库的顺序

情景1如下

makefile编译静态库,Linux,linux,运维,服务器

如上图,当动态库和静态库同时存在并且同名时,gcc编译时默认使用动态库。

情景2如下

makefile编译静态库,Linux,linux,运维,服务器

如上图,当动态库和静态库同时存在并且同名时,如果非要使用静态库进行链接,那么必须加-static选项,-static表示摒弃编译器默认优先使用动态库的原则,并直接使用静态库。 

情景3如下

​​​​​​​makefile编译静态库,Linux,linux,运维,服务器

如上图,即使编译器不带-static选项进行编译时默认链接动态库,但当只有静态库时,也只能以静态链接的方式将静态库拷贝进程序中,程序需要的其它库文件如果是动态库,则以动态方式链接。此时发现ldd命令列出的动态库依赖关系中并没有hello这个静态库文件,事实上不必担心,a.out这个文件一定使用了hello这个静态库的,因为a.out可以成功运行。

为什么要有库?

因为简单便利和安全。安全是指如果想把方法给别人使用,但不想泄漏代码,就可以通过只把库给别人。文章来源地址https://www.toymoban.com/news/detail-769770.html

到了这里,关于制作静态库和动态库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux之静态库和动态库

    目录 一、前言 二、对于库的理解 三、静态库 四、动态库 五、动静态库的加载 在之前,我们讲了静态库和动态库,详情请跳转:静态库和动态库 下面我们将从工程师的角度,去了解静态库和动态库的形成过程,以及实现它们的制作。并且了解如何将自己的库交给别人,让别

    2024年01月20日
    浏览(35)
  • Linux中静态库和动态库的使用

    介绍: 库是一个二进制文件,包含的代码可被程序调用 标准C库、数学库、线程库… 库有源码,可下载后编译;也可以直接安装二进制包 位置一般放在:/lib /usr/lib 库的知识 库是事先编译好的,可以复用的代码 在os上运行的程序基本上都要使用库,使用库可以提高开发效率

    2024年01月25日
    浏览(36)
  • linux下g++链接动态库和静态库

    头文件的作用: include的作用就是复制内容到当前文件 井号开头的就是预处理指令,由预处理器处理,预处理阶段不关心代码,只处理预处理指令。 头文件主要 一是为了解决代码都写在一个文件太大了,二是把变量,结构体,函数声明这些固定的放在一起 函数只要声明了,

    2024年02月09日
    浏览(47)
  • linux并发服务器 —— 动态库和静态库实战(一)

    -E 预处理指定源文件 -S 编译指定源文件 -c 汇编指定源文件 -o 生成可执行文件 -I directory 指定Include包含文件的搜索目录 -g 编译的时候生成调试信息 -D 在程序编译时指定一个宏 -w 不生成任何的警告信息 -Wall 生成所有警告 -On n:0~3;表示编译器的优化选项级别 O0 - 不优化;O1 -

    2024年02月11日
    浏览(49)
  • 制作静态库和动态库

    目录 制作静态库 ar命令 使用makefile制作静态库 如何发布自己的静态库给别人呢? 如何使用静态库呢? 方法一 方法二 制作动态库 使用动态库遇到的问题 上面的问题如何解决呢?(如何使用动态库) 1.方法一 2.方法二 3.方法三 4.方法四 搜索优先级 Linux默认头文件的搜索顺序

    2024年02月03日
    浏览(31)
  • Linux操作命令&静态库和动态库区别&大小端&孤儿僵尸进程

    cd:切换当前目录 ls:查看当前文件与目录 grep:通常与管道符命令一起使用,用于对一些命令的输出进行筛选和加工 cp:复制文件或文件夹 mv:移动文件或文件夹 rm:删除文件或文件夹 ps:查看进程情况 kill:向进程发送信号 tar:对文件进行打包 cat:查看文件内容 top:查看

    2024年02月16日
    浏览(41)
  • 详解Linux下静态库/动态库的生成和使用(含代码示例和操作流程)&&动态库和静态库的区别

    关于gcc的使用方法可以参考下方链接博客: Linux下详解gcc编译过程(含代码示例) gcc使用教程 库是一种组件技术。 库里封装了数据和函数,提供给用户程序调用。 库只执行到第三阶段编译,没有链接。 库的使用可以使程序模块化,提高程序的编译速度,实现代码复用。

    2024年02月15日
    浏览(42)
  • 【探索Linux】—— 强大的命令行工具 P.13(文件系统 | 软硬链接 | 动态库和静态库)

    在计算机科学领域中,Linux 系统一直以来都是备受推崇的操作系统之一。其中,文件系统、软硬链接、动态库和静态库是 Linux 系统中非常重要的概念,在实际应用中扮演着不可或缺的角色。 在上一篇文章中,我们了解了 Linux 系统中文件描述符、重定向以及基础 IO 操作的相关

    2024年02月04日
    浏览(51)
  • aarch64-linux-gcc安装编译及生成so动态库和调用

    官方二进制下载 Ubuntu packages 提供了软件包: gcc-arm-linux-gnueabihf (4:7.4.0-1ubuntu2.3 以及其他的) 。 建议直接从 linaro 的官网下载相应版本的 gcc-linaro 交叉编译工具,并直接选择带有二进制的文件,即在官网入口处选择 binaries 路径,该文件夹下面包含各种版本的已经编译好的 aarch

    2024年02月13日
    浏览(56)
  • 【Linux】静态库与动态库制作及运行原理

    Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法…感兴趣就关注我吧!你定不会失望。 先来总体描述下静态库与动态库的区别. 静态库是将头文件总体复制到可执行文件当中 。 动态库是在可执行程序运行时进行了动态链接 (所需要某个实现方法就去内存中查找). 所

    2024年02月05日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包