Search code examples
cmakecmake-presets

Why is this CMake preset available on Windows when it inherits a condition that should fail on Windows?


From this answer and this link, I understand that CMake presets currently will not compose conditions if the inheriting preset and inherited preset both define conditions.

I tried working around this with "multiple inheritance" where two discrete presets implement two discrete conditions, and the inheriting preset does not implement any presets, as follows:

{
  "version": 3,
  "cmakeMinimumRequired": {
    "major": 3,
    "minor": 20
  },
  "configurePresets": [
    {
      "name": "fail_if_no_foo",
      "displayName": "Fail if no FOO",
      "description": "Demo failing if environment variable FOO is unset",
      "binaryDir": "${sourceDir}/build",
      "generator": "Unix Makefiles",
      "condition": {
        "type": "allOf",
        "conditions": [
          {
            "type": "notEquals",
            "lhs": "$penv{FOO}",
            "rhs": ""
          }
        ]
      }
    },
    {
      "name": "fail_if_not_linux",
      "displayName": "Fail if not Linux",
      "description": "Demo failing if the host is not Linux",
      "condition": {
        "type": "allOf",
        "conditions": [
          {
            "type": "equals",
            "lhs": "${hostSystemName}",
            "rhs": "Linux"
          }
        ]
      }
    },
    {
      "name": "inherited_preset",
      "displayName": "Inherited fail if no FOO and fail if not Linux",
      "description": "Demo multiple inherited conditions",
      "inherits": [
        "fail_if_no_foo",
        "fail_if_not_linux"
      ]
    }
  ]
}

The behavior on Linux gave me hope that it worked; it implements the desired behavior of "hiding" a preset if the conditions are not met. Practically, on Linux, there is only one applicable condition: whether or not FOO is defined in the parent environment:

$ uname -s
Linux
$
$ cmake --list-presets
Available configure presets:

  "fail_if_not_linux" - Fail if not Linux
$
$ FOO=bar cmake --list-presets
Available configure presets:

  "fail_if_no_foo"    - Fail if no FOO
  "fail_if_not_linux" - Fail if not Linux
  "inherited_preset"  - Inherited fail if no FOO and fail if not Linux
$

But, on Windows, the behavior is not as desired.
On Windows, I would have expected that fail_if_no_foo is only available when parent environment variable FOO is set, but that fail_if_not_linux and inherited_preset are never available, because the "fail if not Linux" condition should apply to both.
What I actually observe: when FOO is not set, no presets are available, which is good, but when FOO is set, both fail_if_no_foo and inherited_preset become available:

c:\dev\cmake-learn\preset_multiple_conditions_with_multiple_inheritance>cmake --list-presets

c:\dev\cmake-learn\preset_multiple_conditions_with_multiple_inheritance>set FOO=bar

c:\dev\cmake-learn\preset_multiple_conditions_with_multiple_inheritance>cmake --list-presets
Available configure presets:

  "fail_if_no_foo"   - Fail if no FOO
  "inherited_preset" - Inherited fail if no FOO and fail if not Linux

c:\dev\cmake-learn\preset_multiple_conditions_with_multiple_inheritance>

Is this the same issue already covered at the linked CMake issue?
Is the issue, ultimately, that you cannot "compose" multiple conditions, whether strictly from inherited presets, or from a combination of inherited presets and the inheriting preset?

The terminology at the linked CMake issue is a little tough for me to understand if that asker's issue is the same as mine: I don't quite understand what "nodes" and "active presets" are.


Update: please note, with this question, the observed behavior on Linux is different than what was observed with my prior, related question. But I still have a nagging feeling the issues are "related." I just can't tell if the two issues have the same root cause, thereby whether this is a dupe or not. This is the behavior from this CMakePresets, if readers want to compare to the linked question:

$ cmake --preset fail_if_no_foo
CMake Error: Could not use disabled preset "fail_if_no_foo"
$
$ FOO=bar cmake --preset fail_if_no_foo
-- Configuring done
-- Generating done
-- Build files have been written to: /home/user/dev/cmake-learn/preset_multiple_conditions_with_multiple_inheritance/build
$
$ cmake --preset inherited_preset
CMake Error: Could not use disabled preset "inherited_preset"
$
$ FOO=bar cmake --preset inherited_preset
-- Configuring done
-- Generating done
-- Build files have been written to: /home/user/dev/cmake-learn/preset_multiple_conditions_with_multiple_inheritance/build
$

Here, the behavior in Linux looks "correct."
At the linked question, the inheriting preset enforced its inherited preset, but failed to enforce its own preset.
Here, it's not clear to me if the inheriting preset is correctly enforcing both inherited conditions, or if the "fail if Linux" condition is just being ignored.


Solution

  • Is this the same issue already covered at the linked CMake issue?

    Yes. In the CMake issue the current behavior with multiple inheritance is described as

    In case of multiple inheritance, always the first child providing a condition appears to "win" and provide the effective condition.

    Which is exactly what you're seeing: Only fail_if_no_foo is taken into account, because it is the first inherited preset with a condition.