cmake - 是否可以确定是否从“安装”或“打包”阶段调用了 CMake install(CODE)?
问题描述
我正在使用 CMake v3.21.0在安装阶段通过install(CODE)命令调用 Qt 的windeployqt,如下所示:
install(
CODE "
execute_process(
COMMAND \"${CMAKE_COMMAND}\" -E
env PATH=\"${windeployqt_ROOT_DIR}\"
\"${windeployqt_EXECUTABLE}\"
# TODO(2021-08-25 by wolters): This is a different path when CPack is`
# used. How to check for this case and obtain the correct output path?
--dir \"${CMAKE_INSTALL_PREFIX}/${args_INSTALL_SUFFIX}\"
--no-quick-import
--no-system-d3d-compiler
--no-virtualkeyboard
--no-compiler-runtime
--no-webkit2
--no-angle
--no-opengl-sw
--verbose 0
\"\$<TARGET_FILE:${args_TARGET}>\"
)
"
COMPONENT runtime
)
如果安装项目,这工作正常:
cmake --build . --config RelWithDebInfo --target install
但是在创建 CPack 包时,创建的文件windeployqt
不是包的一部分(在这种情况下为 ZIP):
cpack -G ZIP -C RelWithDebInfo -D CPACK_COMPONENTS_ALL="runtime"
我知道问题是${CMAKE_INSTALL_PREFIX}
在CODE
.
- 对于
install
目标,这是正确的。 - 对于
package
目标,这是不正确的。相反,应该使用当前CPack 生成器的构建目录,例如${CMAKE_CURRENT_BINARY_DIR}/_CPack_Packages/win64/ZIP/${CPACK_PACKAGE_FILE_NAME}
.
我的问题是:
- 有没有办法区分
install
和package
定位该CODE
部分?(伪代码if(CMAKE_IS_PACKAGING)
:) - 如果有办法:是否可以获取或动态构建实际 CPack 临时“安装”目录的目录路径?
如果这两个问题都可以解决,则生成的文件windeployqt
应该是 CPack 生成的包的一部分。
解决方案
CMAKE_INSTALL_PREFIX
不应像您所做的那样在 CMakeLists.txt 中扩展该变量。它在调用时的实际值在install(CODE)
片段中可用。
考虑以下代码段:
cmake_minimum_required(VERSION 3.21)
project(test NONE)
install(CODE [[message(STATUS "HERE: ${CMAKE_INSTALL_PREFIX}")]])
请注意,[[ ... ]]
转义变量扩展(您也可以使用反斜杠)。现在,如果您使用 配置此项目-DCMAKE_INSTALL_PREFIX=/tmp/install
,您将看到按预期打印的消息。
$ cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/tmp/install
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
$ cmake --build build/ --target install
[0/1] Install the project...
-- Install configuration: ""
-- HERE: /tmp/install
如果您现在再次运行安装脚本而不重新配置或重建,它仍然可以工作:
$ cmake --install build/ --prefix /tmp/other-prefix
-- Install configuration: ""
-- HERE: /tmp/other-prefix
这就是 CPack 运行安装规则的方式。它不使用的配置时间值CMAKE_INSTALL_PREFIX
。它希望您的项目是可重定位的(即没有错误)。
推荐阅读
- apache-flink - Flink job falis to recover from checkpoint
- javascript - 使用 setState 方法的类何时发生状态更改?
- javascript - 从 URL 中两个相同字符之间获取子字符串
- moodle - Exams2moodle 可以导出额外的元信息,例如 idnumber 和标签吗?
- kubernetes - 将 hostPath 持久卷挂载到 Argo Workflow 任务模板
- python - 如何在python中提取与模式匹配的两个连续行
- rest - 过度获取究竟是什么意思?
- sql - 如何通过输入多个副本在Access中制作整行的多个副本?
- mysql - 为什么这个 SQL 代码不能在 WHERE EXISTS 构造中使用简单的谓词?
- docker - 使用 nginx 代理传递到子目录