Linux生成静态库_linux生成静态库

Linux生成静态库_linux生成静态库转自:https://blog.csdn.net/ddreaming/article/details/53096411一、动态库、静态库简介库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库.a(win系统下是lib)和动态…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

转自:https://blog.csdn.net/ddreaming/article/details/53096411


一、动态库、静态库简介

库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:

静态库.a(win 系统下是lib)和动态库.so(win 系统下是.dll)。所谓静态、动态是指链接。回顾一下,将一个程序编译成可执行程序的步骤:


Linux生成静态库_linux生成静态库

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库

Linux生成静态库_linux生成静态库



Linux生成静态库_linux生成静态库


静态库特点总结:

静态库对函数库的链接是放在编译时期完成的。

程序在运行时与函数库再无瓜葛,移植方便。

-浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。

是静态库对程序的更新、部署和发布页会带来麻烦。如果静态库liba.lib更新了,所以使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新)。

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在

Linux生成静态库_linux生成静态库

动态库特点总结:

动态库把对一些库函数的链接载入推迟到程序运行的时期。

可以实现进程之间的资源共享。(因此动态库也称为共享库)

将一些程序升级变得简单。

甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。


文主要通过举例来说明在 Linux 中如何创建静态库和动态库,以及使用它们。

[ps:在windows平台和linux平台下都大量存在着库。由于windowslinux的平台不(主要是编译器、汇编器和连接器的不同),因此二者库的二进制是不兼容的。本文仅限于介绍 linux 下的库。]

二、用gcc生成静态和动态链接库的示例

首先,本文主要通过举例来说明在 Linux 中如何创建静态库和动态库,以及使用它们。为了便于阐述,我们先准备下测试代码:hello.h、hello.c、main.c(我将这三个代码放在一个名为‘静态链接’的文件夹中)。如下所示

hello.h

  1. #ifndef HELLO_H  
  2. #define HELLO_H  
  3. void hello(const char* name);  
  4. #endif  

hello.c

  1. #include <stdio.h>  
  2. void hello(const char* name){  
  3.     printf(“hello %s! \n”,name);  
  4. }  

main.c

  1. #include “hello.h”  
  2. int main(){  
  3. hello(“everyone”);  
  4. return 0;  
  5. }  

注意:这个时候,hello.c 是无法通过gcc –o 编译,这个道理非常简单,hello.c 是一个没有main函数的.c程序,因此不够成一个完整的程序,如果使用gcc –o编译并连接它,gcc 将报错。

(ps:gcc -o 与gcc -c 的区别。gcc–o  是将.c源文件编译成为一个可执行的二进制代码,这包括调用作为 GCC 内的一部分真正的 C 编译器( ccl ),以及调用GNU C编译器的输出中实际可执行代码的外部 GNU 汇编器和连接器工具。g -c是使用GNU汇编器将源文件转化为目标代码之后就结束,在这种情况下连接器并没有被执行,所以输出的目标文件不会包含作为 Linux 程序在被装载和执行时所必须的包含信息,但它可以在以后被连接到一个程序)

其实,我们的问题就是,如何让main.c中能使用hello这个函数。这时候我们有三种思路:

1、通过编译多个源文件,直接将目标代码合成一个.o 文件。

2、 通过创建静态链接libmyhello.a ,使得 main 函数调用 hello 函数时可调用静态链接库。

3、 通过创建动态链接库libmyhello.so ,使得 main 函数调用 hello 函数时可调用静态链接库


下面分别进行演示。

1.通过编译多个源文件,直接将目标代码合成一个.o 文件.首先利用gcc -c指令将hello.c和main.c编译生成hello.o和main.o文件,再用gcc -o指令将hello.o和main.o文件生成一个可执行文件hello。具体如下图所示:

Linux生成静态库_linux生成静态库


2.通过创建静态链接库libmyhello.a ,使得main函数调用hello函数时可调用静态链接库。

下面我们先来看看如何创建静态库,以及使用它。Linux静态库命名规范,必须是“lib[your_library_name].a”lib为前缀,中间

是静态库名,扩展名为.a例如:我们将创建的静态库名为 myhello ,静态库文件名就是 libmyhello.a。在创建和使用静态库时,

