FASTBuild: Add install_prep targets for minimal builds

Extend the `install_prep/<component>` and `install_prep/all` targets to
the FASTBuild generator.

Co-authored-by: Tyler Yankee <tyler.yankee@kitware.com>
Issue: #27643
This commit is contained in:
Taylor SasserandTyler Yankee authored and Tyler Yankee committed 2026-10-12 13:58:12 -04:00
1 parent 62e4f1577d
commit e36cd0ac29
10 files changed
+136 -9

No files matched your search

+16
View File
@@ -32,6 +32,22 @@ This writes a FASTBuild configuration file named ``fbuild.bff`` into
Built-in Targets
----------------
.. versionadded:: 4.5
If the project has install rules, the generated build file provides the
following targets, unless :variable:`CMAKE_SKIP_INSTALL_PREP_TARGETS` or
:variable:`CMAKE_SKIP_INSTALL_RULES` is enabled:
``install_prep/<component>``
Builds all known build dependencies for the install component named
``<component>`` added by :command:`install`. Components whose names cannot
be represented safely are excluded. See :ref:`Install Preparation Targets`
and :ref:`Target Names`.
``install_prep/all``
Builds all known build dependencies needed for an installation that does
not select a component. See :ref:`Install Preparation Targets`.
.. versionadded:: 4.5
When the :variable:`CMAKE_TEST_BUILD_DEPENDS` variable is enabled, the
+8 -8
View File
@@ -1782,9 +1782,9 @@ target properties with a limited set of names:
Preparation Targets
===================
The :ref:`Ninja Generators` and :ref:`Makefile Generators` provide convenience
targets that build only the prerequisites of a later step, such as running
tests or installing.
The :ref:`Ninja Generators`, :ref:`Makefile Generators`, and
:generator:`FASTBuild` generator provide convenience targets that build only
the prerequisites of a later step, such as running tests or installing.
.. _`Install Preparation Targets`:
@@ -1860,11 +1860,11 @@ and custom targets. How such a file is prepared depends on how it is produced:
* Any other generated file, such as a byproduct or the output of a custom
command attached to more than one target, is prepared by depending on the
file itself, which runs whatever produces it. The
:ref:`Makefile Generators` cannot do so, so they warn. If a target
installs the file (or the file set to which the file belongs), they build
that target instead, which must therefore depend on the producer, e.g.,
through :command:`add_dependencies`. Otherwise, they do not prepare the
file.
:ref:`Makefile Generators` and :generator:`FASTBuild` cannot do so, so they
warn. If a target installs the file (or the file set to which the file
belongs), they build that target instead, which must therefore depend on
the producer, e.g., through :command:`add_dependencies`. Otherwise, they
do not prepare the file.
For example:
+63
View File
@@ -7,6 +7,7 @@
#include <cstdlib>
#include <initializer_list>
#include <iterator>
#include <map>
#include <queue>
#include <cm/memory>
@@ -1588,6 +1589,67 @@ void cmGlobalFastbuildGenerator::AddTargetAll()
this->AddTarget(std::move(allAliasNode));
}
void cmGlobalFastbuildGenerator::WriteInstallPrepTargets()
{
if (!this->AreInstallPrepTargetsEnabled()) {
return;
}
this->CheckInstallPrepTargets();
cmGlobalGenerator::InstallPrepTargets prepTargets =
this->GetInstallPrepTargets(this->GetConfigNames().front());
// FASTBuild target names are case-insensitive, so merge preparation targets
// whose names differ only in case. Each of them then prepares a superset of
// what its installation needs.
std::map<std::string, FastbuildAliasNode> aliases;
std::set<std::string> unownedGeneratedFiles;
auto addAlias =
[this, &aliases, &unownedGeneratedFiles](
std::string const& name,
cmGlobalGenerator::InstallPrepTargets::TargetMap const& targets) {
FastbuildAliasNode& alias = aliases[cmSystemTools::LowerCase(name)];
if (alias.Name.empty()) {
alias.Name = name;
alias.Hidden = false;
}
for (auto const& dependency : targets) {
cmGeneratorTarget const* target = dependency.first;
bool buildTarget =
dependency.second.Normal || dependency.second.InstallArtifact;
// FASTBuild has no node for a generated file that is not the unique
// output of a target, such as a byproduct, so build its installing
// target instead.
for (std::string const& file : dependency.second.GeneratedFiles) {
if (this->CheckInstallPrepGeneratedFile(target, file,
unownedGeneratedFiles)) {
alias.PreBuildDependencies.emplace(
this->ConvertToFastbuildPath(file));
} else if (target->IsInBuildSystem()) {
buildTarget = true;
}
}
if (buildTarget) {
alias.PreBuildDependencies.emplace(target->GetName());
}
}
};
// Add install_prep/all first so that it keeps its spelling.
addAlias("install_prep/all", prepTargets.All);
for (auto const& component : prepTargets.Components) {
addAlias(cmStrCat("install_prep/", component.first), component.second);
}
for (auto& entry : aliases) {
FastbuildAliasNode& alias = entry.second;
if (alias.PreBuildDependencies.empty()) {
alias.PreBuildDependencies.emplace(FASTBUILD_NOOP_FILE_NAME);
}
this->WriteAlias(alias);
}
}
void cmGlobalFastbuildGenerator::WriteTestPrepTargets()
{
if (!this->Makefiles.front()->IsOn("CMAKE_TEST_BUILD_DEPENDS")) {
@@ -1978,6 +2040,7 @@ void cmGlobalFastbuildGenerator::WriteTargets()
*BuildFileStream << "}\n";
}
WriteInstallPrepTargets();
WriteTestPrepTargets();
if (!this->GetCMakeInstance()->GetIsInTryCompile()) {
+1
View File
@@ -543,6 +543,7 @@ public:
void WriteTargetClean();
void AddTargetAll();
void WriteInstallPrepTargets();
void WriteTestPrepTargets();
void AddGlobCheckExec();
+1 -1
View File
@@ -292,7 +292,7 @@ if(CMAKE_GENERATOR MATCHES "Ninja")
-DRunCMake_GENERATOR_IS_MULTI_CONFIG=${_isMultiConfig})
endif()
add_RunCMake_test(InstallParallel)
if(CMAKE_GENERATOR MATCHES "Make|Ninja")
if(CMAKE_GENERATOR MATCHES "Make|Ninja|FASTBuild")
add_RunCMake_test(InstallPrep)
endif()
add_RunCMake_test(CTest)
@@ -0,0 +1 @@
check_prepared(${dependency}_case_dependency)
@@ -6,6 +6,19 @@ install(TARGETS colon_dependency
COMPONENT "Colon:Name"
)
# Component names that differ only in case each get a working preparation
# target, even where the build tool's target names are case-insensitive.
foreach(case IN ITEMS "Mixed;upper" "mixed;lower" "All;all")
list(GET case 0 component)
list(GET case 1 dependency)
add_library(${dependency}_case_dependency STATIC EXCLUDE_FROM_ALL lib.c)
install(TARGETS ${dependency}_case_dependency
ARCHIVE DESTINATION lib
COMPONENT ${component}
EXCLUDE_FROM_ALL
)
endforeach()
# Components whose names are not representable get no preparation target,
# which is diagnosed when they have build dependencies.
add_library(unsafe_dependency STATIC EXCLUDE_FROM_ALL lib.c)
@@ -0,0 +1,13 @@
^CMake Warning \(author\) at GeneratedByDependency\.cmake:[0-9]+ \(add_library\):
Target "generated_headers" installs file
[^
]*/GeneratedByDependency-build/generated\.h
which is generated but is not the unique output of a build target, so
"install_prep/" targets cannot build it with this generator\. They build
target "generated_headers" instead, which must depend on the target that
produces the file \(for example via add_dependencies\)\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
This warning is for project developers\. Use -Wno-author to suppress it\.$
@@ -0,0 +1,11 @@
^CMake Warning \(author\) at GeneratedFilesByproduct\.cmake:[0-9]+ \(install\):
An install rule installs or depends on file
[^
]*/GeneratedFilesByproduct-build/byproduct\.txt
which is generated but is not the unique output of a build target, so
"install_prep/" targets cannot build it with this generator\..*
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
This warning is for project developers\. Use -Wno-author to suppress it\.$
@@ -65,6 +65,8 @@ macro(configure_install_prep test config)
set(stderr_variant "")
if(RunCMake_GENERATOR MATCHES "Make")
set(stderr_variant make)
elseif(RunCMake_GENERATOR STREQUAL "FASTBuild")
set(stderr_variant fastbuild)
endif()
if(stderr_variant AND
EXISTS "${RunCMake_SOURCE_DIR}/${test}-stderr-${stderr_variant}.txt")
@@ -152,6 +154,13 @@ block()
run_missing_install_prep(ComponentNames-empty-segment
install_prep/Empty//Segment)
run_missing_install_prep(ComponentNames-dot install_prep/./Dot)
foreach(case IN ITEMS "Mixed;upper" "mixed;lower" "All;all")
list(GET case 0 component)
list(GET case 1 dependency)
set(RunCMake-check-file ComponentNames-case-build-check.cmake)
run_cmake_command(ComponentNames-case-${dependency}-build ${CMAKE_COMMAND}
--build . --config Debug --target install_prep/${component})
endforeach()
endblock()
function(run_configured_install_prep test config)