参考 https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
gcc使用-Wl传递连接器参数,ld使用-Bdynamic强制连接动态库,-Bstatic强制连接静态库。所以部分静态,部分动态连接这么写:
gcc ... -Wl,-Bstatic -l<your-static-lib> -Wl,-Bdynamic -l<your-dynamic-lib> ...
举个例子,你想静态连接libA.a同时动态连接libB.so,(先保证你的连接路径-L里面能找到对应的静态或者动态库),这么写:
gcc ... -Wl,-Bstatic -lA -Wl,-Bdynamic -lB ...
这里需要注意,强制静态或者动态连接标记之后的链接库都将按照前面最近的一个标记进行链接,所以如果后面出现了一个libC,没有指定连接标记,那么libC将会被动态连接:
gcc ... -Wl,-Bstatic -lA -Wl,-Bdynamic -lB ... -lC
如果参数里面没指定强制的连接方式标记,那么gcc将按照默认的优先级去链接,优先动态链接,所以如果你这么写,且同时存在libC.so和libC.a那么libC将被动态链接:
gcc ... -lC
由于-B连接标记会改变默认连接方式,所以在Makefile里面如果有人这么干:
LIBS += -Wl,-Bstatic -lC
那么他后面的LIBS+=的库就都只能以静态方式连接了,有时候这是不行的,因为没有静态库,所以会有人这么应对:
LIBS += -Wl,-Bdynamic -lD
这样就改回来了。但是这种胡乱改的行为是非常不好的,比较好的行为应该这样:
LIBS += -l<auto-link-lib>
STATIC_LIBS += -l<static-lib>
DYN_LIBS += -l<dynamic-lib>
LDFLAGS := ${LIBS} -Wl,-Bstatic ${STATIC_LIBS} -Wl,-Bdynamic ${DYN_LIBS}
这样当你不关心怎么连接的时候用LIBS,当你想静态连接的时候用STATIC_LIBS,当你想动态连接的时候用DYN_LIBS。
看到一篇关于libco的博文,里面提到了一个由于全静态链接导致的bug。全静态链接?以前没有接触过这个概念,特意到网上搜了下,原来是一个程序将其依赖的所有动态库都替换成对应静态库,即使是libc.so,libm.so,libstdc++.so这种系统级别的动态库。全静态链接出来的可执行程序,不依赖任何动态库,拷贝到任何一台机器,只需要操作系统,这个程序就可以run起来。
这种全静态链接的方式,肯定有好有坏。
那全静态链接如何优雅的实现呢?gcc为我们提供了(-static)、(-Wl,-Bstatic)、(-Wl,-Bdynamic),这么几个选项。
第一种用法:使用-static选项,将全部动态库都用静态库替换。
这里有个基于boost库的程序,我们使用普通动态链接的方式编译出来,看看可执行程序的依赖关系。
?
由上图可见,可执行程序依赖于libboost_thread.so.1.72.0、libpthread.so.0、libstdc++.so.6、libc.so.6等等动态库。我们再用-static编译这个程序,再看看可执行程序的依赖关系。
?
由上图可见,加入-static选项以后,链接器将动态库全部换成了静态库。
第二种用法:使用-Wl,-Bstatic,-Wl,-Bdynamic选项,将部分动态库设置为静态链接。
gcc使用-Wl将参数传递给连接器。链接器使用-Bdynamic强制连接动态库,-Bstatic强制连接静态库。所以部分静态,部分动态连接这么写:
gcc -Wl,-Bstatic -l<static-lib> -Wl,-Bdynamic -l<dynamic-lib>
我们还是使用上面的boost.cpp作为例子,本次编译我们将libboost_thread.so.1.72.0用作静态编译,其他系统动态库,任然以动态库的方式进行连接。
?
?由上图可见,libboost_thread.so.1.72.0已经是静态链接,而其他系统库,任然是动态链接。
参考1:在Linux下,如何强制让GCC静态链接? - 知乎
参考2:动态链接和静态链接 - 简书
Xlinker后面跟的参数第一个是空格,而Wl后面跟的第一个字符是","
对于传递“-assert definitions”命令给ld来说,Xlinker要一下子传递两个参数需要写两次“Xlinker”,比如-Xlinker -assert -Xlinker defintions而不能一下子写成-Xlinker "-assert definitions"因为链接器会认为这是一个参数,而不是两个参数。如果此时你用的是GNU的linker,通常更简便的做法就是用option=value的方式,比如-Xlinker -Map -Xlinker output.mp可以简写成-Xlinker -Map=output.map。而对于Wl来说,因为他的参数分割是用“,”这样可以不用像Xlinker一样一下子写多个,只需要写多个逗号即可,就拿这个例子来说,可以写成-Wl,-Map,output.map当然了,如果你用的是GNU的linker你也可以-Wl,-Map=output.map。
所以对于rpath来说使用Xlinker可以写成-Xlinker -rpath -Xlinker <dir>(-Xlinker -rpath=<dir>),对于Wl来说可以写成-Wl,rpath,<dir>(-Wl,rpath=<dir>)