【问题标题】:Why "undefined reference" when the variable is defined and the library is linked?为什么在定义变量并链接库时出现“未定义的引用”?
【发布时间】:2012-04-06 09:55:34
【问题描述】:

我们有一些应用程序链接到我们自己的几个库。我最近添加了一个链接到这些库的新应用程序,它可以在 Windows 上成功编译。

但是,在 Linux 上,我看到一个静态变量的“未定义引用”错误,这当然意味着该变量没有定义。错误发生在库中,但仅在链接到新应用程序时才会发生(现有应用程序仍然可以正常链接)。

如您所见,编译器说kAppVersion 未定义。实际上它是在Version.cpp 中定义的,并且common 是链接的(在CMakeLists.txt 中指定)。我们认为这可能与target_link_libraries 排序有关,但将common 移动到base(发生错误的位置)之前似乎没有任何效果。此外,在其他CMakeLists.txt(例如协同作用)中,排序似乎无关紧要,因为此应用程序编译成功。这个类似的问题似乎暗示订购很重要,但我对此没有任何成功:

问题:library is linked but reference is undefined

我唯一的想法是 synergyd.cppCDaemonApp.cpp 可能有问题——但我看不到任何明显的在 Linux 上编译但在 Windows 上编译的东西。

Scanning dependencies of target synergyd
[ 90%] Building CXX object src/cmd/synergyd/CMakeFiles/synergyd.dir/synergyd.o
Linking CXX executable ../../../../../bin/debug/synergyd
../../../../../lib/debug/libarch.a(CArch.o): In function `~XExitApp':
/srv/buildbot/synergy/1.4-linux32/build/src/lib/arch/../synergy/XSynergy.h:114: undefined reference to `vtable for XExitApp'
../../../../../lib/debug/libarch.a(CArch.o): In function `CArchAppUtil::exitApp(int)':
/srv/buildbot/synergy/1.4-linux32/build/src/lib/arch/CArchAppUtil.h:31: undefined reference to `XExitApp::XExitApp(int)'
/srv/buildbot/synergy/1.4-linux32/build/src/lib/arch/CArchAppUtil.h:31: undefined reference to `typeinfo for XExitApp'
../../../../../lib/debug/libarch.a(CArchAppUtilUnix.o): In function `CArchAppUtilUnix::parseArg(int const&, char const* const*, int&)':
/srv/buildbot/synergy/1.4-linux32/build/src/lib/arch/CArchAppUtilUnix.cpp:32: undefined reference to `CApp::isArg(int, int, char const* const*, char const*, char const*, int)'
/srv/buildbot/synergy/1.4-linux32/build/src/lib/arch/CArchAppUtilUnix.cpp:37: undefined reference to `CApp::isArg(int, int, char const* const*, char const*, char const*, int)'
../../../../../lib/debug/libbase.a(CLog.o): In function `CLog::insert(ILogOutputter*, bool)':
/srv/buildbot/synergy/1.4-linux32/build/src/lib/base/CLog.cpp:213: undefined reference to `kAppVersion'
collect2: ld returned 1 exit status
make[2]: *** [../../bin/debug/synergyd] Error 1
make[1]: *** [src/cmd/synergyd/CMakeFiles/synergyd.dir/all] Error 2
make: *** [all] Error 2

完整代码可从our repository浏览。

