首页 > 解决方案 > 在 CMakeLists.txt 中执行 cmake 与在终端中执行 cmake 有什么区别,我们如何使其行为相同?

问题描述

好的,我不确定如何准确解释问题,但基本上,在我的Project X的 CMakeLists.txt 中,我正在构建外部库依赖项,它们本身就是独立的项目(例如,项目 A、项目 B、项目 C,项目 D)-然后我使用catkin_make.

ExternalProject_Add()我为每个项目A、B、C、D使用 CMake ;然后声明add_dependencies()使项目A, B, C, D在主项目 X之前先构建。

现在,我对Project D尤其有问题,需要设置多个路径CMAKE_PREFIX_PATH(例如,CMAKE_PREFIX_PATH=/addrA;/addrB;addrC)。

请注意,当我尝试在终端中运行 Project D 的 cmake 时,我根本没有遇到任何问题。

作为一种解决方法,我execute_process()创建了一个包含项目 D的 cmake 和 make 命令的 bash 脚本,然后我只是在ExternalProject_Add()'sBUILD_COMMANDadd_custom_target()'s调用该 bash 脚本COMMAND这些工作中的任何一个 - 这只是表明,在其中一个中执行的COMMANDcmakeExternalProject_Add()add_custom_target()在某种程度上不同于在终端中或通过 bash 脚本执行 cmake。

我在这里搜索了所有内容,但找不到与我有相同问题的人,因此我现在的解决方法是。

这是有效的粗略代码(我的解决方法):

### Project A 
include(ExternalProject)
ExternalProject_Add(ProjectA
    PREFIX             /tmp/ProjectA
    GIT_REPOSITORY     https://github.com/ProjectA
    GIT_TAG            v0.0.1
    CONFIGURE_COMMAND  ""
    BUILD_COMMAND      cmake -DWITH_GFLAGS=off -DCMAKE_INSTALL_PREFIX=/opt/ProjectA <SOURCE_DIR>
    COMMAND            sudo cmake --build . --target install
    INSTALL_COMMAND    ""
    TEST_COMMAND       ""
)

### Project B
include(ExternalProject)
ExternalProject_Add(ProjectB
    PREFIX             /tmp/ProjectB
    GIT_REPOSITORY     https://github.com/ProjectB
    GIT_TAG            v0.0.1
    CONFIGURE_COMMAND  ""
    BUILD_COMMAND      cmake -DLWS_STATIC_PIC=ON -DCMAKE_INSTALL_PREFIX=/opt/ProjectB <SOURCE_DIR>
    COMMAND            sudo cmake --build . --target install
    INSTALL_COMMAND    ""
    TEST_COMMAND       ""
)

### Project C
include(ExternalProject)
ExternalProject_Add(ProjectC
    PREFIX             /tmp/ProjectC
    GIT_REPOSITORY     https://github.com/ProjectC
    GIT_TAG            v0.0.1
    CONFIGURE_COMMAND  ""
    BUILD_COMMAND      cmake -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=/opt/ProjectC <SOURCE_DIR>
    COMMAND            sudo cmake --build . --target install
    INSTALL_COMMAND    ""
    TEST_COMMAND       ""
)

### Project D
execute_process (
    COMMAND bash -c "echo '#!/bin/bash\ncmake -DCMAKE_PREFIX_PATH=\"/opt/ProjectA;/opt/ProjectB;/opt/ProjectC\" /tmp/ProjectD/src/ProjectD\nmake' > /tmp/projectD_build.sh"
    COMMAND bash -c "chmod 777 /tmp/projectD_build.sh"
)
include(ExternalProject)
ExternalProject_Add(ProjectD
    PREFIX             /tmp/ProjectD
    GIT_REPOSITORY     https://github.com/ProjectD
    GIT_TAG            master
    CONFIGURE_COMMAND  ""
    BUILD_COMMAND      /tmp/projectD_build.sh
    INSTALL_COMMAND    ""
    TEST_COMMAND       ""
)

### Set dependencies to force build Project A, B, C, D before Project X is build
add_library (ProjectX SHARED IMPORTED)
set_target_properties (ProjectX PROPERTIES IMPORTED_LOCATION ${ProjectX_LIBS})
add_dependencies(ProjectX ProjectA)
add_dependencies(ProjectX ProjectB)
add_dependencies(ProjectX ProjectC)
add_dependencies(ProjectX ProjectD)

### Project X build commands here (snipped)

这些是 /tmp/ProjecD_build.txt 中的 cmake + make 命令:

cmake -DCMAKE_PREFIX_PATH="/opt/ProjectA;/opt/ProjectB;/opt/ProjectC" /tmp/ProjectD/src/ProjectD
make

如果我用这个替换整个“### Project D”部分,我会遇到我上面讨论过的错误 #1(多路径 CMAKE_PREFIX_PATH 的问题):

### Project D
include(ExternalProject)
ExternalProject_Add(ProjectD
    PREFIX             /tmp/ProjectD
    GIT_REPOSITORY     https://github.com/ProjectD
    GIT_TAG            master
    CONFIGURE_COMMAND  ""
    BUILD_COMMAND      cmake -DCMAKE_PREFIX_PATH="/opt/ProjectA;/opt/ProjectB;/opt/ProjectC" /tmp/ProjectD/src/ProjectD
    INSTALL_COMMAND    make
    TEST_COMMAND       ""
)

...或像这样添加一个 post-ProjectD,它仍然不起作用并导致我上面讨论的错误 #2(CMAKE 标志未正确设置,如 CMakeCache.txt 中所示)。请注意,使用此解决方案,我将Project D ExternalProject_Add()设置为" BUILD_COMMAND" 因为构建将由添加完成add_custom_target()

ExternalProject_Get_Property(ProjectD install_dir)
ExternalProject_Get_Property(ProjectD source_dir)
ExternalProject_Get_Property(ProjectD binary_dir)
message(STATUS "install_dir is: " ${install_dir})
message(STATUS "source_dir is: " ${source_dir})
message(STATUS "binary_dir is: " ${binary_dir})

add_custom_target(ProjectD_part2 ALL
    cmake -DCMAKE_PREFIX_PATH="/opt/ProjectA;/opt/ProjectB;/opt/ProjectC" ${source_dir}
    COMMAND make
    WORKING_DIRECTORY ${binary_dir}
)

add_dependencies(ProjectD_part2 ProjectA)
add_dependencies(ProjectD_part2 ProjectB)
add_dependencies(ProjectD_part2 ProjectC)
add_dependencies(ProjectD_part2 ProjectD)

解决方法有效。但是有没有更好的方法来做到这一点?谢谢你。

标签: c++cmake

解决方案


看起来很复杂!你能试试https://github.com/floooh/fips吗 ,它让很多 cmake 的事情变得更容易。Fips 是一个 Python 命令行工具,它通过将现有构建工具连接在一起,为 C/C++ 项目提供“集成构建环境”。它支持类似于 Rust 的 Cargo 或 Javascript 的 NPM 的工作流,但适用于 C/C++ 项目。


推荐阅读