静态库
静态库是一种将一组目标文件打包在一起的文件;
用于在编译时链接到应用程序中;
静态库的文件的拓展名一般为.a
(Linux/Unix中)或是.lib
(windows中);
静态库的特点通常为以下几种:
-
编译时链接
静态库在编译时被链接到应用程序的可执行文件中;
链接器将静态库中的代码和数据复制到最终的可执行文件中;
-
独立性
静态库在编译时被嵌入到应用程序中,因此生成的可执行文件不依赖于外部的库文件;
使得可执行文件在运行时更加独立不需要额外的库文件;
-
性能
静态库在编译时已经被链接到可执行文件中,故运行时不需要动态加载库文件,因此启动速度较快,运行时性能较好;
-
文件大小
静态库的代码和数据被复制在可执行文件中,因此生成的可执行文件通常较大;
静态库的创建与使用
假设需要创建一个提供加减乘除方法的库;
-
头文件(
mymath.h
)#pragma once extern int myerrno; int add(int x, int y); int sub(int x, int y); int mul(int x, int y); int div(int x, int y);
-
源文件(
mymath.c
)#include "mymath.h" int myerrno = 0; int add(int x, int y) { return x + y; } int sub(int x, int y) { return x - y; }; int mul(int x, int y) { return x * y; }; int div(int x, int y) { if (y == 0) { myerrno = 1; return -1; } return x / y; };
-
编译源文件为目标文件
使用
gcc
编译源文件mymath.c
为目标文件mymath.o
;gcc -c mymath.c -o mymath.o
-
创建静态库
使用
ar
命令将目标文件mymath.o
打包成静态库libmymath.a
;ar rcs libmymath.a mymath.o
单个目标文件也可以打包成静态库;
-
静态库的使用
创建一个测试程序
main.c
并使用静态库libmymath.a
;#include <stdio.h> #include "mymath.h" int main() { int a = 10, b = 5; printf("Add: %d + %d = %d\n", a, b, add(a, b)); printf("Sub: %d - %d = %d\n", a, b, sub(a, b)); printf("Mul: %d * %d = %d\n", a, b, mul(a, b)); printf("Div: %d / %d = %d\n", a, b, div(a, b)); return 0; }
-
编译和链接测试程序
gcc -o main main.c -L. -lmymath
其中
-L .
表示头文件在当前目录中,-lmymath
表示名为mymath
的库(libmymath.a
需要去掉其中的lib
前缀与后缀.a
才为库名); -
运行测试程序
$ ./main Add: 10 + 5 = 15 Sub: 10 - 5 = 5 Mul: 10 * 5 = 50 Div: 10 / 5 = 2
头文件为一个库的声明(类似于说明书);
库的使用必须提供其头文件;
利用Makefile创建静态库并使用
lib=libmymath.a
$(lib):mymath.o
# ar -rc libmymath.a mymath.o
# ar为归档工具 rc表示 replace and creat
ar -rc $@ $^
mymath.o:mymath.c
gcc -c $^
.PHONY:clean
clean:
rm -rf *.a *.o lib
.PHONY:output
output:
mkdir -p lib/include
mkdir -p lib/mymathlib
cp *.h lib/include
cp *.a lib/mymathlib
-
lib=libmymath.a
定义了一个变量
lib
,其值为libmymath.a
;这个变量代表了要构建的静态库名称;
-
$(lib):mymath.o
这个规则指定了构建静态库
libmymath.a
的方法;其中
$(lib)
表示一个变量的引用;它告诉
make
程序使用之前定义的lib
变量的值;变量在
makefile
中用于存储会被多次使用的数据以方便修改和维护;例如在规则:
$(lib):mymath.o ar -rc $@ $^
这里的
$(lib)
将会被替换为libmymath.a
,故实际执行的规则为:libmymath.a: mymath.o ar -rc $@ $^
这表示了
libmymath.a
依赖于mymath.o
; -
ar -rc $@ $^
这是个构建静态库的命令;
其中
ar
是一个用于创建和修改归档文件(静态库)的工具;-rc
选项表示如果归档文件不存在则创建;如果存在则替换里面的模块;
$@
表示当前规则的目标,这里代指libmymath.a
;$^
代表所有的依赖项,这里指mymath.o
;-
ar rcs $@ $^
这与
-rc
选项相同;唯一不同的是:
-
ar -rc
这里的
-r
选项表示将文件替换到静态库中(如果静态库中已经存在同名文件则替换;如果不存在则添加);-c
选项表示如果指定的库文件不存在则创建静态库文件,一般情况下-c
选项是默认行为; -
ar rcs
这里的
r
与c
与-rc
相同,不赘述;s
选项作用是在创建或者更新库文件之后自动创建或者更新静态库的索引;这个索引是用于提高链接(使用改库的程序)的速度;
-
-
-
.PHONY:clean
这里的
.PHONY
表示clean
是一个伪目标;用于删除所有构建过程中生成的文件;
包括静态库文件,对象文件和
lib
目录;.PHONY:clean clean: rm -rf *.a *.o lib
-
.PHONY:output
表示
output
是一个伪目标,用于创建一个存放构建结果的目录结构,并将头文件和静态库文件复制到相应的位置;.PHONY: output output: mkdir -p lib/include mkdir -p lib/mymathlib cp *.h lib/include cp *.a lib/mymathlib
其中
mkdir -p lib/include
和mkdir -p lib/mymathlib
分别创建lib/include
和lib/mymathlib
目录,用于存放头文件和静态库文件;cp *.h lib/include
把所有头文件复制到lib/include
目录下;cp *.a lib/mymathlib
把所有静态库文件复制到lib/mymathlib
目录下;
假设将已经构建好的静态库打包发布给用户进行使用需要将make output
后所生成的lib
文件夹发送给用户;
假设存在一个test
目录为用户目录,并且lib
文件夹已经发送给用户;
$ mkdir test ; cp -r lib test ; cp main.c test ; ls test
lib main.c
其中用户的源文件为main.c
:
#include <stdio.h>
#include "mymath.h"
int main() {
int a = 10, b = 5;
printf("Add: %d + %d = %d\n", a, b, add(a, b));
printf("Sub: %d - %d = %d\n", a, b, sub(a, b));
printf("Mul: %d * %d = %d\n", a, b, mul(a, b));
printf("Div: %d / %d = %d\n", a, b, div(a, b));
return 0;
}
直接编译将产生报错,原因为未找到mymath.h
头文件的定义;
$ gcc -o mytest main.c
main.c:3:10: fatal error: mymath.h: No such file or directory
#include "mymath.h"
^~~~~~~~~~
compilation terminated.
原因是找不到头文件mymath.h
的定义;
在编译过程中将首先在默认路径下找头文件;
这两个路径一般为 当前路径 与 /usr/include
等目录;
故在进行编译链接时需要使用:
$ gcc -o mytest main.c -I lib/include/ -L lib/mymathlib/ -lmymath ; ls #ls为显示当前目录下的文件
lib main.c mytest
-
gcc -o mytest main.c
最终生成的可执行文件为
mytest
; -
-I lib/include/
-I
选项为include
的简写;表示该库的头文件在
lib/include/
目录下;若头文件在当前目录下或者是与源文件在同一目录下即可省略
-I
选项; -
-L lib/mymathlib/
-L
选项为link
链接的简写;表示需要链接的库文件在
lib/mymathlib/
目录下;同样类似于标准库的库文件也已经在系统中被安装,若是没有指定目录则会去默认路径(当前路径或是系统安装库文件的目录)中查找;
-
-lmymath
-l
选项同样表示link
;一个文件夹内可能存在多个库文件,需要让链接器知道具体需要链接哪个库(建议不需要加空格);
如果依赖其他库则需要额外的
-l
选项指定其他库;这里表示需要链接
mymath
库(去除前缀lib
与后缀.a
即为库名);如果未使用
-l
指定库文件下进行编译(以当前为例):$ gcc -o mytest main.c -I lib/include/ -L lib/mymathlib/ /tmp/ccelRikz.o: In function `main': main.c:(.text+0x21): undefined reference to `add' main.c:(.text+0x49): undefined reference to `sub' main.c:(.text+0x71): undefined reference to `mul' collect2: error: ld returned 1 exit status # 链接错误
由于一个目录下可能存在多个库;
不指定具体的库文件无法在声明中找到文件对应的定义故无法成功链接;
在使用自己写的库与第三方库时必须使用
-l
选项指定需要链接的哪个库; -
为什么头文件只需要给定所在目录而库文件需要具体指定文件?
原因为头文件已经在源文件中进行声明,在此处为include "mymath.h"
,在编译过程中只需要头文件所在路径即可找到该头文件;
gcc/g++的链接行为
使用ldd
命令可以查看程序的链接情况,但只能看到动态链接的链接情况;
$ ldd ./mytest
linux-vdso.so.1 => (0x00007ffd55bcf000)
libc.so.6 => /lib64/libc.so.6 (0x00007f359458c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f359495a000)
在使用gcc/g++
对某个库进行链接时默认采用的是动态链接;
动态链接的好处包括了减小了可执行文件的大小(因为不需要再文件中包含整个库的代码);
同时当库更新时,程序可以不做更改就直接使用新版本的库;
如果希望进行静态链接,即将库的代码直接包含在可执行文件中可使用-static
选项;
这个选项告诉链接器尽可能使用静态库(.a
文件)而不是动态库(.so
文件);
但对于-static
选项而言,这个选项并不保证所有的库都会进行静态链接;
当某个库只有动态版本可用,那么链接器可能无法满足静态链接的要求;
在某些情况下,如果用户只提供了静态库而没有提供对应的动态库,链接器将不得不使用静态链接.但这也取决于编译时的具体指令和可用的库;
不带路径使用第三方静态库
一般使用第三方库时在使用gcc/g++
进行编译需要带头文件的路径与库文件的路径,如:
$ gcc -o mytest main.c -I lib/include/ -L lib/mymathlib/
-
-I
表示头文件路径 -
-L
表示库文件路径 -
-l
表示具体需要链接的库(使用第三方库时无论如何不可省略)
一般具有两种方法:
-
将第三方库安装至系统中(即将库拷贝至系统默认目录下)
一般情况下在
CentOS7.6
中:-
头文件的默认搜索路径为
/usr/include/
$ sudo cp lib/include/mymath.h /usr/include/ ; ls /usr/include/mymath.h /usr/include/mymath.h
-
库文件的默认搜索路径为
/lib64/
$ sudo cp lib/mymathlib/libmymath.a /lib64/ ; ls /lib64/libmymath.a /lib64/libmymath.a
当再次进行编译链接时即可不指定库的路径直接进行链接(在使用第三方库时必须使用
-l
选项带库名);$ ls ; gcc -o mytest main.c -lmymath ; ls;./mytest main.c mymath.c makefile mymath.h test main.c mymath.c mytest makefile mymath.h test Add: 10 + 5 = 15 Sub: 10 - 5 = 5 Mul: 10 * 5 = 50 Div: 10 / 5 = -1 myerrno = 1
-
优点
简化编译命令,不需要直接指定库的位置;
-
缺点
可能会污染系统环境,尤其是如果有多个版本的库可能会导致版本冲突;
-
-
在默认搜索路径中建立软链接
$ sudo ln -s /home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/lib/include/ /usr/include/myinc $ sudo ln -s /home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/lib/mymathlib/libmymath.a /lib64/libmymath.a $ sudo ls -a /lib64/libmymath.a -l lrwxrwxrwx 1 root root 91 Jun 12 16:23 /lib64/libmymath.a -> /home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/lib/mymathlib/libmymath.a $ sudo ls -a /usr/include/myinc -l lrwxrwxrwx 1 root root 78 Jun 12 16:19 /usr/include/myinc -> /home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/lib/include/
当软链接建好之后在头文件之中即可以
软连接/头文件
的形式进行包含;如
#include "myinc/mymath.h"
;$ ls ; gcc -o mytest main.c -lmymath;ls lib libmymath.a main.c makefile mymath.c mymath.h mymath.o test lib libmymath.a main.c makefile mymath.c mymath.h mymath.o mytest test $ ./mytest Add: 10 + 5 = 15 Sub: 10 - 5 = 5 Mul: 10 * 5 = 50 Div: 10 / 5 = -1 myerrno = 1
-
优点
避免了直接复制文件可能带来的污染问题同时简化了编译命令;
-
缺点
需要管理软链接,如果原始库的位置发生变动需要重新更新链接;
-
动态库
动态库(Dynamic Library)又被称为共享库(Shared Library);
是一种包含了可由多个程序同时共享使用的代码和数据的文件;
与静态库不同,动态库在程序运行时被链接而不是在编译时;
这意味着程序在执行过程中会加载动态库并使用其中的代码和数据;
动态库的特点通常为一下几种:
-
运行时链接
动态库在应用程序运行时而非编译时被链接;
这意味着动态库中的代码和数据不会被拷贝至应用程序的可执行文件中而是从外部库文件中动态加载;
-
依赖性
动态库在运行时被加载,因此生成的可执行文件依赖于外部的库文件;
-
性能
由于动态库在运行时加载,其对应的启动时间将会比静态库的时间较慢;
但一旦加载,动态库函数的运行速度与静态库相当;
-
文件大小
动态库不会被整合到每个使用它的可执行文件当中;
因此使用动态库的可执行文件通常比使用静态库的文件要小,同时因为这点其在内存中也可以减少总体消耗;
动态库的创建
在上文的基础上新建四个文件进行测试;
分别为:
-
myprintf.h
#pragma once #include <stdio.h> void Print();
-
myprintf.c
#include "myprintf.h" void Print() { printf("hello myprintf\n"); printf("hello myprintf\n"); printf("hello myprintf\n"); }
-
mylog.h
#pragma once #include <stdio.h> void Log();
-
mylog.c
#pragma once #include <stdio.h> void Log(){ printf("hello mylog\n"); printf("hello mylog\n"); printf("hello mylog\n"); }
当前目录即为:
$ ls
main.c makefile mylog.c mylog.h mymath.c mymath.h myprintf.c myprintf.h
其中mymath.c
与mymath.h
用于生成静态库;
-
编译源文件为目标文件
使用
gcc
编译源文件myprintf.c
与mylog.c
文件为目标文件myprintf.o
与mylog.o
;唯一的区别是在生成动态库的目标文件时需要添加
-fPIC
选项,即 与位置无关码 ;$ gcc -fPIC -c mylog.c ;gcc -fPIC -c myprintf.c
-
将目标文件打包为动态库
使用
gcc/g++
将目标文件myprintf.o
与mylog.o
打包成动态库libmymethod.so
;在打包成动态库时使用
gcc -o
选项进行链接;但在链接过程中需要添加
-shared
选项告诉链接器所生成的并不是可执行文件而是一个动态库(共享库),其中shared
即为共有;$ gcc -shared -o libmymethod.so myprin tf.o mylog.o $ ls libmymethod.so makefile mylog.h mymath.c myprintf.c myprintf.o main.c mylog.c mylog.o mymath.h myprintf.h
单个目标文件也可以打包成动态库;
动态库的使用在下文中进行阐述;
利用Makefile创建动态库
在上文的基础上对Makefile
文件进行修改;
最终目的为生成一个静态库与一个动态库并进行打包;
dy-lib=libmymethod.so
static-lib=libmymath.a
.PHONY:all
all:$(dy-lib) $(static-lib)
$(static-lib):mymath.o
# ar -rc libmymath.a mymath.o
# ar为归档工具 rc表示 replace and creat
ar -rc $@ $^
$(dy-lib):myprintf.o mylog.o
gcc -shared -o $@ $^
myprintf.o:myprintf.c
gcc -fPIC -c $^
mylog.o:mylog.c
gcc -fPIC -c $^
mymath.o:mymath.c
gcc -c $^
.PHONY:clean
clean:
rm -rf *.a *.o *.so mylib
.PHONY:output
output:
mkdir -p mylib/include
mkdir -p mylib/lib
cp *.h mylib/include
cp *.a mylib/lib
cp *.so mylib/lib
-
变量定义
dy-lib=libmymethod.so static-lib=libmymath.a
这里定义了两个变量;
dy-lib
用于存储动态库的名称;static-lib
用于存储静态库的名称; -
伪目标
.PHONY
.PHONY:all clean output
.PHONY
指示给定的目标是"伪目标",这意味着它们不代表文件名;这里定义了三个伪目标:
all
,clean
,和output
;使用伪目标可以防止Make与同名的文件冲突;
-
主目标
all
all:$(dy-lib) $(static-lib)
all
是默认目标,通常是第一个目标;这里它依赖于两个库文件的目标,即$(dy-lib)
和$(static-lib)
;运行
make
或make all
时,这两个库文件将被构建; -
静态库的构建
$(static-lib):mymath.o ar -rc $@ $^
这个规则用于静态库的构建;
其依赖于
mymath.o
目标文件;使用
ar
命令将mymath.o
归档成静态库$(static-lib)
即libmymath.a
; -
动态库的构建
$(dy-lib):myprintf.o mylog.o gcc -shared -o $@ $^
这个规则用于构建动态库;
其依赖于
myprintf.o
与mylog.o
目标文件;使用
gcc
的-shared
选项将这些对象文件链接成动态库$(dy-lib)
即libmymethod.so
; -
目标文件构建
myprintf.o:myprintf.c gcc -fPIC -c $^ mylog.o:mylog.c gcc -fPIC -c $^ mymath.o:mymath.c gcc -c $^
这些规则用于编译
.c
文件使其生成对应的.o
目标文件;对于
myprintf.o
与mylog.o
文件,因为其为动态库做准备需要使用-fPIC
选项来生成与位置无关码; -
清理目标
clean
clean: rm -rf *.a *.o *.so mylib
clean
目标用于删除所有编译生成的文件,包括静态库,动态库,目标文件以及发布后的mylib
目录文件; -
发布
output
output: mkdir -p mylib/include mkdir -p mylib/lib cp *.h mylib/include cp *.a mylib/lib cp *.so mylib/lib
output
目标用于创建发布目录结构并拷贝头文件,动静态库至其对应位置;
动态库的使用
假设将已经构建好的静态库打包发布给用户进行使用需要将make output
后所生成的mylib
文件夹发送给用户;
$ make clean ; make ;make output
rm -rf *.a *.o *.so mylib
gcc -fPIC -c myprintf.c
gcc -fPIC -c mylog.c
gcc -shared -o libmymethod.so myprintf.o mylog.o
gcc -c mymath.c
ar -rc libmymath.a mymath.o
mkdir -p mylib/include
mkdir -p mylib/lib
cp *.h mylib/include
cp *.a mylib/lib
cp *.so mylib/lib
存在一个test
目录为用户目录,并且mylib
文件夹已经发送给用户;
$ mkdir test ; cp -r mylib test ; cp main.c test ; ls test
mylib main.c
其中用户的源文件为main.c
:
#include <stdio.h>
#include "mymath.h"
#include "myprintf.h"
#include "mylog.h"
int main() {
int a = 10, b = 5;
printf("Add: %d + %d = %d\n", a, b, add(a, b));
printf("Sub: %d - %d = %d\n", a, b, sub(a, b));
printf("Mul: %d * %d = %d\n", a, b, mul(a, b));
int n = div(5, 0);
printf("Div: %d / %d = %d\nmyerrno = %d\n", a, b, n,myerrno);
printf("\n");
Printf();
Log();
return 0;
}
使用gcc
对两个库进行链接生成a.out
可执行文件;
$ gcc main.c -I mylib/include/ -L mylib/lib/ -lmymath -lmymethod
$ ls
a.out main.c mylib
当需要链接的文件需要依赖多个库时需要使用多个-l
来指定所使用的库;
若是头文件或者库路径也存在不同位置时则需要使用多个-L
或-I
来确认路径;
直接执行a.out
可执行文件时将发生报错;
$ ./a.out
./a.out: error while loading shared libraries: libmymethod.so: cannot open shared object file: No such file or directory
使用ldd
对该可执行文件观察其链接情况发现虽然使用动态链接但not fount
;
$ ldd a.out
linux-vdso.so.1 => (0x00007ffca2fed000)
libmymethod.so => not found
libc.so.6 => /lib64/libc.so.6 (0x00007f21ba253000)
/lib64/ld-linux-x86-64.so.2 (0x00007f21ba621000)
在使用动态库时存在一个组件为动态链接器(Dynamic Linker),即加载器(Loader);
这个组件主要职责是在程序启动时或者在运行时按需动态加载库(.so
文件)到内存中并处理程序中对库函数的调用;
加载器主要负责:
- 查找程序运行时所需的动态库
- 将这些库加载至内存中
- 接续程序对这些库中函数和变量的引用以确保程序中的调用可以正确定位到苦衷相应的函数或者变量
程序在运行时加载器会根据一系列预设的规则和环境变量来查找动态库;
如果动态库不再这些预设的位置中,程序运行时则可能找不到这些库而导致运行失败;
通常有几种方法可以确保动态链接器能在运行时找到所需的动态库:
-
将动态库放在标准库路径下(如
/usr/lib64/
)$ sudo cp mylib/lib/libmymethod.so /usr/lib64/
使用
ldd
对可执行程序a.out
观察其链接情况时发现已经可以观察到其动态链接的链接情况;$ ldd ./a.out linux-vdso.so.1 => (0x00007ffe7a988000) libmymethod.so => /lib64/libmymethod.so (0x00007ff2e19e5000) libc.so.6 => /lib64/libc.so.6 (0x00007ff2e1617000) /lib64/ld-linux-x86-64.so.2 (0x00007ff2e1be7000)
同时运行可执行程序时将不再报错;
$ ./a.out Add: 10 + 5 = 15 Sub: 10 - 5 = 5 Mul: 10 * 5 = 50 Div: 10 / 5 = -1 myerrno = 1 hello myprintf hello myprintf hello myprintf hello mylog hello mylog hello mylog
-
在标准库中设立软链接
与上文中的静态库的使用相同,将软链接设置到搜索的默认路径中;
$ sudo ln -s /home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/test/mylib/lib/libmymethod.so /lib64/libmymethod.so
使用
ldd
时发现可执行文件a.out
可找到链接情况同时运行不报错;$ ldd a.out linux-vdso.so.1 => (0x00007fff79543000) libmymethod.so => /lib64/libmymethod.so (0x00007f07c92a7000) libc.so.6 => /lib64/libc.so.6 (0x00007f07c8ed9000) /lib64/ld-linux-x86-64.so.2 (0x00007f07c94a9000) $ ./a.out Add: 10 + 5 = 15 Sub: 10 - 5 = 5 Mul: 10 * 5 = 50 Div: 10 / 5 = -1 myerrno = 1 hello myprintf hello myprintf hello myprintf hello mylog hello mylog hello mylog
-
将动态库的路径设置在环境变量
LD_LIBRARY_PATH
中在
Linux
中存在一个环境变量为LD_LIBRARY_PATH
;这个环境变量用来存放用户的动态库;
使用
export
即可将动态库的路径放置在环境变量LD_LIBRARY_PATH
中(针对当前shell
);$ export LD_LIBRARY_PATH=/home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/test/mylib/lib/:$LD_LIBRARY_PATH #此处只需要更新到动态库所在路径即可
若是需要使每次都能够将动态库路径放置在环境变量中应修改配置文件
~/.bashrc
或是~/.profile
,在这两个配置文件中的其中一个添加上述export
命令(上述命令为演示);使用
ldd
观察可执行文件可以查询到链接情况同时运行不报错;$ ldd a.out linux-vdso.so.1 => (0x00007fff641c8000) libmymethod.so => /home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/T0612/test/mylib/lib/libmymethod.so (0x00007f917fe41000) libc.so.6 => /lib64/libc.so.6 (0x00007f917fa73000) /lib64/ld-linux-x86-64.so.2 (0x00007f9180043000) $ ./a.out Add: 10 + 5 = 15 Sub: 10 - 5 = 5 Mul: 10 * 5 = 50 Div: 10 / 5 = -1 myerrno = 1 hello myprintf hello myprintf hello myprintf hello mylog hello mylog hello mylog
当打开一个新的终端时使用
ldd
观察可执行文件情况则再次找不到链接属性;$ ldd ./a.out linux-vdso.so.1 => (0x00007fff572f5000) libmymethod.so => not found libc.so.6 => /lib64/libc.so.6 (0x00007f7dae34c000) /lib64/ld-linux-x86-64.so.2 (0x00007f7dae71a000)
-
在编译时使用
-rpath
选项在编译过程中可以使用
-Wl
选项;-Wl
选项表示在编译命令中传递参数给链接器ld
;同时在使用
-Wl
选项时可以使用-rpath
选项并跟一个路径;表示编译时告诉链接器在运行时在哪个路径下搜索动态库;
即:
gcc -o my_program my_program.c -L/path/to/library -lmylib -Wl,-rpath,/path/to/library
在这个命令中,
-Wl,-rpath,/path/to/library
的意思是将-rpath,/path/to/library
这个参数传递给链接器;-Wl
告诉gcc
,后面跟着的是链接器的参数,-rpath,/path/to/library
是具体的链接器参数,告诉链接器在运行时应该去哪个路径下搜索动态库;同样的在使用
-Wl,-rpath
时只需要跟到动态库所在路径即可;使用该方法编译链接可执行文件时该可执行文件将会把编译时所传递的路径作为默认的动态库链接路径(针对当前可执行文件),是一种长期行为且无关
shell
;只有该可执行文件或者是重新对该可执行文件进行链接并未带
-Wl,-rpath
选项时动态链接器才不会在运行该可执行文件时去指定的路径下寻找;例:
$ gcc main.c -I mylib/include/ -L mylib/lib/ -lmymath -lmymethod -Wl,-rpath,/home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_ library/T0612/test/mylib/lib/
在使用
-Wl,-rpath
选项后使用ldd
查看链接情况发现无异常并且可以直接运行不报错;$ ldd ./a.out linux-vdso.so.1 => (0x00007fff0d5e0000) libmymethod.so => /home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/T0612/test/mylib/lib/libmymethod.so (0x00007ff9253f1000) libc.so.6 => /lib64/libc.so.6 (0x00007ff925023000) /lib64/ld-linux-x86-64.so.2 (0x00007ff9255f3000) $ ./a.out Add: 10 + 5 = 15 Sub: 10 - 5 = 5 Mul: 10 * 5 = 50 Div: 10 / 5 = -1 myerrno = 1 hello myprintf hello myprintf hello myprintf hello mylog hello mylog hello mylog
-
将路径放置在动态链接器配置目录中
在
Linux
当中/etc/ld.so.conf.d
路径为动态链接器配置目录;这里面包括所有默认的动态链接器配置目录;
# su - # cd /etc/ld.so.conf.d/ # ls bind-export-x86_64.conf kernel-3.10.0-1160.108.1.el7.x86_64.conf kernel-3.10.0-957.21.3.el7.x86_64.conf kernel-3.10.0-957.el7.x86_64.conf mysql-x86_64.conf
其中的
.conf
即为配置文件;每个
.conf
文件中都存放了一串路径,路径即为动态链接器将会搜索的路径;# cat mysql-x86_64.conf /usr/lib64/mysql
可将需要的可执行文件所依赖的动态库在该路径下创建并设置;
设置完毕之后执行
ldconfig
使得配置文件重新加载例:
echo "/home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/T0612/test/mylib/lib" > newtest.conf cat newtest.conf /home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/T0612/test/mylib/lib ldconfig
设置好后回到原先路径使用
ldd
观察可执行文件可以查到链接状态且运行不报错;$ ldd a.out linux-vdso.so.1 => (0x00007ffcfe5a8000) libmymethod.so => /home/_XXX/Begin/my_-linux/Pro24/Dynamic_and_static_library/T0612/test/mylib/lib/libmymethod.so (0x00007f2436a00000) libc.so.6 => /lib64/libc.so.6 (0x00007f2436632000) /lib64/ld-linux-x86-64.so.2 (0x00007f2436c02000) $ ./a.out Add: 10 + 5 = 15 Sub: 10 - 5 = 5 Mul: 10 * 5 = 50 Div: 10 / 5 = -1 myerrno = 1 hello myprintf hello myprintf hello myprintf hello mylog hello mylog hello mylog