首页 > 其他分享 >GCC/G++选项 -Wl,-Bstatic和-Wl,-Bdynamic

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

时间:2023-06-14 17:23:01浏览次数:41  
标签:GCC ++ Wl Xlinker 静态 Bdynamic 动态 链接

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

参考 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:https://www.zhihu.com/question/22940048/answer/222625910
参考2:https://www.jianshu.com/p/3f1ec6748655

 

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

 

======== End

 

标签:GCC,++,Wl,Xlinker,静态,Bdynamic,动态,链接
From: https://www.cnblogs.com/lsgxeva/p/17480838.html

相关文章

  • C++ OpenMP、TBB库的简单使用
    1.OpenMP的简单使用OpenMP可以用来并行计算for循环,提高程序运行速度。首先要打开OpenMP支持:“配置属性”——“C/C++”——“语言”——“1.OpenMP支持”后选择“是”。1omp_get_num_procs()//获取系统中处理器的个数2omp_set_num_threads(num_count)/......
  • C++ 中的运算符重载
     您可以重定义或重载大部分C++内置的运算符。这样,您就能使用自定义类型的运算符。重载的运算符是带有特殊名称的函数,函数名是由关键字operator和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。https://www.tzffs.com/lnzt15/......
  • C++ 多态
     多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。下面的实例中,基类Shape被派生为两个类https://www.tzffs.com/mnst14/......
  • C++ 模板类编译过程中出现“undefined reference to”问题
    问题描述C++在使用模板(template)类的时候,如果将类的成员函数的声明和实现分别放在.h头文件和.cpp源文件中,编译时会报错undefinedreferencexxx,找不到对应成员函数。起因.h文件中类的声明为://线程池,定义成模板类,为了代码的复用template<typenameT>classThreadPool{......
  • C/C++《程序设计课程设计》[2023-06-14]
    C/C++《程序设计课程设计》[2023-06-14]《程序设计课程设计》指导书程序设计课程设计说明书一、设计任务与要求《程序设计课程设计》是在完成《程序设计基础》课程学习后进行的一门专业实践课程,是培养学生综合运用所学知识解决专业相关问题的重要环节,是对学生实际工作能力的......
  • 配置 Sublime Text4为 C++ 编辑器
    概述涉及以下插件的安装和配置PackageControlTerminusLSPLSP-clangdclang-formatLSP-pyrightLSP-json配置sublime安装PackageControl以进行包管理。Terminus安装Terminus以实现sublimetext4内的terminal。绑定快捷键:[ { "keys":[ "ctrl+shift+t" ], "c......
  • C++面试八股文:C++中,函数的参数应该传值还是传引用?
    C++面试八股文:C++中,函数的参数应该传值还是传引用?某日二师兄参加XXX科技公司的C++工程师开发岗位第8面:面试官:C++中,函数的参数应该传值还是传引用?二师兄:要看参数的用途。如果是出参,必须传引用。如果是入参,主要考虑参数类型的大小,来决定传值还是传引用。面试官:为什么不使用......
  • C++面试八股文:什么是RAII?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第13面:面试官:什么是RAII?二师兄:RAII是ResourceAcquisitionIsInitialization的缩写。翻译成中文是资源获取即初始化。面试官:RAII有什么特点和优势?二师兄:主要的特点是,在对象初始化时获取资源,在对象析构时释放资源。这种技术可以......
  • C++面试八股文:什么是RAII?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第13面:面试官:什么是RAII?二师兄:RAII是ResourceAcquisitionIsInitialization的缩写。翻译成中文是资源获取即初始化。面试官:RAII有什么特点和优势?二师兄:主要的特点是,在对象初始化时获取资源,在对象析构时释放资源。这种技术可以......
  • 《C++》类和对象
    C++面向对象的三大特性:封装、继承、多态封装将属性和行为作为一个整体,表现生活中的事物。对属性和行为加以权限控制。classCompute{ //访问权限public: intAdd(intx,inty) { returnx+y; } intSub(intx,inty) { returnx+y; } intMul(intx,inty) {......