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 使用 Network 构建 Qt 项目会导致未定义的引用
CMAKE未定义引用'cv :: fastFree(void *)错误的OpenCV Android实现