推广 热搜: csgo  vue  angelababy  2023  gps  新车  htc  落地  app  p2p 

Linux的.a、.so和.o文件

   2023-07-31 网络整理佚名880
核心提示:.o,是目标文件,相当于中的.a这个函数库文件中(如果.o结尾的文件),这些的库函数将有优先加载的权利。o文件。c和main.h(见程序1)为该函数库的头文件。o文件。o文件。o文件。在程序3:main.c中,我们包含了静态库的头文件hello.hello自定义的库时,main.o文件开始。a和动态库文件.a和动态库文件.so复制到目录/usr/lib中即可。(1)把库拷贝到/usr/lib和/lib目录下。so)所需的连接和缓存文件.

原文链接

linux.o,.a,.so

.o是目标文件,相当于下面的.obj文件。so是共享库,用于动态链接,相当于下面的dll。 静态连接

静态函数库特点:它实际上是简单的通用目标文件的集合,在程序执行之前添加到目标程序中。 优点:兼容以前的一些程序; 简单描述; 允许程序员在不重新编译代码的情况下链接程序,节省了重新编译代码的时间(这个优点现在还不明显); 开发人员可以对源代码保密; 理论上,使用ELF格式的静态库函数生成的代码可以比使用共享或动态函数库的程序运行速度更快(约1%-5%) 生成:使用ar程序(缩写)。 ar rcs .a f1.o f2.o 是将目标代码f1.o和f2.o添加到函数库文件.a中(如果.a不存在则创建) 用途:使用gcc生成可执行代码时,使用 -l 参数指定要添加的库函数。 您还可以使用 ld 命令的 -l 和 -L 参数。 共享函数库在可执行程序启动时被加载,并且当所有程序重新启动时可以自动加载共享函数库中的函数。 .so文件感觉很复杂,光是命名规则就已经让我头晕了~整理一下,共享库需要:,真实姓名,编译时名字也有说法。 依次说明: : 要求格式:lib+函数库名+.so+版本号信息(但是记住,非常低级的C库函数都不是以lib命名的)。

示例:/usr/lib/.so.3 真实名称:顾名思义,就是真实名称,有主版本号和发布版本号。 但是没有找到例子...编译器编译时需要的函数库名称不包含版本号信息。 例如,上例中的最后一个 .3 可以删除。 位置:共享函数库文件必须放置在特定目录中。 对于开源代码,GNU标准建议所有函数库文件放在/usr/local/lib目录下,建议命令和可执行程序放在/usr/local/bin目录下。 但这只是一种习惯,是可以改变的。 具体位置信息请参考/etc/ld.so.conf中的配置信息。 当然,你也可以修改这个文件,添加一些你自己的特殊路径要求。 创建:在网上找到了两种创建方法,gcc方法和环境。 gcc方法:首先创建一个文件,这个文件会通过gcc –fPIC参数命令添加到共享函数库中,标准格式:gcc - -Wl,-, -o(说实话,这个标准格式看起来好复杂,我找到了一个例子,不过好像和标准格式略有不同: gcc .c .c .c -fPIC - -o .so) 在环境中生成.so文件: 1.选择一个新项目,创建一个c++项目 2. 在项目中选择类型选项,然后填写项目名称PXXX,然后单击完成。

3.编写程序,然后在debug或.so中编译生成.so文件。 如果不需要lib的开头标记,点击菜单的选项,然后点击弹出界面右侧的Build页面,清除该选项的内容。 4、如果是C++程序,注意在接口函数前面添加“C”标记,并在头文件中添加如下标记:#ifdef#“C”{#endif头文件body#ifdef} #endif 如果不加标记,编译后,so中的函数名就不是你写程序时设置的函数名。 点击开发环境左侧工程文件列表中的debug项中的PXXX.o,可以看到so文件中的函数名都是在你设置的函数名后面加上__Fi标记。 比如你设置的函数名是Func(),而so中的函数名是()或者其他名字。 安装:将共享库文件复制到指定的标准目录,然后运行。 如果您没有权限这样做,那么您必须修改环境变量才能实现这些函数库的使用。 方法不再说了,很复杂。

