简体   繁体   中英

CMake: undefined symbol when linking an executable with an OBJECT target which linked to a Shared Library

To be summarized, I have an Object target ( a_object ) which is PUBLIC linked to a Shared Library ( base ). The Object target is compiled fine, however when I link that Object target to an executable ( main ), I got undefined symbol error from a function in base library when building that executable.

For more details:

Project tree

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

Sources files:

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)

Error log when building 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))

I got no error when building a_object individually. From Cmake documentation on linking Object target , I think it is enough to just linking the a_object to main , am I missing something?

Writing the files straight into the add_library instead of the target_sources might work. Also, write a global CMakeLists.txt file and link everything there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM