【问题标题】:CMake ExternalProject_Add() and FindPackage()CMake ExternalProject_Add() 和 FindPackage()
【发布时间】:2013-07-01 02:00:11
【问题描述】:

是否有正确的方法可以找到使用ExternalProject_Add() 构建的库(通过FindPackage())?

问题是 CMake 在 CMake 时找不到库,因为外部库是在编译时构建的。我知道在超级构建中构建库和项目时可以结合这两个 CMake 函数,但我想在普通 CMake 项目中使用它。

事实上,我想在我的 CMake 项目中使用 ExternalProject_Add 构建 VTK 6 并使用 FindPackage 找到它。

【问题讨论】:

    标签: c++ build cmake vtk external-project


    【解决方案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 不会进行安装。
    • 也许吧,但这个问题与安装无关,它与在配置时消耗动态下载的目标有关。
    猜你喜欢
    • 1970-01-01
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    • 2014-10-21
    • 2016-11-26
    • 2011-09-15
    • 2016-10-21
    • 2018-12-20
    相关资源
    最近更新 更多