需要注意这点。Linux创建静态库分为两步:

第一步:将代码文件编译成目标文件。即将hello.c文件编译成hello.o文件,使用指令是:gcc -c hello.c

第二步:利用ar工具将目标文件hello.o打包成静态库文件.a(注意命名规则,我的静态库文件名为:libmyhello.a)

具体如下图所示:Linux生成静态库_linux生成静态库

现在我们已经生成了静态库文件libmyhello.a了,下面就是怎么使用它。Linux下使用静态库,只需要在编译的时候,指定静态库的

搜索路径(-L选项)、指定静态库名(不需要lib前缀和.a后缀,-l选项)。

指令:

 gcc -o hello main.c -L/Users/wangxuewei/Desktop/静态链接 -lmyhello

指令可以这么解释:利益gcc -o指令,将main.c编译成可执行文件hello。其中main.c函数中要使用的函数,存储在静态链接库

libmyhello.a 。”-L/Users/wangxuewei/Desktop/静态链接”是该静态库文件所在地址,”-lmyhello”表示的是要使用的静态库文

件的名字,看起来怪怪的哈,因为它不需要制定前缀lib和后缀.a,所以就变成了myhello,-l则是指令标示符号。

[ps:关于gcc指令中的-l和-L参数问题。-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so(.o),很容易看出,把库文件名的头lib和尾.so/.o去掉就是库名了。放在/lib/usr/lib/usr/local/lib里的库直接用-l参数就能链接了,但如果库文件没放在这三个目录里,而是放在其他目录里,这时我们只用-l参数的话,链接还是会出错,出错信息大概是:“/usr/bin/ld: cannot find -lxxx”,也就是链接程序ld在那3个目录里找不到libxxx.so,这时另外一个参数-L就派上用场了,比如常用的X11的库,它在/usr/X11R6/lib目录下,我们编译时就要用-L/usr/X11R6/lib -lX11参数,-L参数跟着的是库文件所在的目录名。再比如我们把libtest.so放在/aaa/bbb/ccc目录下,那链接参数就是-L/aaa/bbb/ccc -ltest


进一步可以删除静态函数libmyhello.a,然后运行hello函数,看看其是否真的链接到了目标函数.

Linux生成静态库_linux生成静态库



3、 通过创建动态链接库libmyhello.so ,使得 main 函数调用 hello 函数时可调用静态链接库

linux动态库的命名规则

动态链接库的名字形式为 libxxx.so,前缀是lib,后缀名为“.so”。

l  针对于实际库文件,每个共享库都有个特殊的名字“soname”。在程序启动后,程序通过这个名字来告诉动态加载器该载入哪个共享库。

l  在文件系统中,soname仅是一个链接到实际动态库的链接。对于动态库而言,每个库实际上都有另一个名字给编译器来用。它是一个指向实际库镜像文件的链接文件(lib+soname+.so)。

创建动态库(.so)可以分为两步:

第一步:生成目标文件,此时要加编译器选项-fPIC。[ps:-fPIC是创建与地质无关的编译程序,是为了能够在多个应用程序间共享]

  1. gcc -fPIC -c hello.c  

第二步:生成动态库,此时要加链接器选项-shared。[ps:-shared是指定生成动态链接库]

  1. gcc -shared -o libmyhello.so hello.o  

以上两步也可以写成一条指令:

  1. gcc -shared -fPCI -o libmyhello.so hello.c  

运行该指令后会生成一个libmyhello.so文件,如下图:

Linux生成静态库_linux生成静态库

使用动态链接库

引用动态链接库,和静态库一样,在编译时指定动态链接库就好

  1. gcc main.c -L. -lmyhello  

-L.  代表动态库在当前路径下;-l后面跟的是动态链接库的名字(
与静态一样,可以舍去前缀lib和后缀.so

执行该指令后,会生成一个a.out的可执行文件,可以执行下看看:

Linux生成静态库_linux生成静态库
可以看到,是可以执行的!!但是,在网上看,很多博客说这样是不可以的,因为:库文件在连接(静态库和动态库)和运行(仅限于使用动态库的程序)时被使用,其搜索路径是在系统中进行设置的。一般Linux系统把/lib /usr/lib(也可能是/usr/local/lib)三个目录作为默认的库搜索路径,所以使用这两个目录中的库时不需要进行设置路径即可直接使用。对于处于默认库搜索路径之外的库,需要将库的位置添加到搜索路径之中。但是,我电脑中,当动态库与执行程序在同一目录下时,也可以运行,可能是因为我用的mac吧,暂时没弄清楚。。。不过可以确定,当将动态库libmyhello.so移动到/usr/local/lib时,a.out仍可正常运行。

Linux生成静态库_linux生成静态库

更一般的,对于处于默认路径之外的库,如何让系统找到它呢?一般有两种方法:

1.将动态库复制到/lib 或 /usr/lib 或 /usr/local/lib中。就像我上面做的一样,将libmyhello.so复制到/usr/local/lib中,这是系统是可以找到的。

2.如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下:

2.1 编辑/etc/ld.so.conf文件,加入库文件所在目录的路径

2.2 运行ldconfig ,该命令会重建/etc/ld.so.cache文件

[ps:第二种方法我没有试,因为mac系统里好像跟这个不太一样,还在研究中。。。具体可以参考下面几篇文章,解释的比较详细]

参考:

http://www.cppblog.com/deane/archive/2012/08/01/165216.html

http://www.cnblogs.com/skynet/p/3372855.html

http://blog.163.com/hitperson@126/blog/static/130245975201151552938133

http://www.aichengxu.com/view/10712254

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/187604.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 最短路径模板+解析——(FLoyd算法)[通俗易懂]

    最短路径模板+解析——(FLoyd算法)[通俗易懂]对于无权的图来说:若从一顶点到另一顶点存在着一条路径,则称该路径长度为该路径上所经过的边的数目,它等于该路径上的顶点数减1。由于从一顶点到另一顶点可能存在着多条路径,每条路径上所经过的边数可能不同,即路径长度不同,我们把路径长度最短(即经过的边数最少)的那条路径叫做最短路径,其路径长度叫做最短路径长度或最短距离。对于带权的图来说:考虑路径上各边上的权值,则通常把…

  • JS获取除法取整[通俗易懂]

    JS获取除法取整[通俗易懂]保留整数部分:parseInt(17/2)向上取整:Math.ceil(17/2)向下取整:Math.floor(17/2)四舍五入:Math.round(17/2)取余数:17%2

  • redisson和jedis区别_redisson和redis区别

    redisson和jedis区别_redisson和redis区别Redis可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为String(字符串)、List(列表)、Set(集合)、Hash(散列)和Zset(有序集合)。redis与spring的整合一般分为spring-data-redis整合和jedis整合,先看看两者的区别1、引用的依赖不同:spring-data-redis使用的依赖如下: <dependency> <groupId>org.springframework..

  • nslookup命令解析域名_nslookup是什么意思

    nslookup命令解析域名_nslookup是什么意思1、作用:查询DNS的记录,查看域名解析是否正常,在网络故障的时候用来诊断网络问题。2、命令解析命令格式:nslookupdomain[dns-server]示例:nslookupwww.163.com第一部分服务器:本机DNS服务器信息。192.168.3.1是我当前计算机的DNS服务器,由于是内网服务器名称无法获取第二部分非权威应答:Non-authoritativeanswer,除非实际存储DNSServer中获得域名解析回答的,都称为非权威应答。也就.

    2022年10月19日
  • MySQL数据库备份的几种方式

    MySQL数据库备份的几种方式MySQL备份的几种方式最近一直想写点博客,但是不知道写什么,感觉自己最近的知识没有什么增加,今天想到了一篇可以写的博客。以前试过根据data文件夹备份MySQL,但是从来没有成功过,前几天帮助朋友还原MySQL,终于成功的将备份的data文件夹还原成功了。MySQL数据库算是常用的数据库中最好使用的数据库了,对于备份的操作也不例外。所以今天分享一下MySQL数据库的备份的几种方式。方

  • 怎样使用 App Studio 高速定制你自己的 Universal Windows App

    怎样使用 App Studio 高速定制你自己的 Universal Windows App

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号