CMake find_package依赖于子项目

时间:2011-11-24 17:03:22

标签: cmake

我有以下目录布局:

main_folder
 + static_lib1
 + executable
  • 'static_lib1'和'executable'都有一个完整的CMakeLists,以便它们可以 独立建造。
  • 'executable'取决于'static_lib1'。它使用find_package()来定位'static_lib1'。
  • main_folder包含一个CMakeLists,它通过add_subdirectory包含'static_lib1'和'executable',方便一次性构建整个项目。

如果我手动构建'static_lib1'然后'可执行',那么一切正常。但是当从主文件夹运行CMakeLists时,我收到错误,因为find_package无法从尚未构建的'static_lib1'中找到库文件。

如何在保持CMakeLists文件分离的同时解决这个问题(即不包括可执行文件的CMakeLists中的static_lib的CMakeLists)?

2 个答案:

答案 0 :(得分:3)

在可执行文件的CMakeLists.txt中,您可以检查您是独立构建还是作为项目的一部分构建:

if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
  # stand-alone build
  find_package(static_lib1)
else()
  include_directories(../static_lib1)
  link_directories(../static_lib1)
  ...
  target_link_libraries(executable static_lib1)
endif()

答案 1 :(得分:0)

从基于文件的方法切换到基于目标的方法,以处理从executablestatic_lib1的依赖性。

发生原始问题是因为executable调用find_package来定位static_lib1,然后它试图通过调用{用库文件的路径填充STATIC_LIB1_LIBRARY这样的变量{1}}。 find_library然后在executable调用中使用该变量的内容。这里的问题是,由于这些库文件仅在构建过程中生成,因此对target_link_libraries(executable ${STATIC_LIB1_LIBRARY})的调用将找不到任何内容。

构建find_library需要在此处支持两种方案:

  1. 构建为独立版本,executable的预编译版本位于光盘上的某个位置。
  2. static_lib1构建,其中main_folderexecutable都是同一构建的一部分。

问题中的方法支持方案1,但不支持方案2。

使用目标代替使用变量来传达两个构建之间的依赖关系。 static_lib1的{​​{1}}可能会创建类似CMakeLists.txt的库目标。在可执行文件中,我们现在只需执行static_lib1。这足以支持方案2。

为了同时允许场景1,我们来看add_library(static_lib1 [...])target_link_libraries(executable PUBLIC static_lib1)中对find_package(static_lib1)的调用。现在,此调用不再需要像以前那样提供变量,而需要提供使用目标CMakeLists.txt

因此,我们将executable的查找脚本调整为以下行为:

  • 如果目标static_lib1已经存在,则无需执行任何操作,并且可以返回查找脚本(这是方案2)。

  • 否则,我们调用find_library在磁盘上找到库文件(与以前的原始方法一样),然后创建一个新的导入目标:static_lib1。然后,我们将静态库的所有相关属性配置到该目标。例如,要添加库文件的位置,我们可以

    static_lib1

    要支持MSVC等多配置生成器,而不是设置IMPORTED_LOCATIONIMPORTED_LINK_INTERFACE_LANGUAGES,而是要设置特定于配置的属性,例如IMPORTED_LOCATION_DEBUG and IMPORTED_LOCATION_RELEASE。由于手动操作可能很繁琐,因此您可以让CMake在package script中为您生成此信息(以及许多其他方便的东西)。程序包脚本的查找机制在幕后工作原理略有不同,但是add_library(static_lib1 STATIC IMPORTED)的{​​{1}}中的代码看起来是相同的,只需调用set_target_properties(static_lib1 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION ${STATIC_LIB1_LIBRARY} ) 。主要区别在于,此调用将不会分派到手写的查找脚本,而是分派到CMake在CMakeLists.txt的构建过程中自动生成的程序包脚本。