CMake presets: `inherit` makes it hard to include toolchain file

Hi,

We have a CMake structure where there is a common platform which can be built by itself or included via different sub-components.

Since the platform is always used by the sub-components we thought it a good fit to specify a CMakePresets.json file in the platform and the sub-components would simply include it.

|- common/
| |- platform/
| | |- CMakeLists.txt
| | |- CMakePresets.json
|- sub-component1/
| |- CMakeLists.txt
| |- CMakePresets.json (includes the platforms CMakePreset.json)
|- sub-component2/
| | - CMakeLists.txt
| | - CMakePresets.json (includes the platforms CMakePreset.json)

The configurePresets in the platforms CMakePresets.json looks something like this:

 "configurePresets": [
    {
      "name": "linux",
      "description": "Configure options specific for Linux",
      "generator": "Ninja",
      "toolchainFile": "${fileDir}/cmake/toolchains/linux.cmake"
    },
    {
      "name": "linux-multi",
      "inherits": "linux",
      "description": "Multi-config linux setup",
      "generator": "Ninja Multi-Config"
    },
    {
      "name": "windows",
      "description": "Configure options specific for Windows",
      "generator": "Visual Studio 17 2022",
      "architecture": {
          "value": "x64"
        },
      "toolchainFile": "${fileDir}/cmake/toolchains/windows.cmake"
    }

This worked fine when the sub-components simply included the platforms CMakePresets.json from their own. However, when users started to specify their own presets and used inherit on the platforms presets the toolchainFile didn’t work any longer since the ${fileDir} macro is no evaluated in the context of the platform, but the sub-components: “All macros are evaluated in the context of the preset being used, even if the macro is in a field that was inherited from another preset.” https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html#macro-expansion

Using the CMAKE_TOOLCHAIN_FILE is not an ideal solution for us (since it would require changing both the platform and all sub-components) since the sub-components typically include the platform after they’ve specified project() causing the toolchain file not to be included.

Given that we want to be able to build the platform by itself and via the sub-components, is it possible to use inherit in combination with the above toolchainFile inclusion?

2 Likes

To clarify, adding the following CMakeUserPresets.json to sub-component1:

{
    "version": 6,
    "configurePresets": [{
      "name": "default",
      "inherits": "linux-multi", // defined in platform
      "cacheVariables": {
        ...
      }
    }]
}

results in the following error:

 cmake --preset default .
Preset CMake variables:

  ...

  CMAKE_TOOLCHAIN_FILE:FILEPATH="/path/to/subcomponent1/cmake/toolchains/linux.cmake"

Using ccache /usr/bin/ccache
CMake Error at /usr/share/cmake-3.25/Modules/CMakeDetermineSystem.cmake:130 (message):
  Could not find toolchain file:
  /path/to/subcomponent1/cmake/toolchains/linux.cmake
Call Stack (most recent call first):
  CMakeLists.txt:42 (project)


CMake Error: CMake was unable to find a build program corresponding to "Ninja Multi-Config".  CMAKE_MAKE_PROGRAM is not set.  You probably need to select a different build tool.
-- Configuring incomplete, errors occurred!

Hi!
I am facing the same issue. Did you find a workaround for this?
For me it seems like a bug, as the fileDir should be the directory containing the preset, which should be this specific file. Otherwise there should be yet another macro defining this.

Unfortunately not. We ended up moving everything from the toolchain files into the CMakePreset.json of the platform component.

Please let me know if you find a solution :slight_smile: