CMake ExternalProject_Add() 和 FindPackage()
Posted
技术标签:
【中文标题】CMake ExternalProject_Add() 和 FindPackage()【英文标题】:CMake ExternalProject_Add() and FindPackage() 【发布时间】:2013-07-01 02:00:11 【问题描述】:是否有正确的方法可以找到使用ExternalProject_Add()
构建的库(通过FindPackage()
)?
问题是 CMake 在 CMake 时找不到库,因为外部库是在编译时构建的。我知道在超级构建中构建库和项目时可以结合这两个 CMake 函数,但我想在普通 CMake 项目中使用它。
事实上,我想在我的 CMake 项目中使用 ExternalProject_Add
构建 VTK 6 并使用 FindPackage
找到它。
【问题讨论】:
【参考方案1】:有办法做到这一点。但这有点骇人听闻。 您基本上添加了一个自定义目标,在构建期间重新运行 cmake。
您必须在一个小型测试项目中尝试此方法,以确定它是否适合您
find_package(Beaengine)
############################################
#
# BeaEngine
#
include(ExternalProject)
externalproject_add(BeaEngine
SOURCE_DIR $PROJECT_SOURCE_DIR/beaengine
SVN_REPOSITORY http://beaengine.googlecode.com/svn/trunk/
CMAKE_ARGS -DoptHAS_OPTIMIZED=TRUE -DoptHAS_SYMBOLS=FALSE -DoptBUILD_64BIT=FALSE -DoptBUILD_DLL=FALSE -DoptBUILD_LITE=FALSE
INSTALL_COMMAND ""
)
if(NOT $Beaengine_FOUND)
#rerun cmake in initial build
#will update cmakecache/project files on first build
#so you may have to reload project after first build
add_custom_target(Rescan $CMAKE_COMMAND $CMAKE_SOURCE_DIR DEPENDS BeaEngine)
else()
#Rescan becomes a dummy target after first build
#this prevents cmake from rebuilding cache/projects on subsequent builds
add_custom_target(Rescan)
endif()
add_executable(testapp testapp.cpp )
add_dependencies(testapp Rescan)
if($Beaengine_FOUND)
target_link_libraries(testapp $Beaengine_LIBRARY)
endif()
这似乎适用于 mingw makefiles / eclipse makefile 项目。 vs 将在首次构建后请求重新加载所有项目。
【讨论】:
这很有效,但是当使用具有缓存变量的 FindXpackage 时,您可能需要在 find_package 之前取消设置它们...即,如果构建比系统上可用的新版本的野牛:unset (FLEX_EXECUTABLE CACHE) find_package (FLEX 2.6) 未设置 (BISON_EXECUTABLE CACHE) find_package (BISON 3)【参考方案2】:您可以使用下面的 build_external_project 函数强制构建。
它的工作原理是在构建树中生成一个简单的帮助器项目,然后在帮助器上调用 cmake 配置和 cmake 构建。
为实际的 ExternalProject_add 命令随意定制。
请注意,尾随参数用于传递 CMAKE_ARGS。进一步的增强功能留给读者作为练习:-)
# This function is used to force a build on a dependant project at cmake configuration phase.
#
function (build_external_project target prefix url) #FOLLOWING ARGUMENTS are the CMAKE_ARGS of ExternalProject_Add
set(trigger_build_dir $CMAKE_BINARY_DIR/force_$target)
#mktemp dir in build tree
file(MAKE_DIRECTORY $trigger_build_dir $trigger_build_dir/build)
#generate false dependency project
set(CMAKE_LIST_CONTENT "
cmake_minimum_required(VERSION 2.8)
include(ExternalProject)
ExternalProject_add($target
PREFIX $prefix/$target
URL $url
CMAKE_ARGS $ARGN
INSTALL_COMMAND \"\"
)
add_custom_target(trigger_$target)
add_dependencies(trigger_$target $target)
")
file(WRITE $trigger_build_dir/CMakeLists.txt "$CMAKE_LIST_CONTENT")
execute_process(COMMAND $CMAKE_COMMAND ..
WORKING_DIRECTORY $trigger_build_dir/build
)
execute_process(COMMAND $CMAKE_COMMAND --build .
WORKING_DIRECTORY $trigger_build_dir/build
)
endfunction()
【讨论】:
我的project 中有类似的内容。值得注意的是,如果你想为不同的生成器构建发布/调试库,你需要不同的功能。对于类似 make 的生成器,您需要两个 ExternalProject_Add commands,对于类似 msvc 的生成器,您需要一个 ExternalProject_Add 命令,但需要两个 install stages。 不要忘记使用“execute_process(COMMAND $CMAKE_COMMAND -G$CMAKE_GENERATOR ..”将当前生成器传递给外部项目,否则如果二进制文件将用不同的生成器构建:)【参考方案3】:时间已经过去,CMake 实现了一个允许从 ExternalProject_Add 引用目标的本机版本。
此功能在FetchContent 模块中实现。它允许下载并立即使用在配置时定义的目标。
它使用我的previous answer 所暗示的临时构建目录,但在更集成的 API 中。
【讨论】:
这对 find_package 有什么帮助? FetchContent 没有提供安装目标的方法,那怎么办? 最初的问题是关于下载一个项目以在配置阶段找到它。阅读有关 FetchContent 的文档可以让我们看到 FetchContent_MakeAvailable() 函数中也提供了此功能。 使用find_package,它通常会检查实际文件是否存在,例如,使用find_library作为lib,使用find_path作为header。如果不触发编译和安装过程,这些文件将根本不存在。同样在文档中它说“INSTALL_COMMAND”是被禁止的。使用 FetchContent_MakeAvailable 不会进行安装。 也许吧,但这个问题与安装无关,它与在配置时消耗动态下载的目标有关。以上是关于CMake ExternalProject_Add() 和 FindPackage()的主要内容,如果未能解决你的问题,请参考以下文章
链接到 CMAKE 中的 ExternalProject_add 依赖项
CMake 使 add_library 依赖于 ExternalProject_Add
ExternalProject_Add 使用 pybind11 进行 CMake 项目的智能方法