查看:通过ldd可以查看程序使用的共享函数库。 例如 ldd /bin/ls。 要查看 .so 文件,请使用 nm 命令,例如 nm .so。 (注意nm对静态函数库和共享函数库都适用)关于覆盖:如果想用自己的函数覆盖某个库中的部分函数,​​同时保留该库中的其他函数,可以使用 /etc 添加该库被替换(以.o结尾的文件)到/ld.so。 这些库函数将有优先被加载的权利。关于更新:每次添加动态加载的函数库、删除函数库或修改函数库的路径时,都必须重新运行更新缓存文件/etc /ld.so.cache,保存在队列Well- List of link Names中

(Linux下,共享库的加载是通过/lib/ld.so完成的,ld.so加载共享库时,会从ld.so.cache中查找)

我们通常将一些公共函数做成函数库,以供其他程序使用。 函数库有两种类型:静态库和动态库。 静态库会在程序编译时链接到目标代码中,程序运行时不再需要静态库。 动态库在程序编译时并没有连接到目标代码,而是在程序运行时加载,因此动态库在程序运行时仍然需要存在。 本文主要通过实例来说明如何在Linux中创建静态库和动态库并使用它们。 在创建函数库之前,我们首先准备好示例的源程序,并将函数库的源程序编译成.o文件。 第一步:编辑获得的示例程序——hello.h、hello.c、main.c; hello.c(见程序2)是函数库的源程序,其中包含公共函数hello,该函数会在屏幕上显示输出“Hello XXX!”。 hello.h(见程序1)是该函数库的头文件。 main.c(见程序3)是测试库文件的主程序,主程序中调用了公共函数hello。 程序1:hello.h # # void hello(const char *name); #endif // 程序 2: hello.c # void hello(const char *name) { ("Hello %s!\n", name); } 程序 3: main.c # "hello.h" int main() { hello(""); 0; 第二步:将hello.c编译成.o文件; 由 .o 文件创建。

因此,我们首先要通过g cc将源程序hello.c编译成.o文件。 在系统提示符处键入以下命令以获取 hello.o 文件。 # gcc -c hello.c # 我们运行ls命令来查看hello.o文件是否存在。 # ls hello.c hello.h hello.o main.c # 在ls命令的结果中,我们看到了hello.o文件,这一步就完成了。 我们来看看如何创建静态库并使用它。 步骤3:从.o文件创建静态库; 静态库文件名的命名约定以lib为前缀,后跟静态库名,扩展名为.a。 例如:我们要创建的静态库的名称是.a。 创建和使用静态库时请注意这一点。 使用 ar 命令创建静态库。 在系统提示符下键入以下命令将创建静态库文件.a。 # ar -cr .a hello.o # 我们同样运行ls命令查看结果: # ls hello.c hello.h hello.o .a main.c # ls命令的结果中有.a。 第四步:在程序中使用静态库; 静态库制作完成后,如何使用其内部函数呢? 只需要在使用这些公共函数的源程序中包含这些公共函数的原型声明,然后在使用gcc命令生成目标文件时指定静态库名,gcc就会从静态链接这些公共函数库到目标文件。

注意gcc会在静态库名前加上lib前缀,然后在静态库文件名后面追加扩展名.a来查找静态库文件。 在程序3:main.c中,我们包含静态库的头文件hello.h,然后直接调用主程序main中的公共函数hello。 接下来生成目标程序hello,然后运行hello程序看结果。 方法1# gcc -o hello main.c -L。 –,或 gcc main.c -L。 --o hello自定义库,main.c也可以放在-L之间。 和-,但不能放在两者后面,否则会提示未定义,但当是系统库时,如 g++ -o main(-L/usr/lib) - main.cpp 不会make一个错误。 方法2#gcc main.c .a -o hello 或 gcc -o .c .a 方法3:先生成main.o:gcc -c main.c,然后生成可执行文件:gcc -o hello main.o 。 a 或 .o .ao 你好,连接动态库时也可以这样做。

