如何在 cmake 中正确链接库?

Posted

技术标签:

【中文标题】如何在 cmake 中正确链接库?【英文标题】:How to link library correctly in cmake? 【发布时间】:2020-07-07 16:25:34 【问题描述】:

我最近在使用 yaml-cpp 库。我按照“yaml-cpp-config.cmake.in”中的配置文件,内容是

  # - Config file for the yaml-cpp package
  # It defines the following variables
  #  YAML_CPP_INCLUDE_DIR - include directory
  #  YAML_CPP_LIBRARIES    - libraries to link against
   
  # Compute paths
  get_filename_component(YAML_CPP_CMAKE_DIR "$CMAKE_CURRENT_LIST_FILE" PATH)
  set(YAML_CPP_INCLUDE_DIR "@CONFIG_INCLUDE_DIRS@")
   
 # Our library dependencies (contains definitions for IMPORTED targets)
 include("$YAML_CPP_CMAKE_DIR/yaml-cpp-targets.cmake")
 
 # These are IMPORTED targets created by yaml-cpp-targets.cmake
 set(YAML_CPP_LIBRARIES "@EXPORT_TARGETS@")
                                                                                                    
                 

根据第 8 行和第 14 行(或评论部分),我编辑了我的 CMakeLists.txt 和 test.cpp 之类的

  cmake_minimum_required(VERSION 3.5)
  project(yaml_test)
  find_package(yaml-cpp)
  include_directories($YAML_CPP_INCLUDE_DIRS)
   
  add_executable(yaml_test src/test.cpp)
  target_link_libraries(yaml_test $YAML_CPP_LIBRARIES)
                                                                                                
                                                                                                                             

   #include <yaml-cpp/yaml.h>
   
   int main()
    
     YAML::Node node = YAML::LoadFile("test.yaml");
   
     
     return 0;
   

我得到了

CMakeFiles/yaml_test.dir/src/test.cpp.o: In function `main':
test.cpp:(.text+0xf9): undefined reference to `YAML::LoadFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
collect2: error: ld returned 1 exit status
CMakeFiles/yaml_test.dir/build.make:94: recipe for target 'yaml_test' failed
make[2]: *** [yaml_test] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/yaml_test.dir/all' failed
make[1]: *** [CMakeFiles/yaml_test.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

我从undefined reference to YAML::LoadFile找到了解决方案

将我的 CMakeLists.txt 更改为

cmake_minimum_required(VERSION 3.5)
  project(yaml_test)
  find_package(yaml-cpp)
  include_directories($YAMLCPP_INCLUDE_DIRS)
   
  add_executable(yaml_test src/test.cpp)
  target_link_libraries(yaml_test $YAMLCPP_LIBRARIES)

我可以成功构建我的代码。

我的问题是如何直接从 yaml-cpp 包的 CMakeLists.txt 或配置文件中分辨出正确的“include_directories”和“target_link_libraries”?

有人可以帮助我吗?谢谢!

【问题讨论】:

当使用YAMLCPP 变量时,您似乎引用了that answer。但是这个答案不使用find_package(yaml-cpp)。相反,它使用宏pkg_check_modules 来获取有关yaml-cpp 包的信息,并且YAMLCPP 只是简单地传递给该宏(也就是说,您可以传递任何其他前缀,并且该前缀将用于输出变量)。但是您的第二个 sn-p 仍然使用 find_package(yaml-cpp),这与该答案相矛盾并且完全错误。 【参考方案1】:

我的问题是如何直接从 yaml-cpp 包的 CMakeLists.txt 或配置文件中分辨出正确的“include_directories”和“target_link_libraries”?

请务必查看配置文件,该文件由 CMake 实际使用。 例如。 yaml-cpp-config.cmake.in 只是未来yaml-cpp-config.cmake 的一个模板,但您的系统可能有相同包的其他配置文件。

CMake 将配置文件的确切路径存储在 &lt;PackageName&gt;_CONFIG 变量中,因此如果不确定,您可以打印此变量的值:

...
find_package(yaml-cpp)
message(STATUS "Used config file: $yaml-cpp_CONFIG")

重要提示

读取配置文件时,除了顶部的文档之外,检查set 行很有用,该行将值分配给记录的变量,如*_LIBRARY*_LIBRARIES。如果该值为empty,则“config”文件可能损坏,并且很可能无法使用已记录的变量。但是您可以使用 IMPORTED 目标,见下文。

请注意,大多数“配置”文件都提供了 IMPORTED 目标以供其他代码使用。

这种机制优于使用变量*_INCLUDE_DIR*_LIBRARIES。如果找不到有关使用哪个确切 IMPORTED 目标的文档,请查看配置文件中 *_LIBRARIES 变量的值:该变量可能包含 IMPORTED 目标列表,您可以尝试通过 @987654335 在代码中使用它@。

更多详情请查看find_packagedocumentation。

【讨论】:

嗨,齐瓦列夫。谢谢你专业的回答。但我仍然有一个问题。在我听从了你的建议之后。我发现配置文件位于 /usr/local/share/cmake/yaml-cpp。共有四个cmake文件,包括“yaml-cpp-config.cmake”、“yaml-cpp-targets.cmake”、“yaml-cpp-config-version.cmake”和“yaml-cpp-targets-noconfig.cmake” .但在“yaml-cpp-config.cmake”中,与模板配置文件的内容相同。在“yaml-cpp-config-targets.cmake”中,我找不到任何相关的词如“YAML_CPP”或“YAMLCPP”。 抱歉问了这么烦人的问题,这个问题我囤了很久...... 你只需要查看yaml-cpp-config.cmake:只有这个脚本可以包含对用户有用的变量设置。文件 yaml-cpp-targets.cmakeyaml-cpp-targets-noconfig.cmake 由 CMake 生成并且相当复杂,但它们只能定义 IMPORTED 目标。文件yaml-cpp-config-version.cmake 仅用于版本检查。如果文件yaml-cpp-config.cmake 描述了变量YAML_CPP_LIBRARIES,那么这个变量应该可以工作... set(YAML_CPP_LIBRARIES "...") 行是否为变量分配了一个非空值 是的,我在link 中找到了解决方案,而我的 yaml-cp-config.cmake 就像你说的那样。它将空值分配给 YAML_CPP_INCLUDE_DIR 和 YAML_CPP_LIBRARIES set(YAML_CPP_LIBRARIES "") set(YAML_CPP_INCLUDE_DIR "") 但为什么它们是空值?我通过this insturction 构建了这个库。而我做错了什么? "但是为什么它们是空值?" - 这是 yaml-cpp 项目中的错误(?)。在linked answer 中有一个指向错误报告的链接,该链接仍然处于打开状态。

以上是关于如何在 cmake 中正确链接库?的主要内容,如果未能解决你的问题,请参考以下文章

使用 cmake 正确链接库

如何使用cmake生成基于静态库的动态链接库

如何正确地将库与 cmake 链接?

CMAKE将动态库链接到模块,但不显示为链接依赖

如何在 CMake 中链接预编译库?

当我链接动态库而不是静态库时,CMake 有效