cmake C使find_package依赖于子项目

kulphzqa  于 2022-11-11  发布在  其他
关注(0)|答案(3)|浏览(194)

我有以下目录布局:

main_folder
 + static_lib1
 + executable
  • “static_lib1”和“executable”都有一个完整的CMakeLists,因此可以独立生成。
  • “可执行文件”依赖于“static_lib1”。它使用find_package()来定位“static_lib1”。
  • main_folder包含一个CMakeLists,它通过add_subdirectory同时包含“static_lib1”和“executable”,以便一次构建整个项目。

如果我手动生成“static_lib1”,然后再生成“executable”,一切都正常。但当从主文件夹运行CMakeLists时,我得到一个错误,因为find_package无法从“static_lib1”中找到尚未生成的库文件。
如何在保持CMakeLists文件独立的同时解决此问题(即,不将static_lib的CMakeLists与可执行文件的CMakeLists包括在一起)?

wvt8vs2t

wvt8vs2t1#

在可执行文件的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()
7vux5j2d

7vux5j2d2#

从基于文件的方法切换到基于目标的方法,以处理从executablestatic_lib1的依赖关系。
发生最初的问题是因为executable调用find_package来定位static_lib1,然后static_lib1试图通过调用find_library用库文件的路径填充STATIC_LIB1_LIBRARY之类的变量。executable然后在target_link_libraries(executable ${STATIC_LIB1_LIBRARY})调用中使用该变量的内容。这里的问题是,由于这些库文件只作为构建的一部分生成,对find_library调用将无法找到任何内容。
构建executable需要支持以下两种场景:
1.构建单机版,其中static_lib1的预编译版本位于光盘上的某个位置。
1.从main_folder生成,其中executablestatic_lib1都是同一生成的一部分。
问题中的方法支持场景1,但不支持场景2。
在两个构建版本之间使用一个目标来传递依赖关系,而不是使用一个变量。static_lib1CMakeLists.txt可能会创建一个像add_library(static_lib1 [...])这样的库目标。在可执行文件中,我们现在只需执行target_link_libraries(executable PUBLIC static_lib1)。这足以支持场景2。
为了同时考虑到场景1,我们在executableCMakeLists.txt中查看对find_package(static_lib1)的调用。此调用现在需要提供一个目标static_lib1以供使用,而不是像以前那样提供一个变量。
因此,我们将static_lib1的find脚本调整为以下行为:

  • 如果目标static_lib1已经存在,则不需要执行任何操作,find脚本可以直接返回(这是场景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}
)

为了支持像MSVC这样的多配置生成器,您将需要设置像IMPORTED_LOCATION_DEBUG and IMPORTED_LOCATION_RELEASE这样的配置特定属性,而不是设置IMPORTED_LOCATIONIMPORTED_LINK_INTERFACE_LANGUAGES。您可以让CMake生成此信息,包脚本的查找机制在内部的工作方式略有不同,但CMakeLists.txt中的executable代码看起来是一样的,只是简单地调用find_package(static_lib1)。主要区别在于,此调用不会分派给手写的find脚本,而是分派给作为static_lib1构建过程的一部分由CMake自动生成的package脚本。

ryhaxcpt

ryhaxcpt3#

我想我会把这个答案留给后人,因为直到最近我才寻找到这个问题的解决方案,并发现...

从CMake 3.24开始,这是可能的!

可以使用FetchContent_Declare()标志**OVERRIDE_FIND_PACKAGE**重写对find_package()的后续调用。
您的

add_subdirectory("path/to/static_lib1")

必须将main_folder/CMakeLists.txt中的调用替换为:

include(FetchContent)
FetchContent_Declare(
    static_lib1
    SOURCE_DIR "path/to/static_lib1"
    OVERRIDE_FIND_PACKAGE
)

find_package(static_lib1)的任何调用都将为您调用FetchContent_MakeAvailable(),实际上使其与add_subdirectory()调用相同。
您可以在CMake文档中阅读更多关于OVERRIDE_FIND_PACKAGE的信息。

相关问题