CMake:如何构建外部项目并包括其目标
我有一个项目a,它将静态库导出为目标:CMake:如何构建外部项目并包括其目标,cmake,external-project,Cmake,External Project,我有一个项目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_
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)
ExternalProject\u Add(项目a
URL…project_a.tar.gz
前缀${CMAKE\u CURRENT\u BINARY\u DIR}/project\u a
CMAKE_ARGS-DCMAKE_INSTALL_前缀:PATH=
)
包括(${CMAKE\u CURRENT\u BINARY\u DIR}/lib/project\u a/project\u a-targets.CMAKE)
问题是,在运行项目B的CmakeList时,包含文件还不存在
有没有办法使include依赖于正在构建的外部项目
更新:
我根据这一点和我遇到的其他常见问题写了一篇短文。我想你在这里混淆了两种不同的范例 正如您所注意到的,高度灵活的模块在构建时运行其命令,因此您不能直接使用Project A的导入文件,因为它只在安装Project A后创建 如果您想
包含项目A的导入文件,则必须在调用项目B的CMakeLists.txt之前手动安装项目A-就像以这种方式或通过查找文件/查找库/查找包添加的任何其他第三方依赖项一样
如果要使用ExternalProject\u 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)
ExternalProject\u Add(项目a
URL…project_a.tar.gz
前缀${CMAKE\u CURRENT\u BINARY\u DIR}/project\u a
CMAKE_ARGS-DCMAKE_INSTALL_前缀:PATH=
)
包括(${CMAKE\u CURRENT\u BINARY\u DIR}/lib/project\u a/project\u a-targets.CMAKE)
外部项目获取属性(项目安装目录)
包含目录(${install\u dir}/include)
添加依赖项(项目b项目a)
target_link_库(project_exe${install_dir}/lib/alib.lib)
Edit:CMake现在已经内置了对此的支持。看哪一个使用
还可以在辅助生成过程中强制生成从属目标
请参阅相关主题。有一个合理的答案:
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
然而,它看起来确实很粗糙。我想提出另一种解决方案——使用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()
命令。但那是辆马车,对我不起作用
编辑2:如果使用add\u子目录(“googletest”EXCLUDE\u FROM\u ALL)
似乎意味着默认情况下不使用子目录中的install()
命令。cmake的ExternalProject\u add确实可以使用,但我不喜欢它——它在构建、连续轮询等过程中执行某些操作。。。我更喜欢在构建阶段构建项目,而不是其他阶段。我多次尝试覆盖ExternalProject\u Add
,但不幸没有成功
然后,我还尝试添加git子模块,但这会拖拽整个git存储库,而在某些情况下,我只需要整个git存储库的子集。我已经检查过了——确实可以执行稀疏git签出,但这需要单独的函数,我在下面写到
#-----------------------------------------------------------------------------
#
# Performs sparse (partial) git checkout
#
# into ${checkoutDir} from ${url} of ${branch}
#
# List of folders and files to pull can be specified after that.
#-----------------------------------------------------------------------------
function (SparseGitCheckout checkoutDir url branch)
if(EXISTS ${checkoutDir})
return()
endif()
message("-------------------------------------------------------------------")
message("sparse git checkout to ${checkoutDir}...")
message("-------------------------------------------------------------------")
file(MAKE_DIRECTORY ${checkoutDir})
set(cmds "git init")
set(cmds ${cmds} "git remote add -f origin --no-tags -t master ${url}")
set(cmds ${cmds} "git config core.sparseCheckout true")
# This command is executed via file WRITE
# echo <file or folder> >> .git/info/sparse-checkout")
set(cmds ${cmds} "git pull --depth=1 origin ${branch}")
# message("In directory: ${checkoutDir}")
foreach( cmd ${cmds})
message("- ${cmd}")
string(REPLACE " " ";" cmdList ${cmd})
#message("Outfile: ${outFile}")
#message("Final command: ${cmdList}")
if(pull IN_LIST cmdList)
string (REPLACE ";" "\n" FILES "${ARGN}")
file(WRITE ${checkoutDir}/.git/info/sparse-checkout ${FILES} )
endif()
execute_process(
COMMAND ${cmdList}
WORKING_DIRECTORY ${checkoutDir}
RESULT_VARIABLE ret
)
if(NOT ret EQUAL "0")
message("error: previous command failed, see explanation above")
file(REMOVE_RECURSE ${checkoutDir})
break()
endif()
endforeach()
endfunction()
SparseGitCheckout(${CMAKE_BINARY_DIR}/catch_197 https://github.com/catchorg/Catch2.git v1.9.7 single_include)
SparseGitCheckout(${CMAKE_BINARY_DIR}/catch_master https://github.com/catchorg/Catch2.git master single_include)
#-----------------------------------------------------------------------------
#
#执行稀疏(部分)git签出
#
#从${branch}的${url}进入${checkoutDir}
#
#之后可以指定要拉取的文件夹和文件的列表。
#-----------------------------------------------------------------------------
函数(SparseGitCheckout checkoutDir url分支)
if(存在${checkoutDir})
返回()
endif()
消息(“----------------------------------------------------------------------------”)
消息(“稀疏git签出到${checkoutDir}…”)
消息(“----------------------------------------------------------------------------”)
文件(生成目录${checkoutDir})
集合(cmds“git init”)
set(cmds${cmds}“git remote add-f origin--no tags-t master${url}”)
设置(cmds${cmds}“git config core.sparseCheckout true”)
#此命令通过文件写入执行
#echo>>.git/info/sparse checkout”)
set(cmds${cmds}“git pull--depth=1 origin${branch}”)
#消息(“在目录中:${checkoutDir}”)
foreach(cmd${cmds})
消息(“-${cmd}”)
字符串(替换“;”cmdList${cmd})
#消息(“Outfile:${Outfile}”)
#消息(“最终命令:${cmdList}”)
if(拉入列表cmdList)
字符串(替换“\n”文件“${ARGN}”)
文件(写入${checkoutDir}/.git/info/sparse checkout${FILES})
endif()
执行程序(
命令${cmdList}
工作目录${checkoutDir}
结果变量ret
)
如果(不等于“0”)
消息(“错误:上一个命令失败,请参阅上面的解释”)
文件(删除\u RECURSE${checkoutDir})
break()
endif()
endforeach()
endfunction()
SparseGitCheckout(${CMAKE_BINARY_DIR}/catch_197)https://github.com/catchorg/Catch2.git v1.9.7单个(包括)
SparseGitCheckout(${CMAKE_BINARY_DIR}/catch_masterhttps://github.com/catchorg/Catch2.git 主单板(包括)
我在下面添加了两个函数调用,只是为了说明如何使用该函数
有人可能不喜欢签出master/trunk,因为它可能会坏掉——然后总是可以指定特定的标记
签出将只执行一次,直到您清除缓存文件夹。我正在搜索类似的解决方案。此处的回复和顶部的教程提供了信息。我研究了此处引用的帖子/博客,以成功构建我的帖子。我发布了完整的CMakeLists.txt,对我来说很有用。我想
cmake_minimum_required(VERSION 3.10.2)
# Target Project
project (ClientProgram)
# Begin: Including Sources and Headers
include_directories(include)
file (GLOB SOURCES "src/*.c")
# End: Including Sources and Headers
# Begin: Generate executables
add_executable (ClientProgram ${SOURCES})
# End: Generate executables
# This Project Depends on External Project(s)
include (ExternalProject)
# Begin: External Third Party Library
set (libTLS ThirdPartyTlsLibrary)
ExternalProject_Add (${libTLS}
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/${libTLS}
# Begin: Download Archive from Web Server
URL http://myproject.com/MyLibrary.tgz
URL_HASH SHA1=<expected_sha1sum_of_above_tgz_file>
DOWNLOAD_NO_PROGRESS ON
# End: Download Archive from Web Server
# Begin: Download Source from GIT Repository
# GIT_REPOSITORY https://github.com/<project>.git
# GIT_TAG <Refer github.com releases -> Tags>
# GIT_SHALLOW ON
# End: Download Source from GIT Repository
# Begin: CMAKE Comamnd Argiments
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/${libTLS}
CMAKE_ARGS -DUSE_SHARED_LIBRARY:BOOL=ON
# End: CMAKE Comamnd Argiments
)
# The above ExternalProject_Add(...) construct wil take care of \
# 1. Downloading sources
# 2. Building Object files
# 3. Install under DCMAKE_INSTALL_PREFIX Directory
# Acquire Installation Directory of
ExternalProject_Get_Property (${libTLS} install_dir)
# Begin: Importing Headers & Library of Third Party built using ExternalProject_Add(...)
# Include PATH that has headers required by Target Project
include_directories (${install_dir}/include)
# Import librarues from External Project required by Target Project
add_library (lmytls SHARED IMPORTED)
set_target_properties (lmytls PROPERTIES IMPORTED_LOCATION ${install_dir}/lib/libmytls.so)
add_library (lmyxdot509 SHARED IMPORTED)
set_target_properties(lmyxdot509 PROPERTIES IMPORTED_LOCATION ${install_dir}/lib/libmyxdot509.so)
# End: Importing Headers & Library of Third Party built using ExternalProject_Add(...)
# End: External Third Party Library
# Begin: Target Project depends on Third Party Component
add_dependencies(ClientProgram ${libTLS})
# End: Target Project depends on Third Party Component
# Refer libraries added above used by Target Project
target_link_libraries (ClientProgram lmytls lmyxdot509)