【问题讨论】:

    标签: c++ compiler-errors cmake


    【解决方案1】:

    简而言之真正的问题: archsynergy 之间的循环库依赖关系。此外,base 实际上没有链接到 common 库(在 CMakeLists.txt 中为 base)。

    有趣的是,这是由库的 CMakeLists.txt 文件中的配置问题引起的。这与我添加的新 synergyd 应用程序的 CMakeLists.txt 无关。

    问题是我没有将这些库相互链接,新的调用被添加到其他库中的类。但是,现在循环链接似乎存在问题。

    例如,我可以添加...

    if (UNIX)
        target_link_libraries(arch synergy)
    endif()
    

    ... 到 arch 库中的 CMakeLists.txt,因为 arch 现在调用了 synergy 库中的某些内容。但这是无效的,因为synergy 已经调用了arch 中的某些内容。

    显然这在 Windows 上无关紧要。

    我不太确定是什么原因导致这种情况开始发生,因为以前编译过的所有旧代码都可以正常编译,并且在其他应用程序中仍然可以正常编译。我怀疑很可能与最近从 CArch 中删除样板有关,而不是 CDaemonApp 正在做的事情(或者甚至可能两者兼而有之)。

    更新

    以防万一有人关心 ;-) -- 我认为这与 archsynergy 之间糟糕的循环库依赖关系之间的关系有关,再加上 CDaemonApp.cpp 不包括在内的事实CApp.h -- 表示它被包含在其他位置,导致奇怪的未定义引用错误。

    为了妥善解决这个问题,我删除了循环依赖,这似乎是问题的核心。

    更新 2

    代码现在完全编译了,哇!

    我仍然看到最后一个错误(这个问题的主题):

    [ 90%] Building CXX object src/cmd/synergyd/CMakeFiles/synergyd.dir/synergyd.o
    Linking CXX executable ../../../../../bin/debug/synergyd
    ../../../../../lib/debug/libbase.a(CLog.o): In function `CLog::insert(ILogOutputter*, bool)':
    /home/nick/Projects/synergy/branches/1.4/src/lib/base/CLog.cpp:213: undefined reference to `kAppVersion'
    collect2: ld returned 1 exit status
    make[2]: *** [../../bin/debug/synergyd] Error 1
    make[1]: *** [src/cmd/synergyd/CMakeFiles/synergyd.dir/all] Error 2
    make: *** [all] Error 2
    

    这仅仅是由于base 库没有链接到common 库引起的。将以下代码添加到 base 的 CMakeLists.txt 文件中修复了此问题:

    if (UNIX)
        target_link_libraries(base common)
    endif()
    

    仍然不确定为什么会发生这种情况,很高兴它已修复。

    更新 3

    这是提交:r1354

    【讨论】:

      【解决方案2】:

      首先,链接的顺序很重要,至少在 g++ 中是这样。如果A使用来自B的符号,那么B应该在A之后提及:g++ ... -lA -lB

      我还看到了undefined reference to vtable for XExitApp。此错误意味着您在XExitApp 中有一个未定义的虚函数。如果您不想定义该函数,请通过添加 = 0 使其成为纯虚拟函数

      【讨论】:

      • 我知道会有关于订购的评论,这就是为什么我在这个问题上花了这么多时间 - 正如你所见,在 base 之前订购 common 并不能解决问题。
      • 链接顺序很重要,除非使用 ld 的 --no-as-needed 选项链接库。
      • 我并不是说链接的顺序无关紧要——请阅读我所说的。我已经尝试更改顺序,但并没有解决问题。在这种情况下,问题不一定是由链接顺序引起的(除非 cmake 以某种方式更改它)。
      • @nbolton,你解决了我说的“未定义的 vtable 引用”吗?
      • 我正在查看您的存储库,搜索了getWhat,但在任何地方都找不到它的实现(对于XExitApp 类)。首先解决它(通过实现它,或添加= 0),也许其他一些也会消失。
      【解决方案3】:

      我注意到的唯一一件事是您在/synergyd/CMakeLists.txtset(inc... 部分中缺少“../../lib/synergy”。这是否与我只能猜测的问题有关。

      您遇到的所有链接错误似乎都是由于链接器没有找到它正在寻找的符号。造成这种情况的常见原因是相关的 .o 文件不存在、未包含在构建中或编译不正确。

      我将首先清理,更改 CMakeList.txt 文件以尽可能匹配已知的工作版本,并在所有编译器/警告打开的情况下重建所有内容。如果这不起作用(相同的错误或不同的错误),我会更仔细地研究什么起作用和不起作用。您说 Windows 构建有效,但 Linux 构建无效。两者之间有什么区别,哪些可以解释这个问题。类似的项目也可以正确构建:这两个项目之间有什么区别。

      【讨论】:

      • 我认为这行不正确 --> 你缺少 "../../lib/synergy" 另外,谢谢,但我理解链接器错误,我意识到 可能 是原因......但正如你所看到的,解决方案并不明显(可能是为什么你也无法解决它)。
      • 请查看我的答案以获得实际解决方案。还是谢谢。
      猜你喜欢
      • 2022-12-07
      • 1970-01-01
      • 2014-06-21
      • 2019-02-25
      • 2012-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-15
      相关资源
      最近更新 更多