# 。/你好你好 ! # 我们删除静态库文件来尝试一下公共函数hello是否真的连接到了目标文件hello。 # rm .a rm: 文件“.a”? y#./hello 你好! # 程序照常运行,静态库中的公共函数已经链接到目标文件中。 我们继续看看如何在Linux中创建动态库。 我们仍然从 .o 文件开始。 第五步:从.o文件创建动态库文件; 动态库文件名命名规范与静态库文件名命名规范类似,也是在动态库名称中添加前缀lib,但其文件扩展名为.so。 例如:我们要创建的动态库的名称是ello.so。 使用gcc创建动态库。 在系统提示符下输入以下命令,获取动态库文件.so。 # gcc - -fPIC -o .so hello.o (-o是必须的) # 我们还是用ls命令看看动态库文件是否生成了。 # ls hello.c hello.h hello.o .so main.c # 第六步:在程序中使用动态库; 程序中使用动态库和使用静态库是一模一样的,也是这些公共函数的来源 程序中包含这些公共函数的原型声明,然后指定动态库名进行编译当使用 gcc 命令生成目标文件时。

我们首先运行gcc命令生成目标文件,然后运行看结果。 # gcc -o 你好 main.c -L。 - (或者#gcc main.c .so -o hello 不会报错(如果没有.so的话就会报错),但是然后./hello就会提示错误,因为虽然连接时使用了动态库在当前目录下,但运行时是到/usr/lib下找库文件,把.so文件复制到/usr/lib目录下就可以了) # ./hello ./hello:错误 while : .so: 打开共享文件: 没有这样的文件或 # 哦! 错误。 看错误信息,原来是找不到动态库文件.so。 程序运行时会在/usr/lib、/lib等目录中搜索所需的动态库文件。 如果找到则加载动态库,否则会提示类似上面的错误并终止程序。 我们将文件 .so 复制到目录 /usr/lib 并重试。

# mv .so /usr/lib # ./hello 你好! # 成功。 这进一步说明程序运行时需要动态库。 我们回头发现,使用静态库和动态库编译目标程序所用的gcc命令是完全一样的。 当静态库和动态库同名时,gcc命令会使用哪个库文件? 抱着必须追根究底的感觉,我们就来试试吧。 首先删除除.c和.h之外的所有文件,恢复到我们刚刚编辑的示例程序的状态。 # rm -f hello hello.o /usr/lib/.so # ls hello.c hello.h main.c # 创建静态库文件.a和动态库文件.so。

生成动态库时需要使用-fPIC,这样可以生成位置无关的代码,达到共享代码段和数据段的目的# gcc -c -fpic hello.c //编译hello时添加-fpic .c 选项,否则 ' 时不能使用 ; with -fPIC # ar -cr .a hello.o (或 -cvr ) # gcc - -fPIC -o .so hello.o # ls hello.c hello.h 你好。 o .a .so main.c # 通过上面最后一条ls命令,可以发现静态库文件.a和动态库文件.so都已经生成,并且在当前目录下。 然后,我们运行gcc命令,利用函数库生成目标文件hello,并运行程序hello。 # gcc -o 你好 main.c -L。 – (当动态库和静态库同时存在时,优先使用动态库,当然如果直接#gcc main.c .a -o hello,则指定为静态库)# . /hello ./hello: error while : .so: open shar ed file: No such file 或者 # 从程序hello的结果很容易知道,当静态库和动态库同名时,gcc命令会先使用动态库,默认连接/usr/lib和/lib目录下的动态库,并将.so文件复制到/usr/lib目录下。 注:编译参数解析最重要的是GCC命令行的一个选项: - 该选项指定生成动态链接库(让链接器生成T类型的导出符号表,有时还生成弱链接的W - 类型导出符号)。 该标志表示无法连接外部程序。相当于可执行文件

