动态库,静态库,LD_LIBRARY_PATH,LIBRARY_PATH,-L,-l

本文详细介绍了静态库和动态库的生成与使用过程。静态库通过`ar`命令创建,使用时通过`-L`和`-l`选项指定。动态库需使用`-shared`和`-fPIC`选项,运行时可能需要设置`LD_LIBRARY_PATH`或使用`-Wl,-rpath`。在编译阶段,当静态库和动态库同时存在时,编译器会优先选择动态库。" 88692631,8186203,iOS App集成Google AdMob 插页广告指南,"['IOS开发', '广告平台', 'Google AdMob', '移动广告']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库动态库两种。

两者对比:


动态库

静态库

编译时

不连接到目标代码

连接到目标代码

运行时

动态加载

不再需要(已经在目标代码内)


动态库的生成和使用,静态库的生成和使用


假如编写一个数组相关的应用,大概代码框架如下:


/home/xiantao/binarysearchtree/

▾arrdata/一个关于创建数组的函数包括创建数组和打印数组,被test.c使用

arr.c

arr.h

test.c

▾ taolib/自己的一个调试宏的实现,arr.h中会使用这个

maclib.h



这次就把arr.c中的函数当成我们要用的到库,分别生成动态库和静态库来使用。




静态库的生成和使用:



1.编写源程序,上边已经有了,包括arr.c,arr.htest.c这三个文件

下面是arr.h的内容


1 #ifndef_ARR_H_

2 #define_ARR_H_

3 #include"../taolib/maclib.h"

4 voidswap(DataType *a,DataType *b);

5 voidprintarr(DataType arr[],int len);

6 voidcreatearr(DataType arr[],int len);

7 #endif


2.编译,将arr.c编译成arr.o

xiantao@tao:~/binarysearchtree/arrdata$gcc -c arr.c此时生成arr.o

无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序arr.c通过gcc先编译成.o文件。



