CMake:如何构建外部项目并包含其目标
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CMake:如何构建外部项目并包含其目标相关的知识,希望对你有一定的参考价值。
我有一个项目A,它导出一个静态库作为目标:
install(TARGETS alib DESTINATION lib EXPORT project_a-targets)
install(EXPORT project_a-targets DESTINATION lib/alib)
现在我想将项目A用作项目B的外部项目并包含其构建目标:
ExternalProject_Add(project_a
URL ...project_a.tar.gz
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
)
include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake)
问题是当运行项目B的CMakeLists时,包含文件尚不存在。
有没有办法让include依赖于正在构建的外部项目?
更新:我根据这个和我遇到的其他常见问题写了一个简短的CMake by Example tutorial。
我想你在这里混淆了两种不同的范例。
如您所述,高度灵活的ExternalProject
模块在构建时运行其命令,因此您无法直接使用Project A的导入文件,因为它仅在安装了项目A后才创建。
如果你想要include
项目A的导入文件,你必须在调用Project B的CMakeLists.txt之前手动安装Project A - 就像通过这种方式或通过find_file
/ find_library
/ find_package
添加的任何其他第三方依赖项一样。
如果你想使用ExternalProject_Add
,你需要在你的CMakeLists.txt中添加如下内容:
ExternalProject_Add(project_a
URL ...project_a.tar.gz
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
)
include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake)
ExternalProject_Get_Property(project_a install_dir)
include_directories(${install_dir}/include)
add_dependencies(project_b_exe project_a)
target_link_libraries(project_b_exe ${install_dir}/lib/alib.lib)
This post有一个合理的答案:
CMakeLists.txt.in
:
cmake_minimum_required(VERSION 2.8.2)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
CMakeLists.txt
:
# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in
googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
execute_process(COMMAND ${CMAKE_COMMAND} --build .
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
# Prevent GoogleTest from overriding our compiler/linker options
# when building with Visual Studio
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This adds
# the following targets: gtest, gtest_main, gmock
# and gmock_main
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build)
# The gtest/gmock targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later. Otherwise we have to add them here ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include"
"${gmock_SOURCE_DIR}/include")
endif()
# Now simply link your own targets against gtest, gmock,
# etc. as appropriate
然而,它似乎相当hacky。我想提出一个替代解决方案 - 使用Git子模块。
cd MyProject/dependencies/gtest
git submodule add https://github.com/google/googletest.git
cd googletest
git checkout release-1.8.0
cd ../../..
git add *
git commit -m "Add googletest"
然后在MyProject/dependencies/gtest/CMakeList.txt
你可以做类似的事情:
cmake_minimum_required(VERSION 3.3)
if(TARGET gtest) # To avoid diamond dependencies; may not be necessary depending on you project.
return()
endif()
add_subdirectory("googletest")
我还没有广泛尝试过,但看起来更干净。
编辑:这种方法有一个缺点:子目录可能会运行您不想要的install()
命令。 This post has an approach to disable them,但它是马车,并没有为我工作。
编辑2:如果使用add_subdirectory("googletest" EXCLUDE_FROM_ALL)
,似乎意味着默认情况下不使用子目录中的install()
命令。
您还可以在辅助生成过程中强制构建从属目标
有关相关主题,请参阅my answer。
你可以尝试做的是在你的export中使用cmake的project_a
命令。它使用install
命令与EXPORT option
有点不同,因为它在运行cmake时会产生一个project_a-targets.cmake
文件。 project_a-targets.cmake
文件中生成的导入目标最初指向项目二进制目录中的现有库文件,这些文件仅在运行build命令后生成。
为了更好地理解我正在谈论的,只需创建一个小的cmake项目,创建一个简单的库,然后是export命令(下面的代码尚未经过测试):
add_library (project_a lib.cpp)
export (
TARGETS
project_a
FILE
project_a-targets.cmake
)
在您的简单示例上运行cmake命令后,您应该能够在二进制目录(或其子文件夹之一)中找到project_a-targets.cmake
。检查文件时,您可能会注意到它当前指向一个不存在的库文件。只有在运行构建命令后,库才会存在。
所以回到你的问题,你需要更新project-a
的CMakeLists.txt
以包含export
命令。然后你需要确保在处理ExternalProject_Add
之后,它调用配置步骤,这将生成project_a-targets.cmake
,然后你可以调用应该工作的include(.../project_a-targets.cmake)
。最后,您需要在project_b
和project_a
之间添加依赖关系,以便在尝试构建project_a
之前强制构建project_b
。
以上是关于CMake:如何构建外部项目并包含其目标的主要内容,如果未能解决你的问题,请参考以下文章