如何用CMake Presets实现环境变量或缓存变量二选一约束?
如何在CMakePresets.json中实现「VCPKG_DIR环境变量或CMAKE_TOOLCHAIN_FILE缓存变量二选一」的约束?
问题背景
我们可以通过CMakePresets.json基于父环境变量VCPKG_DIR指定vcpkg工具链文件,示例配置如下:
{ "version": 3, "cmakeMinimumRequired": { "major": 3, "minor": 20 }, "configurePresets": [ { "name": "demo", "displayName": "demo", "description": "demo", "generator": "Unix Makefiles", "binaryDir": "${sourceDir}/build", "toolchainFile": "$penv{VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake" } ] }
执行时设置VCPKG_DIR即可自动加载工具链:
$ VCPKG_DIR=/home/user/dev/vcpkg/ cmake --preset demo Preset CMake variables: CMAKE_TOOLCHAIN_FILE:FILEPATH="/home/user/dev/vcpkg//scripts/buildsystems/vcpkg.cmake" -- The C compiler identification is GNU 11.4.0 -- The CXX compiler identification is GNU 11.4.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/cc - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /home/user/dev/cmake_learn/preset_env_or_cachevar_for_toolchain/build $
同时,用户也可以直接通过-DCMAKE_TOOLCHAIN_FILE参数指定工具链,无需设置VCPKG_DIR:
$ cmake --preset demo -DCMAKE_TOOLCHAIN_FILE=/home/user/dev/vcpkg/scripts/buildsystems/vcpkg.cmake -- The C compiler identification is GNU 11.4.0 -- The CXX compiler identification is GNU 11.4.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/cc - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /home/user/dev/cmake_learn/preset_env_or_cachevar_for_toolchain/build $
我们希望实现的逻辑是:当用户未指定CMAKE_TOOLCHAIN_FILE时,必须设置VCPKG_DIR环境变量;若用户已指定CMAKE_TOOLCHAIN_FILE,则无需设置VCPKG_DIR。
最初尝试添加condition约束VCPKG_DIR非空,但这样会导致即使指定了CMAKE_TOOLCHAIN_FILE,仍要求必须设置VCPKG_DIR,不符合需求:
{ "version": 3, "cmakeMinimumRequired": { "major": 3, "minor": 20 }, "configurePresets": [ { "name": "demo", "displayName": "demo", "description": "demo", "generator": "Unix Makefiles", "binaryDir": "${sourceDir}/build", "toolchainFile": "$penv{VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake", "condition": { "type": "allOf", "conditions": [ { "type": "notEquals", "lhs": "$penv{VCPKG_DIR}", "rhs": "" } ] } } ] }
执行时的问题示例:
$ cmake --preset demo -DCMAKE_TOOLCHAIN_FILE=/home/user/dev/vcpkg/scripts/buildsystems/vcpkg.cmake # 不符合预期:因未定义VCPKG_DIR而失败 CMake Error: Could not use disabled preset "demo" $
解决方案
要实现二选一约束,需要在condition中使用anyOf组合两个判断条件:
VCPKG_DIR环境变量非空CMAKE_TOOLCHAIN_FILE缓存变量已被指定(非空)
修改后的CMakePresets.json配置如下:
{ "version": 3, "cmakeMinimumRequired": { "major": 3, "minor": 20 }, "configurePresets": [ { "name": "demo", "displayName": "demo", "description": "demo", "generator": "Unix Makefiles", "binaryDir": "${sourceDir}/build", "toolchainFile": "$penv{VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake", "condition": { "type": "anyOf", "conditions": [ { "type": "notEquals", "lhs": "$penv{VCPKG_DIR}", "rhs": "" }, { "type": "notEquals", "lhs": "$cache{CMAKE_TOOLCHAIN_FILE}", "rhs": "" } ] } } ] }
验证效果
- 仅设置VCPKG_DIR:正常执行,自动加载工具链
$ VCPKG_DIR=/home/user/dev/vcpkg/ cmake --preset demo # 执行输出与之前一致,配置成功
- 仅指定CMAKE_TOOLCHAIN_FILE:无需设置VCPKG_DIR,正常执行
$ cmake --preset demo -DCMAKE_TOOLCHAIN_FILE=/home/user/dev/vcpkg/scripts/buildsystems/vcpkg.cmake # 执行输出与之前一致,配置成功
- 两者都未设置:预设被禁用,执行失败(符合预期)
$ cmake --preset demo CMake Error: Could not use disabled preset "demo" $
内容的提问来源于stack exchange,提问作者StoneThrow
相关产品推荐
相关产品推荐

