Search code examples
jsoncmakecmake-presets

Use value defined in another json inside CMakePresets.json


I need to define some properties in a .json file, that must be used inside a CMakePresets.json. This because the CMakePresets.json that I use in my pc is different from the one that I use in the build machine, but some properties (like library versions) are the same and I want to avoid to duplicate those information because I'll forgot to update both files.

So I've created a CMakeCommon.json file that contains:

{
  "version": 5,
  "cmakeMinimumRequired": {
    "major": 3,
    "minor": 25,
    "patch": 1
  },
  "configurePresets": [
    {
      "cacheVariables": {
        "MYLIB_VERSION": "1_0"
      }
    }
  ]
}

and my CMakePresets.json is:

{
  "version": 5,
  "cmakeMinimumRequired": {
    "major": 3,
    "minor": 25,
    "patch": 1
  },
  "include": [
    "CMakeCommon.json"
  ],
  "configurePresets": [
    {
      "name": "default",
      "displayName": "Default Config",
      "description": "Default config generator with ninja",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/${presetName}",
      "hidden": true,
      "cacheVariables": {
        "CMAKE_TOOLCHAIN_FILE": "MyPath/vcpkg/scripts/buildsystems/vcpkg.cmake",
        "VCPKG_DEFAULT_TRIPLET": "x64-windows",
        "CMAKE_EXPORT_COMPILE_COMMANDS": "TRUE",
        "MYLIB_PATH": "D:/MyLib/${MYLIB_VERSION}"
      },
      "environment": {
      }
    },
    {
      "inherits": "default",
      "name": "debug",
      "displayName": "Debug",
      "description": "Debug build.",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug"
      }
    },
    {
      "inherits": "default",
      "name": "release",
      "displayName": "Release",
      "description": "Release build.",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    }
  ],
  "buildPresets": [
    {
      "name": "Debug",
      "configurePreset": "debug"
    },
    {
      "name": "Release",
      "configurePreset": "release"
    }
  ],
  "testPresets": [ ]
}

I cannot use MYLIB_VERSION variable defined in CMakeCommon.json inside the cache variable MYLIB_PATH defined in CMakePresets.json.

Is there a way to achieve this result?


Solution

  • There are two issues with your current implementation: You need to give the preset in the CMakeCommon.json file a name, and then have the default preset in CMakePresets.json to inherit from it, otherwise how would the default preset know to use the value of MYLIB_VERSION from there.

    The second issue is that ${MYLIB_VERSION} in the default preset in CMakePresets.json is not a valid macro expansion. Currently, there is no way to access cache variables of presets you inherited from through macro expansion, only environment variables can be referenced. So you need to make MYLIB_VERSION an environment variable in CMakeCommon.json and then use $env{MYLIB_VERSION} instead of ${MYLIB_VERSION}

    All in all it would look something like this:

    CMakeCommon.json:

    {
      "version": 5,
      "cmakeMinimumRequired": {
        "major": 3,
        "minor": 25,
        "patch": 1
      },
      "configurePresets": [
        {
          "name": "common",
          "hidden": true,
          "environment": {
            "MYLIB_VERSION": "1_0"
          }
        }
      ]
    }
    

    CMakePresets.json:

    {
      "version": 5,
      "cmakeMinimumRequired": {
        "major": 3,
        "minor": 25,
        "patch": 1
      },
      "include": [
        "CMakeCommon.json"
      ],
      "configurePresets": [
        {
          "name": "default",
          "inherits": "common",
          "displayName": "Default Config",
          "description": "Default config generator with ninja",
          "generator": "Ninja",
          "binaryDir": "${sourceDir}/build/${presetName}",
          "hidden": true,
          "cacheVariables": {
            "CMAKE_TOOLCHAIN_FILE": "MyPath/vcpkg/scripts/buildsystems/vcpkg.cmake",
            "VCPKG_DEFAULT_TRIPLET": "x64-windows",
            "CMAKE_EXPORT_COMPILE_COMMANDS": "TRUE",
            "MYLIB_PATH": "D:/MyLib/$env{MYLIB_VERSION}"
          },
          "environment": {
          }
        },
        {
          "inherits": "default",
          "name": "debug",
          "displayName": "Debug",
          "description": "Debug build.",
          "cacheVariables": {
            "CMAKE_BUILD_TYPE": "Debug"
          }
        },
        {
          "inherits": "default",
          "name": "release",
          "displayName": "Release",
          "description": "Release build.",
          "cacheVariables": {
            "CMAKE_BUILD_TYPE": "Release"
          }
        }
      ],
      "buildPresets": [
        {
          "name": "Debug",
          "configurePreset": "debug"
        },
        {
          "name": "Release",
          "configurePreset": "release"
        }
      ],
      "testPresets": [ ]
    }
    

    If you need MYLIB_VERSION to be a cache variable you can also add it back to the cache variables pf the common preset, but set the value to $env{MYLIB_VERSION} so you don't have to duplicate the version number.

    I'd also like to point out that CMake actually has a built-in mechanism for this exact issue of needing machine-specific presets. If you rename your current CMakePresets.json file to CMakeUserPresets.json and the CMakeCommon.json file to CMakePresets.json then you can remove the include from the file that is now CMakeUserPresets.json and get the same behavior, but with the standard names.