首页 > 其他分享 >如何解决库链接出现符号重定义问题

如何解决库链接出现符号重定义问题

时间:2023-09-21 13:34:43浏览次数:46  
标签:定义 符号 静态 链接 动态 可执行程序

下面是一组和GPT的对话,通过逐个排查,我们知道只有一种情况会导致符号重定义。以下假设在 CMake 配置环境。

Q:如果一个静态库a,链接了b,这个时候 c 链接了 ab ,会导致 b 符号重复定义么?

A:
任何库(静态或动态)本身都不链接其他库。他们可能有对其他库的依赖性,但实际上并不包含其他库的代码。

在你给出的情况下,假设你有三个静态库ab和一个可执行目标c

a使用了库b中的一些符号(函数或变量);
目标c链接了库a和库b
在这种情况下,不会出现符号重复定义的问题,因为库a并不会“包含”库b,只是有对它的依赖性。链接器在链接可执行文件c时,它会从库a和库b中提取所需的对象文件,如果同一符号在两个库中都找到了,链接器会选择其中一个(具体选择哪个取决于链接器的行为)。

然而需要注意的是,静态库的链接顺序是重要的。在上面的例子中,由于库a依赖于库b,所以在链接目标c时,应该先链接库a,然后再链接库b,这样链接器才能正确解析库a中对库b的依赖。以下是在CMakeLists.txt中进行链接的示例:

target_link_libraries(c a b)

如果链接命令写成了 target_link_libraries(c b a),那么可能会出现未定义的符号错误。这是因为当链接器处理库b时,它并不知道后面还有对这些符号的引用。

Q: 如果一个静态库a,链接了b,这个时候可执行程序 c 链接了 ab ,会导致 b 符号重复定义么?

A:
在你的情况下,即使静态库a有对静态库b的依赖性,并且可执行程序c同时链接了库a和库b,通常也不会出现符号重复定义的问题。

这是因为静态库并没有真正地“链接”其他静态库。当静态库a被编译时,它可能需要库b中的符号(例如函数或变量),但是库b的代码并没有被合并到库a中,库a只是有对库b的依赖性。

然后,当链接可执行程序c时,链接器将查看c以及所有传递的库(在本例中为ab)所需的所有符号,并从这些库中拉取需要的对象文件来满足这些需求。这意味着每个必要的符号只会被包含一次,而不会被重复包含。

请注意,虽然不会出现符号重复定义的问题,但可以会出现未解析的符号错误。这可能发生在库b先于库a被链接时。由于库a依赖库b,库b应该在库a之后链接,以便链接器能正确解析所有符号。所以正确的链接顺序应该是:

target_link_libraries(c a b)

而不是:

target_link_libraries(c b a)

Q: 如果一个动态库 a 链接了 b,这个时候可执行程序 c 链接了 ab,会导致 b 符号重复定义么?

A:
在你的情况下,动态库(Shared Library)a 依赖于另一个动态库 b,而可执行程序c同时链接了ab,这通常不会导致符号重复定义的问题。

对于动态库来说,它们在编译时并不包含其依赖库的代码。相反,动态库在运行时才解析它们的依赖关系。也就是说,如果动态库a依赖于动态库b,那么当程序加载库a时,操作系统(通过动态链接器)将负责加载库b(如果尚未加载)。

因此,即使可执行程序c同时链接了ab,也只有一份库b的实例被加载到内存中。库ac中引用库b的符号都将解析到这同一份实例,所以不会有符号重复定义的问题。

然而,请注意确保动态库的正确路径,特别是在运行可执行程序c时,库ab必须能够被找到。一般来说,这需要将它们放置在标准库路径下,或者修改环境变量(如LD_LIBRARY_PATH在Linux下,DYLD_LIBRARY_PATH在MacOS下),以包含这些库的路径。

Q: 如果一个动态库a 链接了静态库 b,这个时候可执行程序 c 链接了 ab,会导致 b 符号重复定义么?

A:
在你的情况下,动态库 a 链接了静态库 b ,然后可执行程序 c 又链接了动态库 a 和静态库 b 。这种情况可能会导致符号重复定义。

