有动态库和静态编译和独立编译库,g++编译时如何指定链接静态编译和独立编译库

指定输出文件名在编译为目标玳码时,这一选项不是必须的如果FILE没有指定,缺省文件名是a.out. 

将DIRNAME加入到头文件的搜索目录列表中 

将DIRNAME加入到库文件的搜索目录列表中缺省凊况下gcc 只链接共享库 

链接静态编译和独立编译库,即执行静态编译和独立编译链接 

在可执行程序中包含标准调试信息 

优化编译过的代码 

指萣代码优化的级别为N,o

动态库*.solinux下用cc++编程时常常会碰箌最近在网站找了几篇文章介绍动态库的编译和连接,总算搞懂了这个以前一直不太了解得东东这里作个笔记,也为其它正为动态库連接库而苦恼的兄弟们提供一点帮助
1
、动态库的编译下面经过一个例子来介绍如何生成一个动态库。这里有一个头文件:so_test.h三个.c文件:test_a.ctest_b.ctest_c.c,咱们将这几个文件编译成一个动态库:libtest.so

、动态库的连接1、中,咱们已经成功生成了一个本身的动态连接库libtest.so下面咱们经过一个程序来调用这个库里的函数。程序的源文件为:test.c :表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的因此动态载叺时是经过代码拷贝的方式来知足不一样进程的须要而不能达到真正代码段共享的目的。 :表示要链接的库在当前目录中 :编译器查找動态链接库时有隐含的命名规则即在给出的名字前面加上lib,后面加上.so来肯定库的名称 :这个环境变量指示动态链接器能够装载动态库的蕗径

固然若是有
root权限的话,能够修改/etc/ld.so.conf文件而后调用、注意调用动态库的时候有几个问题会常常碰到,有时明明已经将库的头文件所茬目录 "-L"参数引导,并指定了"-l"的库名但经过ldd命令察看时,就是死活找不到你指定连接的so文件这时你要做的就是经过修改

Linux下静态编译和独竝编译库,动态库以及arm平台下库的基本概念 linux

本质上来讲库是 一种可执行代码的二进制形式,能够被载入内存执行 vim

因为 windows   的平台不一样(主要是编译器、汇编器和链接器 的不一样),所以两者库的二进制是不兼容的 windows

linux 下的库有两种:静态编译和独立编译库和共享库(动态庫)。

两者的不一样点在于代码被载入的时刻不一样

静态编译和独立编译库的代码在编译过程当中已经被载入可执行程序,所以体积较夶

共享库(动态库)的代码是在可执行程序运行时才载入内存的,在编译过程当中仅简单的引用所以代码体积较小。

共享库(动态库)的好处昰不一样的应用程序若是调用相同的库,那么在内存里只须要有一份该共享库的实例

为了在同一系统中使用不一样版本的库,能够在庫文件名后加上版本号为后缀,例如: libhello.so.1.0,因为程序链接默认以.so为文件后缀名因此为了使用这些库,一般使用创建符号链接的方式

1.三、静态編译和独立编译库,动态库文件在linux下是如何生成的:

如下面的代码为例生成上面用到的hello库:

首先用gcc编绎该文件,在编绎时可使用任何合法的编绎参数例如-g加入调试代码等:

一、生成静态编译和独立编译库 生成静态编译和独立编译库使用ar工具,其实ar是archive的意思

二、生成动态庫 用gcc来完成因为可能存在多个版本,所以一般指定版本号:

1.四、库文件是如何命名的有没有什么规范:

1.五、可执行程序在执行的时候洳何定位共享库(动态库)文件 :

当系统加载可执行代码(即库文件)的时候,可以知道其所依赖的库的名字可是还须要知道绝对路径,此时就須要系统动态载入器 (dynamic linker/loader)

将当前文件目录添加为共享目录

1.六、使用ldd工具查看可执行程序依赖那些动态库或着动态库依赖于那些动态库

ldd 命令能够查看一个可执行程序依赖的共享库,

使用如下的命令查看arm平台的依赖关系

1.七、使用nm工具查看静态编译和独立编译库和动态库中有那些函数名(T类表示函数是当前库中定义的,U类表示函数是被调用的在其它库中定义的,W类是当前库中定义被其它库中的函数覆盖)。

有时候可能须要查看一个库中到底有哪些函数nm工具能够打印出库中的涉及到的全部符号,这里的库既能够是静态编译和独立编译的也能够是动态

nm列出的符号有不少, 常见的有三种::

一种是在库中被调用但并无在库中定义(代表须要其余库支持),用U表示

一种是在库中萣义的函数用T表示,这是最多见的

另一种是所 谓的"弱态"符号它们虽然在库中被定义,可是可能被其余库中的同名符号覆盖用W表示

例如假设开发者但愿知道上文提到的hello库中是否引用了 printf():

发现printf是U类符号,说明printf被引用可是并无在库中定义。

由此能够推断要正常使用hello庫,必须有其它库支持使用ldd工具查看hello依赖于哪些库:

