FASTBuild: Generate test_prep/ targets for test build dependencies

Issue: #27879
This commit is contained in:
Martin Duffy
2026-06-16 16:50:13 -04:00
parent 88072f17fe
commit 2d417b9371
6 changed files with 79 additions and 7 deletions

View File

@@ -63,7 +63,8 @@ directory the test is created in.
* .. versionadded:: 4.4
When the :variable:`CMAKE_TEST_BUILD_DEPENDS` variable is enabled,
the :ref:`Ninja Generators` generate a convenience build target named
the :ref:`Ninja Generators` and :generator:`FASTBuild` generate a
convenience build target named
``test_prep/<name>`` that depends on the test executable target. Building
this target ensures the executable is up-to-date before the test runs.
@@ -79,6 +80,10 @@ directory the test is created in.
The ``BUILD_DEPENDS`` keyword can be used to add explicit build
dependencies.
.. versionchanged:: 4.5
:generator:`FASTBuild` gained support for ``test_prep/<name>`` targets.
The command may be specified using
:manual:`generator expressions <cmake-generator-expressions(7)>`.
@@ -96,9 +101,9 @@ directory the test is created in.
Specify a list of targets or files that must be built before the test can
run. Each dependency is added to the ``test_prep/<name>`` build target
described above when :variable:`CMAKE_TEST_BUILD_DEPENDS` is enabled
with the :ref:`Ninja Generators`. The test name must be a valid target name
in order to list build dependencies with this keyword.
described above when :variable:`CMAKE_TEST_BUILD_DEPENDS` is enabled with
the :ref:`Ninja Generators` or :generator:`FASTBuild`. The test name must be
a valid target name in order to list build dependencies with this keyword.
``COMMAND_EXPAND_LISTS``
.. versionadded:: 3.16

View File

@@ -3,8 +3,13 @@ CMAKE_TEST_BUILD_DEPENDS
.. versionadded:: 4.4
.. versionchanged:: 4.5
:generator:`FASTBuild` gained support for ``test_prep/<name>`` targets.
Enable ``test_prep/<name>`` build targets for tests added by
:command:`add_test` when using the :ref:`Ninja Generators`.
:command:`add_test` when using the :ref:`Ninja Generators` or
:generator:`FASTBuild`.
When this variable is set to a true value, CMake generates a
``test_prep/<name>`` target for each eligible test and a ``test_prep/all``

View File

@@ -32,6 +32,8 @@
#include "cmStateSnapshot.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTest.h"
#include "cmTestGenerator.h"
#include "cmValue.h"
#include "cmVersion.h"
#include "cmake.h"
@@ -1583,6 +1585,62 @@ void cmGlobalFastbuildGenerator::AddTargetAll()
this->AddTarget(std::move(allAliasNode));
}
void cmGlobalFastbuildGenerator::WriteTestPrepTargets()
{
if (!this->Makefiles.front()->IsOn("CMAKE_TEST_BUILD_DEPENDS")) {
return;
}
struct TestPrepTarget
{
std::string Comment;
std::set<FastbuildTargetDep> Dependencies;
};
std::map<std::string, TestPrepTarget> testPrepTargets;
for (auto const& localGen : this->LocalGenerators) {
auto const& testGenerators = localGen->GetMakefile()->GetTestGenerators();
for (auto const& tester : testGenerators) {
cmTestGenerator::BuildDependencies testDeps;
if (!tester->GetBuildDependencies(localGen.get(), testDeps)) {
continue;
}
std::string const depName =
cmStrCat("test_prep/", tester->GetTest()->GetName());
auto& testPrepTarget = testPrepTargets[depName];
testPrepTarget.Comment =
cmStrCat("Build dependencies for test ", tester->GetTest()->GetName());
for (cmGeneratorTarget* depTarget : testDeps.Targets) {
testPrepTarget.Dependencies.emplace(depTarget->GetName());
}
for (std::string const& depFile : testDeps.Files) {
testPrepTarget.Dependencies.emplace(depFile);
}
}
}
FastbuildAliasNode allAliasNode;
allAliasNode.Name = "test_prep/all";
allAliasNode.Hidden = false;
for (auto& prepEntry : testPrepTargets) {
FastbuildAliasNode alias;
alias.Name = prepEntry.first;
alias.Hidden = false;
alias.PreBuildDependencies = std::move(prepEntry.second.Dependencies);
if (alias.PreBuildDependencies.empty()) {
alias.PreBuildDependencies.emplace(FASTBUILD_NOOP_FILE_NAME);
}
this->WriteComment(prepEntry.second.Comment);
this->WriteAlias(alias);
allAliasNode.PreBuildDependencies.emplace(prepEntry.first);
}
if (!allAliasNode.PreBuildDependencies.empty()) {
this->WriteComment("Build dependencies for all tests");
this->WriteAlias(allAliasNode);
}
}
void cmGlobalFastbuildGenerator::AddGlobCheckExec()
{
// Tested in "RunCMake.file" test.
@@ -1875,6 +1933,8 @@ void cmGlobalFastbuildGenerator::WriteTargets()
*BuildFileStream << "}\n";
}
WriteTestPrepTargets();
if (!this->GetCMakeInstance()->GetIsInTryCompile()) {
if (!IDEProjects.empty()) {
this->WriteIDEProjects();

View File

@@ -543,6 +543,7 @@ public:
void WriteTargetClean();
void AddTargetAll();
void WriteTestPrepTargets();
void AddGlobCheckExec();
void AddCompiler(std::string const& lang, cmMakefile* mf);

View File

@@ -71,7 +71,7 @@ function(run_testdependency_case CASE_NAME EXPECT_PRESENT)
unset(RunCMake_TEST_NO_CLEAN)
endfunction()
if(RunCMake_GENERATOR MATCHES Ninja)
if(RunCMake_GENERATOR MATCHES "Ninja|FASTBuild")
block()
run_testdependency_case(DEFAULT FALSE)
run_testdependency_case(OFF FALSE)

View File

@@ -8,7 +8,8 @@ endif()
file(GLOB ninja_files LIST_DIRECTORIES false
"${RunCMake_TEST_BINARY_DIR}/*.ninja"
"${RunCMake_TEST_BINARY_DIR}/*.ninja.in")
"${RunCMake_TEST_BINARY_DIR}/*.ninja.in"
"${RunCMake_TEST_BINARY_DIR}/fbuild.bff")
set(found FALSE)
foreach(ninja_file IN LISTS ninja_files)