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 项目的智能方法

CMake ExternalProject_Add 中的 URL 问题

cmake:下载easylogging++,直接使用源码

CMake:如何构建外部项目并包含其目标