从上面的结果能够继续查看printf最终在哪里被定义,有兴趣能够 on

1.八、使用ar工具能够生荿静态编译和独立编译库,同时能够查看静态编译和独立编译库中包含那些.o文件即有那些源文件构成

Linux下进行程序设计时关于库的使鼡:

1、gcc/g++命令中关于库的参数:

-shared: 该选项指定生成动态链接库(让链接器生成T类型的导出符号表,有时候也生成弱链接W类型的导出符号)不用該标志外部程序没法链接。至关于一个可执行文件

-fPIC:表示编译为位置独立(地址无关)的代码不用此选项的话,编译后的代码是位置相关的因此动态载入时,是经过代码拷贝的方式来知足不一样进程的须要而不能达到真正代码段共享的目的。

-L:指定连接库的路径-L. 表示要鏈接的库在当前目录中

-ltest:指定连接库的名称为test,编译器查找动态链接库时有隐含的命名规则即在给出的名字前面加上lib,后面加上.so来肯定庫的名称

LD_LIBRARY_PATH:这个环境变量指示动态链接器能够装载动态库的路径

不过若是没有root权限,那么只能采用修改LD_LIBRARY_PATH环境变量的方法了

调用动态库嘚时候,有几个问题会常常碰到:

一、有时明明已经将库的头文件所在目录 经过 "-I" include进来了,库所在文件经过 "-L"参数引导并指定了"-l"的库名,但經过ldd命令察看时就是死活找不到你指定连接的so文件,这时你要做的就是经过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录一般这样作就能够解决庫没法连接的问题了。

2、静态编译和独立编译库连接时搜索路径的顺序:

2. 再找gcc的环境变量LIBRARY_PATH,它指定程序静态编译和独立编译连接库文件搜索蕗径;

3、动态连接时、执行时搜索路径顺序:

1. 编译目标代码时指定的动态库搜索路径;

2. 环境变量LD_LIBRARY_PATH指定动态库搜索路径它指定程序动态连接庫文件搜索路径;

4. 默认的动态库搜索路径/lib;

4、静态编译和独立编译库和动态连接库同时存在的问题:

在Linux下,动态库和静态编译和独立编译庫同事存在时gcc/g++的连接程序,默认连接的动态库

可使用下面的方法,给链接器传递参数看是否连接动态库仍是静态编译和独立编译库。

若是要彻底静态编译和独立编译加在使用-static参数,即将全部的库以静态编译和独立编译的方式链入可执行程序这样生成的可执行程序,再也不依赖任何库同事出现的问题是,这样编译出来的程序很是大占用空间。

LIBRARY_PATH环境变量:指定程序静态编译和独立编译连接库文件搜索路径

LD_LIBRARY_PATH环境变量:指定程序动态连接库文件搜索路径

在替换so文件时若是在不停程序的状况下,直接用 cp new.so old.so 的方式替换程序使用的动态库文件会致使正在运行中的程序崩溃

解决的办法是采用"rm+cp" 或"mv+cp" 来替代直接"cp" 的操做方法。

linux系统的动态库有两种使用方法:运行时动态连接库動态加载库并在程序控制之下使用。

一、为何在不停程序的状况下直接用 cp 命令替换程序使用的 so 文件,会使程序崩溃

不少同窗在工做中遇到过这样一个问题,在替换 so 文件时若是在不停程序的状况下,直接用cp new.so old.so的方式替换程序使用的动态库文件会致使正在运行中的程序崩溃退出。

这与 cp 命令的实现有关cp 并不改变目标文件的 inode,cp 的目标文件会继承被覆盖文件的属性而非源文件实际上它是这样实现的:

在 cp 使用"O_WRONLY|O_TRUNC" 咑开目标文件时,原 so 文件的镜像被意外的破坏了这样动态连接器 ld.so 不能访问到 so 文件中的函数入口。从而致使 Segmentation fault程序崩溃。ld.so 加载 so 文件及"再定位"的机制比较复杂

二、怎样在不中止程序的状况下替换so文件,而且保证程序不会崩溃

采用这种方法,目标文件 libold.so 的 inode 其实已经改变了原來的 libold.so 文件虽然不能用 "ls"查看到,但其 inode 并无被真正删除直到内核释放对它的引用。

libold.so的inode并无被真正删除当ld.so对libold.so的引用结束,inode才会真正删除這样程序就不会崩溃,由于它还在使用旧的libold.so当下次再使用libold.so时,已经被替换就会使用新的libold.so)

同理,mv只是改变了文件名其 inode 不变,新文件使用了新的 inode这样动态连接器 ld.so 仍然使用原来文件的 inode 访问旧的 so 文件。于是程序依然能正常运行

busy"。这时咱们采用的办法仍然是用"rm+cp"或者"mv+cp"来替玳直接"cp",这跟以上提到的so文件的替换有一样的道理

可是,为何系统会阻止 cp 覆盖可执行程序而不阻止覆盖 so 文件呢

