CMake find_package对子项目的依赖

Com*_*sMS 5 cmake

我有以下目录布局:

main_folder
 + static_lib1
 + executable
Run Code Online (Sandbox Code Playgroud)
  • 'static_lib1'和'executable'都具有完整的CMakeLists,因此可以独立构建它们。
  • “可执行文件”取决于“ static_lib1”。它用于find_package()定位“ static_lib1”。
  • main_folder包含一个CMakeLists,该列表同时包含“ static_lib1”和“ executable”通过add_subdirectory,可方便地一次构建整个项目。

如果我手动构建“ static_lib1”,然后再“可执行”,则一切正常。但是从主文件夹运行CMakeLists时,出现错误,因为find_package无法从“ static_lib1”中找到尚未构建的库文件。

如何在保持CMakeLists文件分离的同时解决该问题(即,不将static_lib的CMakeLists与可执行文件的CMakeLists包括在内)?

Com*_*sMS 0

从基于文件的方法切换到基于目标的方法来处理从executable到 的依赖关系static_lib1

最初的问题是因为executable调用find_package定位而发生的static_lib1,然后尝试通过调用来填充变量,例如STATIC_LIB1_LIBRARY 库文件的路径find_libraryexecutable然后在调用中消耗该变量的内容target_link_libraries(executable ${STATIC_LIB1_LIBRARY})。这里的问题是,由于这些库文件仅作为构建的一部分生成,因此调用find_library将无法找到任何内容。

这里的构建executable需要支持两种场景:

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

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

不要使用变量来传达两个构建之间的依赖关系,而是使用目标。for可能会创建一个库目标,CMakeLists.txt例如. 在可执行文件中,我们现在只需执行. 这足以支持场景 2。static_lib1add_library(static_lib1 [...])target_link_libraries(executable PUBLIC static_lib1)

为了同时考虑场景 1,我们查看forfind_package(static_lib1)中的调用。此调用现在需要提供消费目标,而不是像以前那样提供变量。CMakeLists.txtexecutablestatic_lib1

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

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

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

    set_target_properties(static_lib1 PROPERTIES
      IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
      IMPORTED_LOCATION ${STATIC_LIB1_LIBRARY}
    )
    
    Run Code Online (Sandbox Code Playgroud)

    为了支持像 MSVC 这样的多配置生成器,您将需要设置配置特定属性,例如 和 ,IMPORTED_LOCATION不是设置 和 。由于手动执行此操作可能会非常繁琐,因此您可以让 CMake 在包脚本中为您生成此信息(以及一堆其他方便的内容)。包脚本的查找机制在底层工作原理略有不同,但for中的代码看起来是一样的,都是对. 主要区别在于,此调用不会分派到手写的查找脚本,而是分派到由 CMake 在构建过程中由 CMake 自动生成的包脚本。IMPORTED_LINK_INTERFACE_LANGUAGESIMPORTED_LOCATION_DEBUGIMPORTED_LOCATION_RELEASECMakeLists.txtexecutablefind_package(static_lib1)static_lib1