CMake:未定义的引用

Posted

技术标签:

【中文标题】CMake:未定义的引用【英文标题】:CMake: undefined reference to 【发布时间】:2016-06-23 23:13:03 【问题描述】:

我使用 CMake 3.5.2。尝试构建我的 C++ 代码时,出现以下错误:

[100%] Linking CXX executable SomeExecutable
CMakeFiles/SomeExecutable.dir/Common/src/FunctionOne.cpp.o: In function `FunctionOne::FunctionOne(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double, double, unsigned int, bool)':
FunctionOne.cpp:(.text+0x490): undefined reference to `Helper::initLevel(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)'

程序在 myLib.so 中找不到 Helper::initLevel()。我该如何解决?

CMakeLists.txt:(为简洁而缩短)

cmake_minimum_required(VERSION 3.0)
project(ProjectName)

add_definitions(-std=c++11)
add_definitions(-Wall)
add_definitions(-O2)

link_directories(/usr/local/lib)    

add_executable(SomeExecutable SomeExecutable.cpp $FunctionOne $FunctionTwo)
target_link_libraries(SomeExecutable -pthread -lboost_thread $Boost_LIBRARIES myLib armadillo)

文件结构(为简洁起见):

├── bin
├── CMakeCache.txt
├── cmake_install.cmake
├── CMakeLists.txt
├── Common
│   ├── include
│   │   ├── dataContainer.h
│   │   ├── FunctionOne.h
│   │   ├── FunctionTwo.h
│   └── src
│       ├── FunctionOne.cpp
│       └── FunctionTwo.cpp
├── SomeExecutable.cpp
├── myLib
│   ├── example.cpp
│   ├── include
│   │   ├── Config.h
│   │   ├── Helper.h
│   ├── libmyLib.so

更新:

myLib/include/Config.h:

Namespace Helper 
[...]
    Level* initLevel(const std::string& jsonLvlPath, bool twiceSpatPts =        false);
[..]

更新 2:

kepj@laptop:~/ProjectName$ make VERBOSE=1
/usr/bin/cmake -E cmake_link_script CMakeFiles/SomeExecutable.dir/link.txt --verbose=1
/usr/bin/c++      CMakeFiles/SomeExecutable.dir/SomeExecutable.cpp.o CMakeFiles/SomeExecutable.dir/Common/src/FunctionOne.cpp.o CMakeFiles/SomeExecutable.dir/Common/src/FunctionTwo.cpp.o SomeExecutable  -L/usr/local/lib -rdynamic -pthread -lboost_thread -lboost_system -lboost_filesystem -lmyLib -lsymbolicc++ -lmatio -larmadillo -Wl,-rpath,/usr/local/lib 
CMakeFiles/SomeExecutable.dir/Common/src/FunctionTwo.cpp.o: In function `FunctionTwo::FunctionTwo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double, double, unsigned int, bool)':
FunctionTwo.cpp:(.text+0x490): undefined reference to `Helper::initLevel(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)'
collect2: error: ld returned 1 exit status
CMakeFiles/SomeExecutable.dir/build.make:174: recipe for target 'SomeExecutable' failed
make[2]: *** [SomeExecutable] Error 1
make[2]: Leaving directory '/home/kepj/ProjectName'
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/SomeExecutable.dir/all' failed
make[1]: *** [CMakeFiles/SomeExecutable.dir/all] Error 2
make[1]: Leaving directory '/home/kepj/ProjectName'
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

【问题讨论】:

那么Helper::initLevel 位于哪个文件中?它是什么样子的? 我的猜测是有一个 Helper.cpp 你忘记包含在 CMake 中,但如果没有更多数据就无法得出结论 initLevel 在 Config.h 中声明,但它在哪里定义?您编译的源代码中似乎缺少它,或者定义具有不同的签名。 @KarstenKoop 在 libmyLib.so 中,随源码一起分发。 请分享你运行时看到的make VERBOSE=1 【参考方案1】:

所以从技术上讲,关于这个问题的信息仍然不足以肯定地回答这个问题,但我将分享我将如何调试这个问题,只知道问题中的内容,并解释沿途的每一步。

确保您链接到正确的myLib.so

这个解释性很好,是我对这个问题根源的最佳猜测。

相关编译器标志:-L/usr/local/lib -lmyLib

当试图找到您在编译命令中使用-l 参数指定的库时,链接器会执行一系列步骤: 1. 它查看传递给-l 的参数是绝对路径(到库的整个路径,即在*nix 计算机上以/ 开头,在Windows 上以驱动器号开头)还是只是一个名称。如果它是绝对路径,那么它知道它在哪里。在这种情况下,它只是一个名称,因此请继续执行第 2 步。 2. 下一个要查看的地方是-L 参数中指定的路径。在这种情况下,唯一的-L 参数是/usr/local/lib,所以它看起来在那里。对于这种特定情况,这可能是也可能不是。查看您的文件系统以查看文件/usr/local/lib/libmyLib.so 是否存在,如果存在,请确保该版本是最近的版本。 3. 现在搜索configured linker paths。对每个路径使用与第 2 步相同的步骤。

这是我的猜测,因为您的链接器参数中没有引用您的 myLib 文件夹,但您声称它在该文件夹中,所以我认为它使用的是过时的 myLib.so

确保.so.a 文件实际上具有未定义的符号

在 linux 上,你可以list the symbols defined in a .so file。确保解析为 undefined 的符号在那里。

如果它们不存在,可能的原因如下:

    您没有使用所有 C++ 源文件 (.cpp) 来创建您的库。 定义和声明不匹配:
      定义函数前忘记输入namespace Helper 你拼错了函数名 参数/返回类型不匹配 对于成员函数,您忘记在函数名称前包含MyClass::

ABI 不匹配

(感谢 cmets 中的 n.m 指出这一点)

由于 C++ 标准库有多种实现(和版本),您可能会遇到 ABI 不匹配

这意味着myLib 编译时使用的标准库与您尝试编译可执行文件的标准库不兼容。例如,当您在 linux 上使用 libstdc++ 编译 myLib,然后转到 mac 并尝试编译您的可执行文件,其中标准库是 libc++,您出错。为什么?任何东西的签名,例如std::string 是不一样的。它们是完全不同的类,在链接时会导致签名不匹配。

【讨论】:

您忘记了此错误的最可能原因:C++ ABI mismatch(如果您看到 __cxx11 yadda yadda,您可以合理地确定它是 ABI)。 是的,让我补充一下

以上是关于CMake:未定义的引用的主要内容,如果未能解决你的问题,请参考以下文章

Cmake:对包含方法的未定义引用

使用CMAKE生成makefile后未定义的引用

使用 CMake 使用 Network 构建 Qt 项目会导致未定义的引用

CMAKE未定义引用'cv :: fastFree(void *)错误的OpenCV Android实现

Cmake 链接问题:未定义对 QPushButton 的引用

将 armadillo/blas/lapack 与 cmake 链接(未定义对 `dgemv_' 的引用)