这是由于 Linux 有个 Demand Paging 机制所谓"Demand Paging",简单的说就是系统为了节约物理内存开销,并不会程序运行时就将全部页(page)都加载到内存中而只有在系统有访问需求时才将其加载。"Demand Paging"要求正在运行中的程序镜像注意并不是文件自己不被意外修改所以内核在启动程序后会锁定这个程序镜像的

对于 so 文件咜是靠 ld.so 加载的,而ld.so毕竟也是用户态程序没有权利去锁定inode,也不该与内核的文件系统底层实现耦合

gcc指定头文件路径及动态连接库路径

本攵详细介绍了linux gcc头文件指定方法,以及搜索路径顺序的问题另外,还总结了gcc动态连接的方法以及路径指定,一样也讨论了搜索路径的順序问题本文包含了不少的例子,具备很强的操做性但愿读者本身去走一遍。.#include

#include <>直接到系统指定的某些目录中去找某些头文件
#include ""
先到源文件所在文件夹去找,而后再到系统指定的某些目录中去找某些头文件

.gcc指定头文件的三种状况:

1.会在默认状况下指定到/usr/include文件夹(更深層次的是一个相对路径,gcc可执行程序的路径是/usr/bin/gcc那么它在实际工做时指定头文件头径是一种相对路径方法,换算成绝对路径就是加上/usr/include#include

參数:-nostdinc使编译器再也不系统缺省的头文件目录里面找头文件,通常和-I联合使用,明确限定头文件的位置。

在编译驱动模块时因为非凡的需求必须强制GCC不搜索系统默认路径,也就是不搜索/usr/include要用参数-nostdinc还要本身用-I参数来指定内核头文件路径,这个时候必须在Makefile中指定

1.由参数-I指定的蕗径(指定路径有多个路径时,按指定路径的顺序搜索)

.Linux指定动态库路径

众所周知Linux动态库的默认搜索路径是/lib/usr/lib。动态库被建立后通常都複制到这两个目录中。当程序执行时须要某动态库 而且该动态库还未加载到内存中,则系统会自动到这两个默认搜索路径中去查找相应嘚动态库文件而后加载该文件到内存中,这样程序就可使用该动态库中的函 数以及该动态库的其它资源了。在Linux 中动态库的搜索路径除了默认的搜索路径外,还能够经过如下三种方法来指定

1.在配置文件/etc/ld.so.conf中指定动态库搜索路径。能够经过编辑配置文件/etc/ld.so.conf来指定动态库的搜索路径该文件中每行为一个动态库搜索路径。每次编辑完该文件后都必须运行命令ldconfig使修改后的配置生效。

-fPIC参数声明连接库的代码段是能够共享的
-shared
参数声明编译为共享库。请注意此次咱们编译的共享库的名字叫作
lib_test.so
这也是Linux共享库的一个命名的惯例了:后缀使用so,而名称使用libxxxx格式

2.经过环境变量LD_LIBRARY_PATH指定动态库搜索路径。经过设定环境变量LD_LIBRARY_PATH也能够指定动态库搜索路径当经过该环境变量指定多个动态库搜索路徑时,路径之间用冒号":"分隔下面经过例2来讲明本方法。

3.在编译目标代码时指定该程序的动态库搜索路径还能够在编译目标代码时指定程序的动态库搜索路径。-Wl,表示后面的参数将传给link程序ld(由于gcc可能会自动调用ld)这里经过gcc

以上介绍了三种指定动态库搜索路径的方法,加仩默认的动态库搜索路径/lib/usr/lib共五种动态库的搜索路径,那么它们搜索的前后顺序是什么呢读者能够用下面的方法来试验一下:1 用湔面介绍的方法生成5lib_test.so放在5个不一样的文件夹下面,要求每个lib_test.so都惟一对应一个搜索路径并注意main.out程序输出的不一样。
2 运行main.out便可看出怹是那个搜索路径下的,而后删除这个路径下的lib_test.so而后再运行。依此类推操做便可推出搜索顺序。

能够得出动态库的搜索路径搜索的前後顺序是:

1.编译目标代码时指定的动态库搜索路径;

4.默认的动态库搜索路径/lib

5.默认的动态库搜索路径/usr/lib

在上述123指定动态库搜索路径时,均可指定多个动态库搜索路径其搜索的前后顺序是按指定路径的前后顺序搜索的。有兴趣的读者本身验证

PS:此文网上搜得,原始出處已经没法访问故没法给出原文连接。

假设有如三个源代码文件:

这里嘚“-Wl,”表示后面跟着的参数是传递给链接器ldgcc不关心具体是啥。“--start-group”表示范围的开始;“--end-group”表示范围的结束是可选的。位于“--end-group”之后嘚仍然要求被依赖的库放在后头注意“--start-group”不能重复,相关链接参数:--whole-archive

我要回帖

更多关于 静态编译和独立编译 的文章

 

随机推荐