Issue
The following CMakePresets.json demonstrates finding a toolchain file from a path relative to parent environment variable 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"
}
]
}
$ 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
$
However, a user (i.e. a specific user that I interact with) does not want to set any environment variables; the user wants to explicitly set the CMAKE_TOOLCHAIN_FILE
cache variable. CMake Presets seem to account for this cleanly: you can just specify -DCMAKE_TOOLCHAIN_FILE
:
$ 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
$
I want that when the user does not specify CMAKE_TOOLCHAIN_FILE
, the CMakePresets.json will enforce that the user does specify VCPKG_DIR
in the parent environment.
I tried adding a conditions
clause to implement this:
{
"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": ""
}
]
}
}
]
}
This implements the desired behavior of enforcing that the user specifies VCPKG_DIR
:
$ cmake --preset demo
CMake Error: Could not use disabled preset "demo"
$ 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
$
..but it's not quite right: it implements that the user must always specify VCPKG_DIR
in the parent environment:
$ cmake --preset demo -DCMAKE_TOOLCHAIN_FILE=/home/user/dev/vcpkg/scripts/buildsystems/vcpkg.cmake # undesired: CMake will fail this because VCPKG_DIR is not defined
CMake Error: Could not use disabled preset "demo"
$ VCPKG_DIR=/path/to/foo 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
$
Rather, I would like to implement the condition "either a parent environment variable is set or CMAKE_TOOLCHAIN_FILE
must be specified" -- is there a way to do this in CMakePresets.json?
Solution
No that is not possible. As I had pointed out in my answer to your question Is the system processor available in CMakePreset.json? there is no way to access the value of cache variables through macro expansion in a preset.
However, wouldn't removing the condition that the VCPKG_DIR
variable needs to be set already make the preset behave exactly as you want? If a user doesn't manually specify -DCMAKE_TOOLCHAIN_FILE
(or --toolchain
) on the command-line but has VCPKG_DIR
set it will work, if VCPKG_DIR
is set and the user doesn't specify their own toolchain file it will also work, and if a user doesn't set VCPKG_DIR
and also doesn't specify another toolchain file. configuring the project will fail because the toolchain file at /scripts/buildsystems/vcpkg.cmake
does not exist. That at least generates an error, whereas a condition that is not satisfied would hide the preset entirely, and the user wouldn't even know that they are meant to do something to make it visible.
Answered By - Corristo Answer Checked By - David Marino (WPSolving Volunteer)