Invalid workflow step on cmake preset

In the following preset file:

{
    "version": 10,
    "cmakeMinimumRequired": {
        "major": 3,
        "minor": 31,
        "patch": 0
    },
    "configurePresets": [
        {
            "name": "common-configure-settings",
            "description": "Options and CMake settings common to all configure presets",
            "binaryDir": "${sourceDir}/build/${presetName}",
            "hidden": true
        },
        {
            "name": "ninja-multi",
            "hidden": true,
            "generator": "Ninja Multi-Config"
        },
        {
            "name": "release",
            ...
        },
        {
            "name": "debug",
            "displayName": "Debug",
            "hidden": true,
            "inherits": "common-configure-settings",
            "cacheVariables": {
                "CMAKE_BUILD_TYPE": "Debug"
            }
        },
        {
            "name": "cpp-std",
            "description": "This preset makes sure the project actually builds with at least the specified standard",
            "hidden": true,
            "cacheVariables": {
                "CMAKE_CXX_EXTENSIONS": "OFF",
                "CMAKE_CXX_STANDARD": "20",
                "CMAKE_CXX_STANDARD_REQUIRED": "ON"
            }
        },
        {
            "name": "cpp-build",
            "hidden": true,
            "inherits": ["release"],
            "cacheVariables": {
                "CMAKE_CXX_FLAGS": "$env{CXX_WARNINGS} $env{CXX_OPT}"
            }
        },
        {
            "name": "linux",
            "hidden": false,
            "inherits": ["cpp-std", "cpp-build", "ninja-multi"],
            "description": "Build preset for Linux",
            "environment": {
                "CXX_WARNINGS": "-Wall -Wextra -Werror -pedantic",
                "CXX_OPT": "-fsized-deallocation -fno-math-errno -march=x86-64-v3",
                "PLATFORM": "POSIX64"
            },
            "condition": {
                "type": "equals",
                "lhs": "${hostSystemName}",
                "rhs": "Linux"
            }
        },
        {
            "name": "development",
            "displayName": "Development Build",
            "hidden": false,
            "inherits": [
                "debug",
                "ninja-multi"
            ]
        }
    ],
    "buildPresets": [
        {
            "name": "development-build",
            "configurePreset": "development"
        },
        {
            "name": "linux-build",
            "configurePreset": "linux"
        }
    ],
    "testPresets": [
        {
            "name": "test-all",
            ...
        }
    ],
    "packagePresets": [
        {
            "name": "default-linux-package",
            "configurePreset": "linux",
            "generators": [
                "TGZ"
            ]
        }
    ],
    "workflowPresets": [
        {
            "name": "test",
            "steps": [
                {
                    "type": "configure",
                    "name": "development"
                },
                {
                    "type": "build",
                    "name": "development-build"
                },
                {
                    "type": "test",
                    "name": "test-all"
                }
            ]
        },
        {
            "name": "release",
            "steps": [
                {
                    "type": "configure",
                    "name": "linux"
                },
                {
                    "type": "build",
                    "name": "linux-build"
                },
                {
                    "type": "test",
                    "name": "test-all"
                },
                {
                    "type": "package",
                    "name": "default-linux-package"
                }
            ]
        }
    ]
}

I get the error: Invalid workflow step "linux". What is the exact reason for the error in this particular step?

This is subtle, but I think it’s because your preset names change throughout the workflow.

The problem with using a binaryDir value like "${sourceDir}/build/${presetName}" is that that’ll be evaluated for each preset that inherits it. So, in your "test" workflow, the configuration binary dir will be <sourcedir>/build/development/, the build binary dir will be <sourcedir>/build/development-build, and the test binary dir will be <sourcedir>/build/test-all. In the release workflow, it’ll be <sourcedir>/build/{linux, linux-build, test-all, default-linux-package} in order, for the four steps.

That won’t work, obviously, because those build/test/package binary directories won’t exist or have a generated CMake build system inside them. It’s strange and unhelpful that the errror is manifesting the way it is, but I believe that’s the reason. If you’re going to use a binaryDir based on ${presetName}, you need all of your presets to be named the same for each step of the workflow. This workflow definition loads successfully, if you rename/create all of the corresponding referenced presets accordingly:

    "workflowPresets": [
        {
            "name": "test-all",
            "steps": [
                {
                    "type": "configure",
                    "name": "test"
                },
                {
                    "type": "build",
                    "name": "test"
                },
                {
                    "type": "test",
                    "name": "test"
                }
            ]
        },
        {
            "name": "linux-build",
            "steps": [
                {
                    "type": "configure",
                    "name": "linux"
                },
                {
                    "type": "build",
                    "name": "linux"
                },
                {
                    "type": "test",
                    "name": "linux"
                },
                {
                    "type": "package",
                    "name": "linux"
                }
            ]
        }
    ]

(Note that it’s not an issue if you, say, hardcode the binaryDir to ${sourceDir}/build/debug in the debug configPreset, and ${sourceDir}/build/release in the release configPreset. Then, as long as all of your presets inherit from one of those, you can name them whatever you want.)

