CMakeLists调用cmake与终端执行的差异及一致化实现方案
问题根因
首先明确两个错误的核心原因:
- 错误1:CMake配置阶段会把所有带
;的字符串按列表拆分,你直接把多路径CMAKE_PREFIX_PATH传入自定义BUILD_COMMAND时,/addrA;/addrB会被拆成两个独立参数,自然只有第一个路径生效。你之前尝试的LIST_SEPARATOR、$<SEMICOLON>无效,是因为你自定义了BUILD_COMMAND/CONFIGURE_COMMAND,这些参数只有在使用ExternalProject原生配置流程时才会生效。 - 错误2:自定义
add_custom_target构建时没有显式传入所有CMAKE_INSTALL_*参数,也没有关联ExternalProject下载的源码路径、构建路径变量,导致参数没有正确传递到cmake配置流程。
规范解决方案
方案1:使用ExternalProject原生配置流程(最推荐)
不要覆盖CONFIGURE_COMMAND、BUILD_COMMAND,直接用原生的CMAKE_ARGS参数配合LIST_SEPARATOR处理多路径分隔符,ExternalProject会自动完成参数转义、路径映射:
include(ExternalProject) # 声明Project D依赖A/B/C,保证构建顺序 add_dependencies(ProjectD ProjectA ProjectB ProjectC) ExternalProject_Add(ProjectD PREFIX /tmp/ProjectD GIT_REPOSITORY https://github.com/ProjectD GIT_TAG master # 指定列表分隔符为|,避免分号被提前拆分 LIST_SEPARATOR | # 所有配置参数通过CMAKE_ARGS传入 CMAKE_ARGS -DCMAKE_PREFIX_PATH=/opt/ProjectA|/opt/ProjectB|/opt/ProjectC -DCMAKE_INSTALL_PREFIX=/opt/ProjectD # 其他需要的配置参数直接加在这里即可 TEST_COMMAND "" )
这个方案完全不需要自定义脚本,原生支持参数传递,也不会出现CMAKE_INSTALL_*映射错误的问题。
方案2:自定义命令用bash包装
如果确实需要自定义构建流程,直接把整个cmake命令放到bash -c的字符串参数中,避免CMake提前拆分参数,行为和终端执行完全一致:
ExternalProject_Add(ProjectD PREFIX /tmp/ProjectD GIT_REPOSITORY https://github.com/ProjectD GIT_TAG master CONFIGURE_COMMAND "" BUILD_COMMAND bash -c "cmake -DCMAKE_PREFIX_PATH=\"/opt/ProjectA;/opt/ProjectB;/opt/ProjectC\" -DCMAKE_INSTALL_PREFIX=/opt/ProjectD <SOURCE_DIR> && make -j$(nproc) && make install" INSTALL_COMMAND "" TEST_COMMAND "" )
这个方案比生成临时脚本的写法更简洁,不需要额外生成中间文件。
额外优化建议
你当前写的Project A/B/C也不需要自定义BUILD_COMMAND,直接用原生CMAKE_ARGS传递参数即可,可读性和可维护性更高,示例如下:
ExternalProject_Add(ProjectA PREFIX /tmp/ProjectA GIT_REPOSITORY https://github.com/ProjectA GIT_TAG v0.0.1 CMAKE_ARGS -DWITH_GFLAGS=off -DCMAKE_INSTALL_PREFIX=/opt/ProjectA TEST_COMMAND "" )
另外不建议在构建命令中加sudo,会导致构建过程需要手动输入密码,CI环境也无法正常运行,建议提前给安装目录赋权限,或者编译完成后手动执行安装命令。
内容的提问来源于stack exchange,提问作者Maj
相关产品推荐
相关产品推荐