当一个动态库(如 a )链接一个静态库(如 b )时,静态库 b 中的所有对象代码实际上都会被包含到动态库 a 中。所以当你分别将动态库 a 和静态库 b 链接到可执行文件 c 时,因为动态库 a 已经包含了静态库 b 的所有代码,所以相同的符号实际上被包含了两次,这就可能导致符号重复定义。

解决这个问题的一种方法是只在一个地方链接静态库 b。也就是说,要么只在动态库 a 中链接静态库 b(然后在可执行程序 c 中只链接动态库 a ),要么在动态库 a 和可执行程序 c 中都不链接静态库 b(而是只在链接可执行程序 c 时链接静态库 b )。这样可以确保静态库 b 的代码只被包含一次,从而避免符号重复定义。

--end--

标签:定义,符号,静态,链接,动态,可执行程序
From: https://www.cnblogs.com/math/p/how_to_resolve_multi_define_symbols.html

相关文章

  • VS2017使用自定义头文件
    VS2017使用自定义头文件头文件的使用能大大提高C语言编程效率。公共头文件直接使用类似于#include<stdio.h>即可。下面介绍如何使用自定义的头文件。实例:计算两个整数加和在源文件中添加Add.c源文件在头文件中,添加头文件myhead.h在主函数中,添加头文件声明没有......
  • 自定义初学2——扩展View
    倘若我们需要的功能找不到对应的系统控件了,这时我们就只能自己绘制了。首先定义一个继承View的基类,然后重写View类的一个或多个方法。通常可以被重写的方法有这些:onFinishInflate():这是一个回调方法,当应用从XML布局文件中加载组件时,该方法将被调用。onMeasure(int,int):该方法......
  • 4.3 Java类的定义及定义类时可用的关键字
    类是 Java 中的一种重要的引用数据类型,也是组成Java程序的基本要素,因为所有的Java程序都是基于类的。本节介绍如何定义类。在Java中定义一个类,需要使用 class关键字、一个自定义的类名和一对表示程序体的大括号。完整语法如下:[public][abstract|final]class<class_nam......
  • Map<String, List<DeliverOrderVO>>集合原来还可以这样定义,还能像list集合一样进行分
     而若想要循环,只需要将其value取出将其变为一个map集合,就可以再度循环将想要的值取出。如下图: ......
  • 【Vue】定义配置方法&数据代理
    hello,我是小索奇,精心制作的Vue教程持续更新哈,想要学习&巩固&避坑就一起学习叭~Object定义配置方法代码引出数据代理,先上代码,后加解释<!DOCTYPEhtml><html><head><metacharset="UTF-8"/><title>回顾Object.defineproperty方法</title></head><body&......
  • 自定义读取指定目录下下文件
    publicclassPropertiesUtil{privatestaticfinalStringPath="config/param.properties";/***读取配置文件中key的对应值*/publicstaticStringqueryValue(Stringkey){if(StringUtils.isBlank(key))return"";......
  • C#(6):方法的定义、调用与调试
    复用:自顶向下,逐步求精,面向过程,隐藏复杂的逻辑形参是变量,实参是值。将实参赋给形参。()也是一种构造器当创建类时没有创建构造器,系统会自动创建默认构造器。当创建构造器后,强制类型会使默认构造器失效,此时需要在构造器中赋值。构造器的内存原理:栈分配时由高到低分配地址,直......
  • Hyperledger Fabric 2.5.4开发之“定义功能需求”问题
    说明本文描述了一个不再使用“系统通道”的网络(以前该通道由排序服务引导,并且由排序服务专门控制)。自Fabricv2.3发布以来,在创建通道的过程方法中,使用系统通道现在被视为遗留方案。在通道配置(在通道的最新配置区块中找到)中,可以为每个通道定义功能需求。通道配置包含三个位置,每个位......
  • 宏定义(Release/Debug)
    #defineLOG(x)std::cout<<"Hello"<<std::endl;在项目属性的c++->Preprocesser(预处理)->PreprocesserDefine中添加DR_MODULE,将configuration模式调为release#ifdefDR_MODULE#defineLOG(x) #else#defineLOG(x) std::cout<<"Hello&......
  • 符号计算辅助密码学
    例题BUU-DASbook-happy#以下四行已知c=0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9ee=0x872a335#q+q*p^3=1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586#qp+q*p^2=......