【问题标题】:Linking static libraries in CMake Project - Undefined Reference在 CMake 项目中链接静态库 - 未定义的参考
【发布时间】:2020-07-24 12:41:49
【问题描述】:

我正在尝试将大型主文件中的一些类重构为单独的头文件和 cpp 文件,并且在链接时遇到未定义的引用错误。

我有一个看起来像这样的项目:

├── CMakeLists.txt
├── data
│   └── ICING BE SI Data.csv
├── gcc
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── lib
│   ├── Makefile
│   ├── src
│   └── tmp
├── include
│   ├── Interpolator.hpp
│   ├── InverseCDFProcess.hpp
│   └── XYParser.hpp
├── lib
│   ├── CMakeLists.txt
│   ├── Interpolator.cpp
│   ├── InverseCDFProcess.cpp
│   └── XYParser.cpp
└── test
    └── test_icing.cpp

该项目有几个类InterpolatorInverseCDFProcess,我最近将它们从主可执行文件test_icing.cpp 移到了它们自己的.cpp.hpp 文件中,它们位于libinclude 目录。

由于类确实相互依赖(InverseCDFProcess 需要 Interpolator,而后者又需要 XYParser.cpp 中的函数),我决定将它们构建为静态库,然后在编译时链接到主可执行文件时间。

它们是这样建造的:

add_library(xyparser STATIC XYParser.cpp)
add_library(interpolator STATIC Interpolator.cpp)
add_library(inversecdf STATIC InverseCDFProcess.cpp)

然后我以正常方式将这些库链接到我的可执行文件中:

include_directories(include)
link_directories(lib)
link_directories(include) # Do I need this?

add_executable(test_icing test/test_icing.cpp)

# ... some code adding an external library which works fine

target_link_libraries(test_icing inversecdf interpolator xyparser ${external_library_name})

这会产生这个链接命令:

/usr/bin/c++ CMakeFiles/test_icing.dir/test/test_icing.cpp.o -o test_icing -L/mnt/c/Users/foo/projects/chase-icing/lib -L/mnt/c/Users/foo/projects/chase-icing/include -L/mnt/c/Users/foo/projects/chas e-icing/gcc/src/imtc-build/lib -Wl,-rpath,/mnt/c/Users/foo/projects/chase-icing/lib:/mnt/c/Users/foo/projects/chase-icing/include:/mnt/c/Users/foo/projects/chase-icing/gcc/src/imtc-build/lib lib/libinversecdf .a lib/libinterpolator.a lib/libxyparser.a -limt

此时编译停止并报错:

/mnt/c/Users/foo/projects/chase-icing/test/test_icing.cpp:(.text+0xcca): undefined reference to `Interpolator<double>::Interpolator(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > co
nst&)'
/mnt/c/Users/foo/projects/chase-icing/test/test_icing.cpp:(.text+0xd4c): undefined reference to `Interpolator<double>::set_bounds(std::pair<double, double> const&)'
/mnt/c/Users/foo/projects/chase-icing/test/test_icing.cpp:(.text+0xd99): undefined reference to `InverseCDFProcess<double>::InverseCDFProcess(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<
char> > const&)'
/mnt/c/Users/foo/projects/chase-icing/test/test_icing.cpp:(.text+0xdd9): undefined reference to `InverseCDFProcess<double>::generate()'

库是构建STATIC 还是SHARED 都没有关系。未定义的引用错误仍然发生。

我的问题是:我的类定义或实现中是否遗漏了一些 extern 或类似的东西?为什么这种相对简单的重构会导致未定义的引用?我的链接目录不正确吗?它应该引用构建目录吗?

感谢任何帮助。

【问题讨论】:

  • 在哪里定义了`Interpolator::Interpolator(...)`?
  • 那么是头文件还是cpp文件中缺少的函数呢?看来你可能没有意识到all template code should be placed in header files.
  • @john 不一定。您可以在 cpp 中使用显式模板实例化
  • @tuket 是的,确实如此,但这是一个罕见的用例,我尽量不要将新手与它混淆。它包含在我提供的链接中。重要的一点是模板代码不像常规代码。让每个人第一次发现都会感到惊讶的事情。
  • @ijustlovemath 'header only libraries' 是经常使用的短语。

标签: c++ class c++11 cmake


【解决方案1】:

继续为未来的人回答这个问题:

解决方案嵌入在错误消息中:

/mnt/c/Users/foo/projects/chase-icing/test/test_icing.cpp:(.text+0xdd9): undefined reference to `InverseCDFProcess&lt;double&gt;::generate()'

此错误表明类是模板化的。问题是我将这些模板的实现放在.cpp 文件中,如下所示:

├── include
│   ├── Interpolator.hpp
│   ├── InverseCDFProcess.hpp
│   └── XYParser.hpp
├── lib
│   ├── CMakeLists.txt
│   ├── Interpolator.cpp
│   ├── InverseCDFProcess.cpp
│   └── XYParser.cpp

模板需要在头文件中包含完整的实现。所以,好消息是我一开始就不需要这些库。只需#include "Interpolator.hpp 等,它应该可以按预期工作!

模板需要实现的原因见此处:Why can templates only be implemented in the header file?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-11
    • 1970-01-01
    • 1970-01-01
    • 2010-10-19
    • 2017-05-14
    • 2014-04-28
    • 2020-06-07
    • 2019-03-09
    相关资源
    最近更新 更多