GCC/G++选项 -Wl,-Bstatic和-Wl,-Bdynamic

发布时间:2024年01月04日

参考 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>)

文章来源:https://blog.csdn.net/wwwtovvv/article/details/135389787
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。