3..o文件创建静态库(.a


xiantao@tao:~/binarysearchtree/arrdata$ar cr libarr.a arr.o此时生成libarr.a



静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为arr,则静态库文件名就是libarr.a。在创建和使用静态库时,需要注意这点。创建静态库用ar命令。


4步:在test.c中使用静态库


静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从静态库中将公用函数连接到目标文件中。


xiantao@tao:~/binarysearchtree/arrdata$ls注意此时有libarr.a这个静态库,可以没有arr.o

arr.c arr.h libarr.a test.c


编译test.c文件并测试

xiantao@tao:~/binarysearchtree/arrdata$gcc -o test test.c -L. -larr (注意此时时arr,而不是libarr)

以下三种方式都行

xiantao@tao:~/binarysearchtree/arrdata$gcc -o test test.c./libarr.a

xiantao@tao:~/binarysearchtree/arrdata$gcc -o test test.c libarr.a

xiantao@tao:~/binarysearchtree/arrdata$gcc -o test test.c arr.a


xiantao@tao:~/binarysearchtree/arrdata$./test

9 4 0 1 8 19 19 10



-L指示静态库的目录,-l指示静态库的名称,如果把libarr.a移动到/usr/lib/下,就不用加-L选项了,编译器会自动到那个目录下找到。



回头看以下,其实如果文件夹下只有三个文件arr.c,arr.htest.c,然后编译:

xiantao@tao:~/binarysearchtree/arrdata$gcc arr.c test.c

测试也能成功。所以如果使用了静态库,我们只需要一个test.c源文件,在编译阶段加上静态库目录和名称就行;此时是在进行编译的时候,并没有编译arr.c这个文件,而只是在链接阶段使用到了libarr.a这个静态库。(不同于动态库的使用,它是在运行时和arr.so进行绑定的)。假如在运行./test之前删除这个静态库也是能成功运行的。




动态库到生成和使用:


1.源文件准备,与上边一样


2.编译生成arr.o


xiantao@tao:~/binarysearchtree/arrdata$ gcc-fPIC-c arr.c


如果在编译arr.carr.o的时候没有加上-fPIC这个选项,后面编译生成动态库时会出现以下这个错误:

/usr/bin/ld:arr.o: relocation R_X86_64_32 against `.rodata' can not be used whenmaking a shared object; recompile with -fPIC

arr.o: erroradding symbols: Bad value

collect2: error:ld returned 1 exit status


3..o文件创建动态库(.so



xiantao@tao:~/binarysearchtree/arrdata$gcc -shared arr.o -o libarr.so

xiantao@tao:~/binarysearchtree/arrdata$ls

arr.c arr.h arr.o libarr.so test.c


  动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其文件扩展名为.so。例如:我们将创建的动态库名为arr,则动态库文件名就是libarr.so。用gcc来创建动态库。


也可以第二步第三步合起来编译:
xiantao@tao:~/binarysearchtree/arrdata[master]$ gcc -shared -o libarr.so arr.c    (如果不加-fPIC选项会错现下列错误)
/usr/bin/ld: /tmp/cce8PdBO.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/tmp/cce8PdBO.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
正确编译方式:
xiantao@tao:~/binarysearchtree/arrdata[master]$ gcc -shared -fPIC -o libarr.so arr.c


4编译test.c,使用动态库

xiantao@tao:~/binarysearchtree/arrdata$ gcc -o test test.c -L.-larr 和静态库使用一样

xiantao@tao:~/binarysearchtree/arrdata[master]$ gcc  test.c libarr.so -o test(也行)


测试运行:

xiantao@tao:~/binarysearchtree/arrdata$./test

./test: error whileloading shared libraries: libarr.so: cannot open shared object file:No such file or directory

发现提示找不到这个动态库。其实linux上是有个默认到动态库的/usr/lib/lib。如果把刚刚生成到liarr.so移动到/usr/lib/或者/lib/在运行./test成功.

方法二,就是可以设置环境变量的:LD_LIBRARY_PATH只要在这个变量中包含想要使用到动态库的目录就行。

方法三,修改/etc/ld.so.conf文件,把该库所在绝对路径添加到文件末尾,并执行ldconfig刷新

方法四,在第四步编译的时候,使用参数-Wl,-rpath参数告诉编译器,在编译生成test 可执行文件的时候,记住这个库的位置,以致于在运行的时候不需要在设置这个动态库的位置。当然,如果该动态库的位置最后改变的话汇报错,找不到相应的动态库(共享库):

./test: error while loading shared libraries: libarr.so: cannot open shared object file: No such file or directory

           方法四扩展:可以使用ldd命令查看可执行程序(test)所依赖的动态库:

                         xiantao@tao:~/binarysearchtree/arrdata[master]$ ldd test
                         linux-vdso.so.1 =>  (0x00007fff463fc000)
                         libarr.so => /home/xiantao/binarysearchtree/arrdata/libarr.so (0x00007f60e9860000)
                         libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f60e9485000)
                         /lib64/ld-linux-x86-64.so.2 (0x00007f60e9a64000)



假如把在编译生成test可执行文件后,删除libarr.so这个文件,再运行时,会出现什么结果,猜测会提示找不到共享库。试验以下,果然提示如下错误:

./test: error whileloading shared libraries: libarr.so: cannot open shared object file:No such file ordirectory。有点眼熟,其实就是没有设置好动态运行库到路径的提示错误一样,对于程序来说,也就是它找不到动态库到路径。



总结:

使用静态库编译生成的可执行文件大小要大于动态库的(必需的啊,毕竟动态库人家是在运行时动态加载使用的)。静态库使用时,只需要在编译阶段(test)使用,动态库需要再编译阶段(test)和运行(test)阶段都要有相应的设置,而且都要有相应的.so文件。


上边提到过一次:在编译test.c文件时,编译命令在两种情况下式样的,那假如目录下同时有动态库(libarr.so)和静态库(libarr.a)时,到底使用的时谁呢?测试一下:

同时编译两种库,然后运行test

xiantao@tao:~/binarysearchtree/arrdata$gcc -c arr.c

xiantao@tao:~/binarysearchtree/arrdata$ar -cr libarr.a arr.o


xiantao@tao:~/binarysearchtree/arrdata$gcc -fPIC -c arr.c

xiantao@tao:~/binarysearchtree/arrdata$gcc -o test test.c -L. -larr

xiantao@tao:~/binarysearchtree/arrdata$./test

./test: error whileloading shared libraries: libarr.so: cannot open shared object file:No such file or directory

然后再添加LD_LIBRARY_PATH

xiantao@tao:~/binarysearchtree/arrdata$LD_LIBRARY_PATH=./

xiantao@tao:~/binarysearchtree/arrdata$./test成功


说明如果同时有静态库和动态库,编译器是会默认使用动态库的。





同时,还需要注意以下更多的编译选项,-W -D,-rdynamic -Wl,-rpath




以下时引用别人博客

LIBRARY_PATHLD_LIBRARY_PATHLinux下的两个环境变量,二者的含义和作用分别如下:

 

LIBRARY_PATH环境变量用于在程序编译期间查找动态链接库时指定查找共享库的路径,例如,指定gcc编译需要用到的动态链接库的目录。

 

LD_LIBRARY_PATH环境变量用于在程序加载运行期间查找动态链接库时指定除了系统默认路径之外的其他路径,注意,LD_LIBRARY_PATH中指定的路径会在系统默认路径之前进行查找。

 

区别与使用:

开发时,设置LIBRARY_PATH,以便gcc能够找到编译时需要的动态链接库。

发布时,设置LD_LIBRARY_PATH,以便程序加载运行时能够自动找到需要的动态链接库。

GCC里的链接器的选项是-rpath-rpath-link,看了下man ld,大致是这个意思:

 

 



 

GCC链接选项-L-rpath-link-rpath

-L: “链接”的时候,去找的目录,也就是所有的-lFOO选项里的库,都会先从-L指定的目录去找,然后是默认的地方。

-rpath_link (或者-rpath-link):这个也是用于“链接”的时候的,例如你显示指定的需要FOO.so,但是FOO.so本身是需要BAR.so的,后者你并没有指定,而是FOO.so引用到它,这个时候,会先从-rpath-link给的路径里找。
-rpath:“运行”的时候,去找的目录。运行的时候,要找.so文件,会从这个选项里指定的地方去找。对于交叉编译,只有配合--sysroot选项才能起作用。

也就是说,-rpath指定的路径会被记录在生成的可执行程序中,用于运行时。
-rpath-link则只用于链接时。



### 配置 LD_LIBRARY_PATH 环境变量 #### 临时配置 可以通过 `export` 命令为 `LD_LIBRARY_PATH` 赋值来实现临时设置,这种方式仅影响当前 shell 会话。例如: ```bash export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/new/library/directory ``` 此命令将 `/new/library/directory` 添加到现有的 `LD_LIBRARY_PATH` 中[^1]。 如果需要覆盖原有的路径,则可以这样操作: ```bash export LD_LIBRARY_PATH=/another/new/path ``` 这一步骤使得动态链接器在加载共享库时优先查找新指定的路径中的库文件[^2]。 #### 动态链接库的作用范围 `LD_LIBRARY_PATH` 是 Linux 系统中的一个环境变量,其主要功能是指定除默认路径外额外的动态链接库搜索路径。当应用程序启动并尝试加载所需的共享库时,系统会按照 `LD_LIBRARY_PATH` 所定义的顺序依次扫描这些路径[^3]。 值得注意的是,在实际应用中,`LD_LIBRARY_PATH` 的路径会被放在系统默认路径之前进行检查,这意味着自定义路径下的库文件可能被优先选用,即使存在同名的标准库文件[^4]。 #### 持久化配置 为了使更改永久生效,可编辑用户的 Shell 配置文件(如 `.bashrc`, `.zshrc` 或者全局配置文件 `/etc/profile`),加入类似的导出语句。例如对于 Bash 用户来说可以在 `~/.bashrc` 文件末尾追加以下内容: ```bash export LD_LIBRARY_PATH=/path/to/your/libraries:$LD_LIBRARY_PATH ``` 保存修改后执行以下命令让改动立即生效: ```bash source ~/.bashrc ``` 或者如果是针对整个系统的设定,考虑调整 `/etc/ld.so.conf` 文件以及调用 `ldconfig` 更新缓存: ```bash echo "/path/to/your/libraries" | sudo tee -a /etc/ld.so.conf sudo ldconfig ``` 这种方法不仅持久有效而且更加安全可靠,因为它避免了因频繁使用 `LD_LIBRARY_PATH` 变量而可能导致的安全隐患和性能下降问题。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值