Edit: Actually, it’s slightly more strict than that — each preset in the workflow, at every step, also has to have the same "configurePreset" value — just “inherits the same definition” doesn’t appear to be enough.

But as long as all of the configurePresets match, and the binaryDir isn’t based on the ${presetName}, then you’re OK to name them whatever.

Edit2: And, yeah, the error reporting on all of this is woefully inadequate. Not only does "Invalid workflow step "<name>" completely fail to give any indication what, exactly, is “invalid” about the workflow, but it will typically give the name of the "configure" step as the “invalid” one.

By definition, "configure" is the one step that can’t be invalid. It’s when one of the later steps has a configurePreset that doesn’t match the configurePreset named in the "configure" step, that the workflow is invalidated.

1 Like

This makes perfect sense, although I agree the error does not help you much in pinpointing the issue. In this case I will make sure that all steps use the same build path. Thank you so much for pointing that out.

Do I need to additionally instruct the build-system where the build folder is, or am I missing some additional configuration step?

My presets now look a bit like this:

{
    "version": 9,
    "cmakeMinimumRequired": {
        "major": 3,
        "minor": 30,
        "patch": 0
    },
    "configurePresets": [
        {
            "name": "common-configure-settings",
            "description": "Options and CMake settings common to all configure presets",
            "binaryDir": "${sourceDir}/build/${presetName}",
            "hidden": true
        },
        {
            "name": "ninja",
            "hidden": true,
            "generator": "Ninja"
        },
        {
            "name": "linux",
            "hidden": false,
            "inherits": ["ninja"],
            "description": "Build preset for Linux",
            "environment": {
                "CXX_WARNINGS": "-Wall -Wextra -Werror -pedantic",
                "PLATFORM": "POSIX64"
            },
            "condition": {
                "type": "equals",
                "lhs": "${hostSystemName}",
                "rhs": "Linux"
            }
        }
    ]
}

And I’m trying to create an action that builds this app using the following workflow:

name: build-linux

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

permissions:
  contents: read
  packages: read

jobs:
  build:
    runs-on: ubuntu-latest
    if: github.ref_name == 'main'
    steps:
    - uses: actions/checkout@v4
      with:
        token: ${{ secrets.GITHUB_TOKEN }}

    - uses: cachix/install-nix-action@v27
      with:
        extra_nix_config: |
          access-tokens = github.com=${{ secrets.GH_TOKEN }}

    - name: Build
      working-directory: ${{github.workspace}}
      run: nix build
      env:
        NIX_CONFIG: "access-tokens = github.com=${{ secrets.GH_TOKEN }}"

But it fails with the following message:

error: builder for '/nix/store/vj6wfq1lafh59wk7wkfa02q19hwfchkz-myapp.drv' failed with exit code 1;
last 25 log lines:
>  * USE_CERES, Use the non-linear least squares optimizer from Ceres solver to tune model coefficients (if OFF, Eigen::LevenbergMarquardt will be used instead).
>
> -- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY
> -- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY - Success
> -- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY
> -- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY - Success
> -- Performing Test COMPILER_HAS_DEPRECATED_ATTR
> -- Performing Test COMPILER_HAS_DEPRECATED_ATTR - Failed
> -- Performing Test COMPILER_HAS_DEPRECATED
> -- Performing Test COMPILER_HAS_DEPRECATED - Failed
> -- Configuring done (1.7s)
> -- Generating done (0.0s)
> CMake Warning:
>   Manually-specified variables were not used by the project:
>
>     CMAKE_EXPORT_NO_PACKAGE_REGISTRY
>     CMAKE_POLICY_DEFAULT_CMP0025
>
> 
> -- Build files have been written to: /build/a75cv3clh1z9k7cg9hrnhi5m2z3hcgcm-source/build/linux
> cmake: enabled parallel building
> cmake: enabled parallel installing
> Running phase: buildPhase
> build flags: -j2
> ninja: error: loading 'build.ninja': No such file or directory
For full logs, run 'nix log /nix/store/vj6wfq1lafh59wk7wkfa02q19hwfchkz-myapp.drv'.

@greenleafone7

Yeah, I have no idea what nix build does, is the thing.

You might want to try running the workflow manually first, with cmake --workflow --preset <workflowname>, to see if that works correctly. If it does, your question becomes about nix build instead, and this probably isn’t the best place to get help with that.

But normally, if all of your presets at every level have the same name, and they all reference the same "configurePreset": that also has the same name, it should use the correct binaryDir at each step in the workflow.

The workflow works just fine now that I think of it. I have no idea why I asked here, it can’t possibly be it :stuck_out_tongue:

1 Like

So the issue I think is me trying to define: "binaryDir": "${sourceDir}/build/${presetName}" on my presets, and at the same time having:

    - name: Build
      working-directory: ${{github.workspace}}
      run: nix build

on my action. If I remove the binaryDir instruction then it works. So I either need to remove that, or tell the github runner where the actual workspace is.