-fPIC 作用于编译阶段,告诉编译器生成与位置无关的代码(-Code)。 那么生成的代码中,没有绝对地址,全部采用相对地址,因此代码可以被加载器加载到内存的任意位置,并且可以正确执行。 这正是共享库所需要的。 当共享库被加载时,它在内存中的位置并不固定。

如果不添加fPIC,则编译后的代码在加载时需要根据加载的位置进行重定位(因为里面的代码不是位置无关的代码),如果被多个应用程序使用,那么它们必须被每个程序使用维护so的代码副本。 (因为每个程序加载so的位置不同,显然这些重定位的代码也不同,当然不能共享)。

如果不使用该选项,则编译后的代码是位置相关的,因此在动态加载时采用代码复制的方式来满足不同进程的需要,无法实现真正​​的代码段共享。 -L。 表示要链接的库在当前目录下; (多个库:在编译命令行中,将使用的静态库文件放在源文件后面。例如: gcc -L/usr/lib .c .a .a .a -o 其中,-L/usr/lib指定库文件的搜索路径,默认情况下,编译器首先在当前目录中搜索指定的库文件,如前面的“方法2#.c .ao hello”) - 当编译器寻找动态链接库,即在给定的名称前面添加lib,在其后面添加.so或.a,以确定库的名称.so或.a。 该环境变量指示动态链接器可以加载动态库的路径。 当然,如果有root权限,可以修改/etc/ld.so.conf文件,然后调用/sbin/来达到同样的目的,但如果没有root权限,就只能使用输出方法。 在调用动态库时,经常会遇到几个问题。 有时候,已经通过“-I”进入了库的头文件所在的目录,而通过“-L”参数引导库所在的文件,而“-l”,但是当通过ldd命令,找不到您为链接指定的so文件。 这时,你需要做的就是通过修改/etc/ld.so.conf文件来指定动态库的目录。 通常这样做可以解决库无法链接的问题。

链接静态库时的搜索路径顺序:

1.ld(GNU)会查找GCC命令中的参数-L

编译过程分为四个阶段:预处理(也称预编译)、编译()、汇编()和连接(link)[链接] 2.找到gcc的环境变量 3.找到默认目录/lib/ usr/lib /usr/local/lib 这是最初写gcc时程序中写的

动态链接和执行期间的搜索路径顺序:

1、编译目标代码时指定的动态库搜索路径 2、环境变量指定的动态库搜索路径 3、配置文件/etc/ld.so.conf中指定的动态库搜索路径 4、默认动态库搜索路径/lib 5.默认动态库搜索路径/usr/lib

关于环境变量: 环境变量:指定程序静态链接库文件搜索路径 环境变量:指定程序动态链接库文件搜索路径

另:由上可知,查找生成的动态库有以下三种方法: (1)将库复制到/usr/lib和/lib目录下。 (2) 将库的路径添加到环境变量中。 例如动态库.so在/home//lib目录下:=:/home//lib (3)修改/etc/ld.so.conf文件,将库所在路径添加到文件末尾(直接写在文件末尾,路径前不要加),并执行(该命令的目的主要是在默认搜索目录(/lib和/usr/lib)和动态库配置文件 /etc/ld.so.conf 列出的目录下,搜索到可共享的动态链接库(格式如上所述,lib*.so*),然后创建该动态链接库所需的连接和缓存文件动态加载器(ld.so)。默认的缓存文件是/etc/ld.so.cache,该文件保存了动态链接库名称的有序列表。)。 这样,添加的目录下的所有库文件都将可见。 附:指定路径如下连接系统静态库,会报错说找不到要连接的库: g++ -o main main.cpp -L /usr/lib .a 必须像这样 g++ -o main main.cpp - L/usr/lib - 是正确的。 在/usr/lib下测试自定义库时, g++ -o main main.cpp -L/usr/lib .a .a .a 会出错,但是这样 g++ -o main main.cpp -L/usr /lib - - - 没错。

 
反对 0举报 0 收藏 0 打赏 0评论 0
 
更多>同类资讯
推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报
Powered By DESTOON