gcc链接选项 链接静态库和动态库

链接库

链接指定的库有两种方式

  • -llibrary
  • -l library

如链接LuaJIT库,可以用-lluajit-5.1,此时gcc会在库路径中查找libluajit-5.1.so或者libluajit-5.1.a。 也可以用-l llibluajit-5.1.a,第二种只能用在POXIS上,推荐使用第一种方式。而且第二种方式只会在特定的目录进行搜索,会发生找不到库的情况。

通过-llibrary链接库时,可能既有静态库如libluajit-5.1.a,也有动态库如libluajit-5.1.so,这是链接器会优先链接动态库。

指定库路径

如果需要的库不在系统的库搜索路径下,就需要通过-L指定库的搜索路径。 如lua解释器安装时会把libluajit-5.1.a,和libluajit-5.1.so等放在/usr/local/lib下,而gcc进行链接时默认不会在这个路径下搜索库,导致链接失败。通过-L/usr/local/lib指定库路径就可以解决这个问题。

1
2
3
4
5
~$ gcc main.c -lluajit-5.1             
/usr/bin/ld: 找不到 -lluajit-5.1
collect2: error: ld returned 1 exit status

~$ gcc main.c -L/usr/local/lib -lluajit-5.1

指定运行时库搜索路径

有时通过-L指定库路径可以正常链接,运行程序时却因为找不到库报错

1
2
3
4
5
6
7
8
~ $ ./a.out 
./a.out: error while loading shared libraries: libluajit-5.1.so.2: cannot open shared object file: No such file or directory
~ $ ldd ./a.out 
	linux-vdso.so.1 =>  (0x00007ffc1638e000)
	libluajit-5.1.so.2 => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4c23d48000)
	/lib64/ld-linux-x86-64.so.2 (0x000055713bf16000)

使用ldd命令可以看到运行时找不到libluajit-5.1.so.2,无法运行,对此可以通过-Wl,-rpath指定运行时库的搜索路径

1
2
3
4
5
6
7
8
9
10
11
12
13
kenan@kenan-desktop ~ $ gcc test.c -I/usr/local/include/luajit-2.1 -Wl,-rpath=/usr/local/lib/ -lluajit-5.1
kenan@kenan-desktop ~ $ ./a.out 
Hello, Lua!
~ $ 
~ $ ldd ./a.out 
	linux-vdso.so.1 =>  (0x00007ffd6c5d7000)
	libluajit-5.1.so.2 => /usr/local/lib/libluajit-5.1.so.2 (0x00007f5ea238c000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5ea1fa5000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5ea1c9b000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5ea1a97000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5ea1881000)
	/lib64/ld-linux-x86-64.so.2 (0x0000565491551000)

再使用ldd命令查看,libluajit-5.1.so.2在/sur/local/lib下。

使用静态链接

对于运行时找不到动态库的问题,除了通过-Wl,-rpath指定路径外,还可以通过静态链接库的方式来解决。实际生产环境中通常只在一台机器上编译二进制程序,再将二进制程序分发到线上运行环境。程序需要的库可能实际线上环境中根本没有,也需要将库静态链接。

静态链接库有下面几种方式。

只保留静态库

如安装luajit后,在/usr/local/lib下既有静态库,也有动态库。链接时优先链接动态库。如果将动态库删除,只保留静态库,这时链接器就会链接静态库.

通过-Wl,-Bstatic对指定的库使用静态链接

gcc会对-Wl,-Bstatic 后面的库使用静态链接。对-Wl,-Bdynamic后面跟的库使用动态链接。 如果需要对指定的库使用静态链接,其他的库使用默认的动态链接,可以这样用

1
gcc test  -Wl,-Bstatic -lluajit-5.1 -Wl,-Bdynamic -lxxx -lxxx

这样gcc会链接libluajit-5.1.a,而对其他库使用动态链接。

使用 -static 避免动态链接

gcc编译时使用-static参数,会阻止使用动态链接的方式。与之前两个方法不同,-static参数会导致gcc对所有的库使用静态链接,一般不推荐使用这种方式。

1
2
3
~ $ gcc test.c -I/usr/local/include/luajit-2.1 -Wl,-rpath=/usr/local/lib/ -L/usr/local/lib -lluajit-5.1 -ldl -lm -static
~ $ ldd ./a.out 
	不是动态可执行文件

对程序使用ldd命令提示不是动态可执行文件

没有使用-static时ldd可以看到程序需要的动态库,以及库的路径。

1
2
3
4
5
6
7
8
9
~ $ gcc test.c -I/usr/local/include/luajit-2.1 -Wl,-rpath=/usr/local/lib/ -L/usr/local/lib -lluajit-5.1 -ldl -lm     
~ $ ldd ./a.out 
	linux-vdso.so.1 =>  (0x00007ffd057f1000)
	libluajit-5.1.so.2 => /usr/local/lib/libluajit-5.1.so.2 (0x00007f1e72a48000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1e7267f000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1e72375000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f1e72171000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1e71f5b000)
	/lib64/ld-linux-x86-64.so.2 (0x000055875c7a0000)

使用 -static-libxxx对某些系统库进行静态链接

gcc本身提供了参数可以只对libgcc,libstdc++等库进行静态链接 主要有下面这些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-static-libgcc

-static-libasan

-static-libtsan

-static-liblsan

-static-libubsan

-static-libmpx

-static-libmpxwrappers

-static-libstdc++

更详细的介绍可以参见官方文档