【问题标题】:CMake: undefined symbol when linking an executable with an OBJECT target which linked to a Shared LibraryCMake:将可执行文件与链接到共享库的 OBJECT 目标链接时未定义的符号
【发布时间】:2021-12-26 16:34:25
【问题描述】:

总而言之,我有一个对象目标 (a_object),它是链接到共享库 (base) 的 PUBLIC。对象目标编译得很好,但是当我将该对象目标链接到可执行文件 (main) 时,在构建该可执行文件时,base 库中的函数出现未定义符号错误。

更多详情:

项目树

src
+---base
|       CMakeLists.txt
|       parser_helper.cpp
|       parser_helper.hpp
|
\---module
        a.cpp
        a.hpp
        CMakeLists.txt
        main.cpp

源文件:

base/parser_helper.hpp
#include <istream>
#include <string>

namespace base {
  class line : public std::string {
   public:
    friend auto operator>>(std::istream& is, line& line) -> std::istream&;
  };
}   // namespace base
base/parser_helper.hpp
#include "base/parser_helper.hpp"

namespace {
  using base::line;
}   // namespace

auto base::operator>>(std::istream& is, line& line) -> std::istream& {
  return std::getline(is, line);
}
base/CMakeLists.txt
add_library(base SHARED parser_helper.cpp parser_helper.hpp)
target_compile_options(base PRIVATE ...)
target_compile_features(base PRIVATE ...)
target_include_directories(base PRIVATE ...)
module/a.hpp
#include <istream>

namespace longlp {
  void f(std::istream& input_stream);
  ...
}   // namespace longlp
module/a.cpp
#include "module/a.hpp"

#include <algorithm>
#include <iterator>

#include "base/parser_helper.hpp"

namespace {
  using base::line;
}   // namespace

namespace longlp {
  void f(std::istream& input_stream) {
    std::for_each(std::istream_iterator<line>(input_stream),
                  std::istream_iterator<line>(),
                  [](const line& line) {
                    // ...
                  });
  }
}   // namespace longlp
module/main.cpp
#include <sstream>
#include "module/a.hpp"

int main() {
  std::stringstream input("123\n123");
  longlp::f(input);

  return 0;
}
module/CMakeLists.txt
add_library(a_object OBJECT)
target_sources(a_object PRIVATE a.cpp a.hpp)
target_compile_options(a_object PRIVATE ...)
target_compile_features(a_object PRIVATE ...)
target_include_directories(a_object PRIVATE ...)
target_link_libraries(a_object PUBLIC base)

add_executable(main)
target_sources(main PRIVATE main.cpp)
target_compile_options(main PRIVATE ...)
target_compile_features(main PRIVATE ...)
target_include_directories(main PRIVATE ...)
target_link_libraries(main PRIVATE a_object)

构建main时的错误日志

[build] lld-link: error: undefined symbol: class std::basic_istream<char, struct std::char_traits<char>> & __cdecl base::operator>>(class std::basic_istream<char, struct std::char_traits<char>> &, class base::line &)
[build] >>> referenced by C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\iterator:290
[build] >>>               src/module/CMakeFiles/a_object.dir/a.cpp.obj:(private: void __cdecl std::istream_iterator<class base::line, char, struct std::char_traits<char>, __int64>::_Getval(void))

单独构建a_object 时没有出错。从Cmake documentation on linking Object target,我认为只需将a_object 链接到main 就足够了,我错过了什么吗?

【问题讨论】:

  • 您使用的是哪个编译器/构建系统?如果它是带有默认编译器的 Visual Studio,那么对于类和运算符,您肯定会在 parse_helper.hpp 中缺少 __dllspec(dllimport)/_dllspec(dllexport)... 但是我怀疑您使用的是 Visual Studio 默认编译工具,因为这会导致 base.lib 没有被创建,因为没有导出的符号......顺便说一句:有没有特定的理由不使用 std::istream&amp; operator&gt;&gt;(std::istream&amp; is, line&amp; line); 并在这里使用拖尾返回类型?恕我直言,这只会使代码更长更难阅读而没有任何好处。

标签: c++ cmake undefined-reference undefined-symbol


【解决方案1】:

将文件直接写入add_library 而不是target_sources 可能会起作用。 另外,编写一个全局 CMakeLists.txt 文件并将所有内容链接到那里。

【讨论】:

    猜你喜欢
    • 2021-06-16
    • 2023-03-15
    • 1970-01-01
    • 2015-05-28
    • 1970-01-01
    • 1970-01-01
    • 2019-12-29
    • 2015-09-05
    • 2019-02-12
    相关资源
    最近更新 更多