我有以下目录布局:
main_folder
+ static_lib1
+ executable
find_package()
来定位'static_lib1'。add_subdirectory
包含'static_lib1'和'executable',方便一次性构建整个项目。如果我手动构建'static_lib1'然后'可执行',那么一切正常。但是当从主文件夹运行CMakeLists时,我收到错误,因为find_package
无法从尚未构建的'static_lib1'中找到库文件。
如何在保持CMakeLists文件分离的同时解决这个问题(即不包括可执行文件的CMakeLists中的static_lib的CMakeLists)?
答案 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)
从基于文件的方法切换到基于目标的方法,以处理从executable
到static_lib1
的依赖性。
发生原始问题是因为executable
调用find_package
来定位static_lib1
,然后它试图通过调用{用库文件的路径填充STATIC_LIB1_LIBRARY
这样的变量{1}}。 find_library
然后在executable
调用中使用该变量的内容。这里的问题是,由于这些库文件仅在构建过程中生成,因此对target_link_libraries(executable ${STATIC_LIB1_LIBRARY})
的调用将找不到任何内容。
构建find_library
需要在此处支持两种方案:
executable
的预编译版本位于光盘上的某个位置。static_lib1
构建,其中main_folder
和executable
都是同一构建的一部分。问题中的方法支持方案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_LOCATION
和IMPORTED_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
的构建过程中自动生成的程序包脚本。