Skip to content

Support CMake presets and CTest in the CMake tool wrapper #725

Open

Description

@Illustar0

Description

Support CMake presets and CTest in the CMake tool wrapper.

Projects that build with CMake today mostly describe their configurations in CMakePresets.json (generator, binary directory, toolchain, cache variables) and drive them with cmake --preset, cmake --build --preset and ctest --preset. The CMake wrapper in Fallout.Common has no way to express this:

  • CMakeGenerate, CMakeBuild and CMakeInstall have no Preset property, and there is no wrapper for cmake --workflow --preset.
  • The defaults assume a preset-less Visual Studio build: CMakeGenerate always passes -G "Visual Studio 16 2019" -A x64 -S . -B ./out, and CMakeBuild always passes ./out --config Debug. With a preset these either override it (-G beats the preset's Ninja generator) or make the command invalid (cmake --build ./out --preset x). Each one has to be removed with ResetGenerator(), ResetPlatform(), ResetRootDirectory(), ResetOutputDirectory() and so on.
  • There is no CTest wrapper at all, so tests that CMake registers have to run through ToolResolver.GetPathTool("ctest").

Usage Example

Target Compile => _ => _
    .Executes(() =>
    {
        CMakeGenerate(s => s
            .SetPreset(Preset)
            .AddDefine($"MY_LIBRARY={LibraryPath}"));
        CMakeBuild(s => s.SetPreset(Preset));
    });

Target Test => _ => _
    .DependsOn(Compile)
    .Executes(() => CTest(s => s
        .SetPreset(Preset)
        .EnableOutputOnFailure()));

Target Install => _ => _
    .DependsOn(Compile)
    .Executes(() => CMakeBuild(s => s
        .SetPreset(Preset)
        .SetTarget("install")));

Setting a preset would only leave out the defaults that the preset owns, i.e. generator, platform, source and binary directories, and the configuration of a single-config generator. Values that the build sets explicitly would still be passed, and CMake applies them over the preset's own. For example, this uses a preset but picks the generator and binary directory itself:

CMakeGenerate(s => s
    .SetPreset(Preset)
    .SetGenerator("Ninja Multi-Config")
    .SetOutputDirectory(RootDirectory / "out" / Preset));

Without a preset, the defaults would stay as they are, so existing builds keep working.

Without a preset

The current defaults get in the way here too:

  • -G "Visual Studio 16 2019" is passed unless reset, so CMake never picks a generator itself, whether from the CMAKE_GENERATOR environment variable or from the platform's default. Visual Studio 2019 is also several versions old by now.
  • -A x64 is passed with any generator. SetGenerator(CMakeGenerator.Ninja) alone therefore fails, since Ninja and Makefile generators reject a platform, and has to be paired with ResetPlatform().

So the wrapper should have no defaults for generator, platform, source and binary directory, and configuration, and pass only what the build sets, as the cmake command line does. This changes existing builds that rely on the defaults, so it would have to wait for a breaking release.

Alternative

What we do now is skip the wrapper and call the executables directly:

Tool CMake => ToolResolver.GetPathTool("cmake");
Tool CTest => ToolResolver.GetPathTool("ctest");

CMake($"--preset {Preset} -DMY_LIBRARY={LibraryPath}", workingDirectory: SourceDirectory, environmentVariables: MsvcEnvironment);
CMake($"--build --preset {Preset}", workingDirectory: SourceDirectory, environmentVariables: MsvcEnvironment);
CTest($"--preset {Preset}", workingDirectory: SourceDirectory, environmentVariables: MsvcEnvironment);

This works, but it gives up typed settings, and every build repeats the same argument strings.

A related gap: Ninja presets with MSVC need the Visual Studio developer environment. Fallout can find Visual Studio through VSWhere, but each build still runs VsDevCmd.bat ... && set and parses the output to get an environment to pass to the tools. If that is in scope, it could be a separate issue.

Could you help with a pull-request?

Yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions