CMake ExternalProject:如何指定根CMakeLists.txt的相对路径?

nil*_*ils 9 git build-automation build-process build cmake

似乎CMake ExternalProject总是假定外部项目的根目录是源目录.但如果不是这样呢?

请考虑以下示例:

外部项目使用此目录布局:

libfoo.git                 <--- ExternalProject assumes this as source dir.
??? ...
??? libfoo                 <--- However, the actual source directory is this!
    ??? CMakeLists.txt
    ???  ...
Run Code Online (Sandbox Code Playgroud)

在依赖项目libfoo中配置如下:

ExternalProject_Add( libfoo 
    PREFIX            "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo"
    GIT_REPOSITORY    "<link to remote which hosts libfoo.git>" 
    GIT_TAG           "<some hash>"
)
Run Code Online (Sandbox Code Playgroud)

然后生成失败,并显示以下错误消息:

$ cmake -H/path/to/source-dir -B/path/to/build-dir
...
$ cmake --build /path/to/build-dir/ --target all
...
CMake Error: The source directory "/path/to/build-dir/EP_libfoo/src/libfoo" does not appear to contain CMakeLists.txt.
...
$
Run Code Online (Sandbox Code Playgroud)

因此,正如上面的目录布局所指出的,CMake认为外部项目的根是

/path/to/build-dir/EP_libfoo/src/libfoo
Run Code Online (Sandbox Code Playgroud)

事实上,它确实如此

/path/to/build-dir/EP_libfoo/src/libfoo/libfoo
Run Code Online (Sandbox Code Playgroud)

我试图解决这个问题:

  1. 不幸的是,修改参数SOURCE_DIRExternalProject没有工作,因为这个变量的值被用作位置,它是的Git仓库libfoo克隆到.这导致递归依赖地狱无法打破.

  2. 更改目录布局libfoo以符合ExternalProject.显然,这可行,但它可能不适用于其他(只读)第三方库.

  3. 滥用更新/补丁步骤ExternalProject,例如通过指定

    set( EP_LIBFOO_DIR "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo" )
    
    ExternalProject_Add( libfoo 
        PREFIX            "${EP_LIBFOO_DIR}"
        GIT_REPOSITORY    "<link to remote which hosts libfoo.git>" 
        GIT_TAG           "<some hash>"
    
        # Copy the content of `<...>/libfoo/libfoo` into `<...>/libfoo`.
        # Note to self: using symlinks instead copying is too platform-specific.
        PATCH_COMMAND     ${CMAKE_COMMAND} -E copy_directory "${EP_LIBFOO_DIR}/src/libfoo/libfoo" "${EP_LIBFOO_DIR}/src/libfoo"
    )
    
    Run Code Online (Sandbox Code Playgroud)

    这有效,但很容易与其他外部项目失败.

  4. 解决另一个问题的基础上:CMakeLists.txt在CMake承担它的位置添加一个临时值 .这个临时文件然后包括实际CMakeLists.txt:

    set( EP_LIBFOO_DIR "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo" )
    set( GENERATED_DIR "${CMAKE_BINARY_DIR}/generated" )
    
    file( MAKE_DIRECTORY ${GENERATED_DIR} )
    file( WRITE ${GENERATED_DIR}/CMakeLists.txt
        "cmake_minimum_required( VERSION 3.0 )\n"
        "add_subdirectory( libfoo )\n" 
    )
    
    ExternalProject_Add( libfoo 
        PREFIX            "${EP_LIBFOO_DIR}"
        GIT_REPOSITORY    "<link to remote which hosts libfoo.git>" 
        GIT_TAG           "<some hash>"
    
        # Copy the 
        UPDATE_COMMAND    ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/generated/CMakeLists.txt ${EP_LIBFOO_DIR}/src/libfoo
    )
    
    Run Code Online (Sandbox Code Playgroud)

    这也很有效,感觉比以前的解决方案更好.

但是,存在更优雅的做法吗?

Mat*_*hew 10

我已经提交了一个合并请求来添加一个SOURCE_SUBDIR选项来ExternalProject_Add解决这个用例.希望它将在CMake 3.7中提供.(您也可以ExternalProject*.cmake在本地复制到您自己的项目中,以便立即利用该功能.)