mirror of
https://github.com/Kitware/CMake.git
synced 2026-11-06 05:16:58 +00:00
Makefile: Add install_prep targets for minimal builds
Extend the `install_prep/<component>` and `install_prep/all` targets to the Makefile generators. Some differences compared to the implementation for Ninja: * A Makefile rule name cannot contain `:`, so components whose names contain one get no preparation target. * A top-level rule cannot build an individual custom command output, so a generated file to be installed is prepared by building the target that owns its custom command. * When a target must be relinked before installation, its `preinstall` rule is built after its `all` rule. * Where the make tool matches target names case-insensitively, components whose names differ only in case share a preparation target, as done for `test_prep/`. Co-authored-by: Tyler Yankee <tyler.yankee@kitware.com> Issue: #27643
This commit is contained in:
1 parent
0ea2d28b54
commit
62e4f1577d
14 files changed
+407
-12
No files matched your search
@@ -30,6 +30,23 @@ be created, containing the following targets:
|
||||
``package``
|
||||
Runs the package step in the subdirectory, if any.
|
||||
|
||||
.. versionadded:: 4.5
|
||||
|
||||
If the project has install rules, the top-level makefile additionally
|
||||
provides the following targets, unless the
|
||||
:variable:`CMAKE_SKIP_INSTALL_PREP_TARGETS` or
|
||||
:variable:`CMAKE_SKIP_INSTALL_RULES` variable 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
|
||||
|
||||
@@ -75,7 +75,8 @@ Some convenience targets derive their names from other names in the project:
|
||||
and :variable:`CMAKE_TEST_BUILD_DEPENDS`.
|
||||
* The ``install_prep/<component>`` targets use install component names.
|
||||
A component name may contain the characters allowed in target names above,
|
||||
plus ``:`` and ``/``. See also :ref:`Install Preparation Targets`.
|
||||
plus ``:`` and ``/``. The :ref:`Makefile Generators` do not allow ``:``.
|
||||
See also :ref:`Install Preparation Targets`.
|
||||
|
||||
.. _`Executables`:
|
||||
|
||||
@@ -1781,8 +1782,9 @@ target properties with a limited set of names:
|
||||
Preparation Targets
|
||||
===================
|
||||
|
||||
The :ref:`Ninja Generators` provide convenience targets that build only the
|
||||
prerequisites of a later step, such as running tests or installing.
|
||||
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.
|
||||
|
||||
.. _`Install Preparation Targets`:
|
||||
|
||||
@@ -1852,11 +1854,17 @@ and custom targets. How such a file is prepared depends on how it is produced:
|
||||
* A file that is the output of a custom command attached to exactly one
|
||||
target is prepared by running that custom command. The target which
|
||||
installs the file (or the file set to which the file belongs), if any, is
|
||||
not built.
|
||||
not built. The :ref:`Makefile Generators` cannot depend on individual
|
||||
files, so they build the target owning the custom command instead.
|
||||
|
||||
* 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.
|
||||
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.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -1869,7 +1877,8 @@ For example:
|
||||
set_property(TARGET A PROPERTY PUBLIC_HEADER
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/generated.h")
|
||||
|
||||
# Preparation runs gen, the producer of the byproduct.
|
||||
# Preparation runs gen, or with some generators builds B instead, so B
|
||||
# must depend on the producer of its byproduct.
|
||||
add_custom_target(gen COMMAND ...
|
||||
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/byproduct.h")
|
||||
add_library(B b.c)
|
||||
|
||||
@@ -3616,6 +3616,28 @@ void cmGlobalGenerator::CheckInstallPrepTargets()
|
||||
}
|
||||
}
|
||||
|
||||
bool cmGlobalGenerator::CheckInstallPrepGeneratedFile(
|
||||
cmGeneratorTarget const* target, std::string const& file,
|
||||
std::set<std::string>& diagnosed)
|
||||
{
|
||||
if (this->FindOutputOwningTarget(file)) {
|
||||
return true;
|
||||
}
|
||||
if (diagnosed.insert(file).second) {
|
||||
target->GetLocalGenerator()->IssueDiagnostic(
|
||||
cmDiagnostics::CMD_AUTHOR,
|
||||
cmStrCat("Target \"", target->GetName(), "\" installs file\n ", file,
|
||||
"\nwhich 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 \"",
|
||||
target->GetName(),
|
||||
"\" instead, which must depend on the target that produces "
|
||||
"the file (for example via add_dependencies)."),
|
||||
target->GetBacktrace());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cmGlobalGenerator::AreInstallPrepTargetsEnabled() const
|
||||
{
|
||||
return !this->Makefiles.empty() && this->InstallTargetEnabled &&
|
||||
|
||||
@@ -174,6 +174,14 @@ public:
|
||||
// Generators that write install preparation targets call this once.
|
||||
void CheckInstallPrepTargets();
|
||||
|
||||
// Whether a generated file to be prepared for installation is the unique
|
||||
// output of a target. Generators that cannot depend on a file with no such
|
||||
// owner build its installing target instead, and call this to diagnose it
|
||||
// once per file.
|
||||
bool CheckInstallPrepGeneratedFile(cmGeneratorTarget const* target,
|
||||
std::string const& file,
|
||||
std::set<std::string>& diagnosed);
|
||||
|
||||
bool AreInstallPrepTargetsEnabled() const;
|
||||
|
||||
/** Check whether the given name matches the current generator. */
|
||||
|
||||
@@ -96,6 +96,14 @@ void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
|
||||
gt->ObjectDirectory = dir;
|
||||
}
|
||||
|
||||
bool cmGlobalUnixMakefileGenerator3::IsInstallPrepComponentRepresentable(
|
||||
std::string const& component) const
|
||||
{
|
||||
// A Makefile rule name cannot contain ':'.
|
||||
return component.find(':') == std::string::npos &&
|
||||
this->cmGlobalGenerator::IsInstallPrepComponentRepresentable(component);
|
||||
}
|
||||
|
||||
bool cmGlobalUnixMakefileGenerator3::CanEscapeOctothorpe() const
|
||||
{
|
||||
// Make tools that use UNIX-style '/' paths also support '\' escaping.
|
||||
@@ -118,9 +126,10 @@ void cmGlobalUnixMakefileGenerator3::Generate()
|
||||
this->TestPrepTargets.clear();
|
||||
this->TestPrepEnabled = false;
|
||||
|
||||
// Compute the "test_prep/" targets before generating the local makefiles
|
||||
// so they can be emitted in a single pass.
|
||||
// Compute the "test_prep/" and "install_prep/" targets before generating the
|
||||
// local makefiles so they can be emitted in a single pass.
|
||||
this->ComputeTestPrepTargets();
|
||||
this->ComputeInstallPrepTargets();
|
||||
|
||||
// first do superclass method
|
||||
this->cmGlobalGenerator::Generate();
|
||||
@@ -246,8 +255,9 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
|
||||
cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen));
|
||||
}
|
||||
|
||||
// Write the internal test_prep/ rules.
|
||||
// Write the internal test_prep/ and install_prep/ rules.
|
||||
this->WriteTestPrepRules(makefileStream, rootLG);
|
||||
this->WriteInstallPrepRules(makefileStream, rootLG);
|
||||
|
||||
// Write special bottom targets
|
||||
rootLG.WriteSpecialTargetsBottom(makefileStream);
|
||||
@@ -726,8 +736,10 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
|
||||
}
|
||||
}
|
||||
|
||||
// Forward the test_prep/ convenience targets to CMakeFiles/Makefile2.
|
||||
// Forward the test_prep/ and install_prep/ convenience targets to
|
||||
// CMakeFiles/Makefile2.
|
||||
this->WriteTestPrepConvenienceRules(ruleFileStream);
|
||||
this->WriteInstallPrepConvenienceRules(ruleFileStream);
|
||||
}
|
||||
|
||||
void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
|
||||
@@ -1231,6 +1243,162 @@ void cmGlobalUnixMakefileGenerator3::WriteTestPrepConvenienceRules(
|
||||
"test_prep/all", depends, commands, true);
|
||||
}
|
||||
|
||||
void cmGlobalUnixMakefileGenerator3::ComputeInstallPrepTargets()
|
||||
{
|
||||
this->InstallPrepComponentTargets.clear();
|
||||
this->InstallPrepAllTargets.clear();
|
||||
this->InstallPrepOrderedTargets.clear();
|
||||
this->InstallPrepEnabled = false;
|
||||
if (!this->AreInstallPrepTargetsEnabled()) {
|
||||
return;
|
||||
}
|
||||
this->InstallPrepEnabled = true;
|
||||
this->CheckInstallPrepTargets();
|
||||
|
||||
auto const& rootLG =
|
||||
cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
|
||||
this->LocalGenerators.front());
|
||||
std::string const config = rootLG.GetConfigName();
|
||||
InstallPrepTargets const prep = this->GetInstallPrepTargets(config);
|
||||
|
||||
std::set<std::string> unownedGeneratedFiles;
|
||||
auto appendTargetRules =
|
||||
[this, &config, &unownedGeneratedFiles](
|
||||
std::vector<std::string>& rules, cmGeneratorTarget const* gt,
|
||||
InstallPrepTargets::TargetRequirements requirements) {
|
||||
auto* lg3 =
|
||||
static_cast<cmLocalUnixMakefileGenerator3*>(gt->GetLocalGenerator());
|
||||
std::string const targetDirectory = lg3->GetRelativeTargetDirectory(gt);
|
||||
bool const needsRelink = gt->NeedRelinkBeforeInstall(config);
|
||||
if (requirements.InstallArtifact && needsRelink) {
|
||||
std::string const orderedRule =
|
||||
cmStrCat(targetDirectory, "/install_prep");
|
||||
this->InstallPrepOrderedTargets[orderedRule] = {
|
||||
cmStrCat(targetDirectory, "/all"),
|
||||
cmStrCat(targetDirectory, "/preinstall")
|
||||
};
|
||||
rules.push_back(orderedRule);
|
||||
return;
|
||||
}
|
||||
// A top-level rule cannot build an individual custom command output, so
|
||||
// build the whole target that owns it. A generated file that is not
|
||||
// the unique output of a target is attributed to its installing target.
|
||||
for (std::string const& file : requirements.GeneratedFiles) {
|
||||
this->CheckInstallPrepGeneratedFile(gt, file, unownedGeneratedFiles);
|
||||
}
|
||||
if (requirements.Normal ||
|
||||
(!requirements.GeneratedFiles.empty() && gt->IsInBuildSystem())) {
|
||||
rules.push_back(cmStrCat(targetDirectory, "/all"));
|
||||
}
|
||||
if (requirements.InstallArtifact) {
|
||||
rules.push_back(
|
||||
cmStrCat(targetDirectory, needsRelink ? "/preinstall" : "/all"));
|
||||
}
|
||||
};
|
||||
|
||||
for (auto const& target : prep.All) {
|
||||
appendTargetRules(this->InstallPrepAllTargets, target.first,
|
||||
target.second);
|
||||
}
|
||||
|
||||
for (auto const& entry : prep.Components) {
|
||||
std::string const name = cmStrCat("install_prep/", entry.first);
|
||||
// Merge targets whose names differ only in case where the make tool does
|
||||
// not distinguish them, as for "test_prep/" targets. Each of them then
|
||||
// prepares a superset of what its installation needs. Components are
|
||||
// visited in order, so the first spelling names the target.
|
||||
std::string const key = this->TargetNamesAreCaseInsensitive()
|
||||
? cmSystemTools::LowerCase(name)
|
||||
: name;
|
||||
std::vector<std::string>* rules = &this->InstallPrepAllTargets;
|
||||
if (key != "install_prep/all") {
|
||||
InstallPrepTarget& prepTarget = this->InstallPrepComponentTargets[key];
|
||||
if (prepTarget.Name.empty()) {
|
||||
prepTarget.Name = name;
|
||||
}
|
||||
rules = &prepTarget.Rules;
|
||||
}
|
||||
for (auto const& target : entry.second) {
|
||||
appendTargetRules(*rules, target.first, target.second);
|
||||
}
|
||||
}
|
||||
|
||||
auto sortAndRemoveDuplicates = [](std::vector<std::string>& rules) {
|
||||
std::sort(rules.begin(), rules.end());
|
||||
rules.erase(std::unique(rules.begin(), rules.end()), rules.end());
|
||||
};
|
||||
sortAndRemoveDuplicates(this->InstallPrepAllTargets);
|
||||
for (auto& entry : this->InstallPrepComponentTargets) {
|
||||
sortAndRemoveDuplicates(entry.second.Rules);
|
||||
}
|
||||
}
|
||||
|
||||
void cmGlobalUnixMakefileGenerator3::WriteInstallPrepRules(
|
||||
std::ostream& makefileStream, cmLocalUnixMakefileGenerator3& rootLG)
|
||||
{
|
||||
if (!this->InstallPrepEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> noCommands;
|
||||
std::string const makefile2 = "CMakeFiles/Makefile2";
|
||||
for (auto const& ordered : this->InstallPrepOrderedTargets) {
|
||||
std::vector<std::string> depends{ ordered.second.NormalRule };
|
||||
std::vector<std::string> commands{ rootLG.GetRecursiveMakeCall(
|
||||
makefile2, ordered.second.PreinstallRule) };
|
||||
rootLG.WriteMakeRule(makefileStream, nullptr, ordered.first, depends,
|
||||
commands, true);
|
||||
}
|
||||
|
||||
for (auto const& entry : this->InstallPrepComponentTargets) {
|
||||
std::vector<std::string> depends = entry.second.Rules;
|
||||
if (depends.empty() && !this->EmptyRuleHackDepends.empty()) {
|
||||
depends.push_back(this->EmptyRuleHackDepends);
|
||||
}
|
||||
rootLG.WriteMakeRule(makefileStream, nullptr, entry.second.Name, depends,
|
||||
noCommands, true);
|
||||
}
|
||||
|
||||
std::vector<std::string> allDepends = this->InstallPrepAllTargets;
|
||||
if (allDepends.empty() && !this->EmptyRuleHackDepends.empty()) {
|
||||
allDepends.push_back(this->EmptyRuleHackDepends);
|
||||
}
|
||||
rootLG.WriteMakeRule(makefileStream, nullptr, "install_prep/all", allDepends,
|
||||
noCommands, true);
|
||||
}
|
||||
|
||||
void cmGlobalUnixMakefileGenerator3::WriteInstallPrepConvenienceRules(
|
||||
std::ostream& ruleFileStream)
|
||||
{
|
||||
if (!this->InstallPrepEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
|
||||
this->LocalGenerators[0]);
|
||||
|
||||
bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
|
||||
std::string const makefile2 = "CMakeFiles/Makefile2";
|
||||
|
||||
std::vector<std::string> depends;
|
||||
std::vector<std::string> commands;
|
||||
auto writeForward = [&](std::string const& prepName) {
|
||||
depends.clear();
|
||||
if (regenerate) {
|
||||
depends.emplace_back("cmake_check_build_system");
|
||||
}
|
||||
commands.clear();
|
||||
commands.push_back(lg.GetRecursiveMakeCall(makefile2, prepName));
|
||||
lg.WriteMakeRule(ruleFileStream, nullptr, prepName, depends, commands,
|
||||
true);
|
||||
};
|
||||
|
||||
for (auto const& entry : this->InstallPrepComponentTargets) {
|
||||
writeForward(entry.second.Name);
|
||||
}
|
||||
writeForward("install_prep/all");
|
||||
}
|
||||
|
||||
void cmGlobalUnixMakefileGenerator3::WriteHelpRule(
|
||||
std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
|
||||
{
|
||||
|
||||
@@ -201,6 +201,9 @@ public:
|
||||
|
||||
bool IsIPOSupported() const override { return true; }
|
||||
|
||||
bool IsInstallPrepComponentRepresentable(
|
||||
std::string const& component) const override;
|
||||
|
||||
bool SupportsShortObjectNames() const override;
|
||||
void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
|
||||
|
||||
@@ -248,6 +251,20 @@ protected:
|
||||
// into CMakeFiles/Makefile2.
|
||||
void WriteTestPrepConvenienceRules(std::ostream& ruleFileStream);
|
||||
|
||||
// Compute the "install_prep/<component>" build targets. Each installation
|
||||
// component's dependencies are resolved to the build-system targets that
|
||||
// produce them so that the recursive Makefile graph can build them.
|
||||
void ComputeInstallPrepTargets();
|
||||
|
||||
// Write the internal "install_prep/<component>" and "install_prep/all" rules
|
||||
// into CMakeFiles/Makefile2.
|
||||
void WriteInstallPrepRules(std::ostream& makefileStream,
|
||||
cmLocalUnixMakefileGenerator3& rootLG);
|
||||
|
||||
// Write the top-level "install_prep/<component>" convenience rules that
|
||||
// forward into CMakeFiles/Makefile2.
|
||||
void WriteInstallPrepConvenienceRules(std::ostream& ruleFileStream);
|
||||
|
||||
// Target name hooks for superclass.
|
||||
char const* GetAllTargetName() const override { return "all"; }
|
||||
char const* GetInstallTargetName() const override { return "install"; }
|
||||
@@ -347,4 +364,27 @@ private:
|
||||
TestPrepTarget& GetTestPrepTarget(std::string const& name);
|
||||
void AddDirectoryTestPrepTargets(cmLocalGenerator* lg);
|
||||
bool TestPrepEnabled = false;
|
||||
|
||||
// An "install_prep/<component>" target and the "<target>.dir/all"
|
||||
// recursive rules that must be built to prepare the named installation
|
||||
// component.
|
||||
struct InstallPrepTarget
|
||||
{
|
||||
std::string Name;
|
||||
std::vector<std::string> Rules;
|
||||
};
|
||||
|
||||
// Ordered map of "install_prep/" target name -> its rules. Populated by
|
||||
// ComputeInstallPrepTargets.
|
||||
std::map<std::string, InstallPrepTarget> InstallPrepComponentTargets;
|
||||
std::vector<std::string> InstallPrepAllTargets;
|
||||
|
||||
struct InstallPrepOrderedTarget
|
||||
{
|
||||
std::string NormalRule;
|
||||
std::string PreinstallRule;
|
||||
};
|
||||
std::map<std::string, InstallPrepOrderedTarget> InstallPrepOrderedTargets;
|
||||
|
||||
bool InstallPrepEnabled = false;
|
||||
};
|
||||
@@ -292,7 +292,7 @@ if(CMAKE_GENERATOR MATCHES "Ninja")
|
||||
-DRunCMake_GENERATOR_IS_MULTI_CONFIG=${_isMultiConfig})
|
||||
endif()
|
||||
add_RunCMake_test(InstallParallel)
|
||||
if(CMAKE_GENERATOR MATCHES "Ninja")
|
||||
if(CMAKE_GENERATOR MATCHES "Make|Ninja")
|
||||
add_RunCMake_test(InstallPrep)
|
||||
endif()
|
||||
add_RunCMake_test(CTest)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
^CMake Warning \(author\) at ComponentNames\.cmake:[0-9]+ \(install\):
|
||||
The install component "Colon:Name" has build dependencies, but its name
|
||||
cannot be used in a build target name with this generator\. No
|
||||
"install_prep/" target will be generated for it\. Rename the component to
|
||||
build its dependencies with an "install_prep/" target\.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers\. Use -Wno-author to suppress it\.
|
||||
+
|
||||
CMake Warning \(author\) at ComponentNames\.cmake:[0-9]+ \(install\):
|
||||
The install component "Unsafe/\.\./Name" has build dependencies, but its name
|
||||
cannot be used in a build target name with this generator\. No
|
||||
"install_prep/" target will be generated for it\. Rename the component to
|
||||
build its dependencies with an "install_prep/" target\.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers\. Use -Wno-author to suppress it\.
|
||||
+
|
||||
CMake Warning \(author\) at ComponentNames\.cmake:[0-9]+ \(install\):
|
||||
The install component "Empty//Segment" has build dependencies, but its name
|
||||
cannot be used in a build target name with this generator\. No
|
||||
"install_prep/" target will be generated for it\. Rename the component to
|
||||
build its dependencies with an "install_prep/" target\.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers\. Use -Wno-author to suppress it\.
|
||||
+
|
||||
CMake Warning \(author\) at ComponentNames\.cmake:[0-9]+ \(install\):
|
||||
The install component "\./Dot" has build dependencies, but its name cannot
|
||||
be used in a build target name with this generator\. No "install_prep/"
|
||||
target will be generated for it\. Rename the component to build its
|
||||
dependencies with an "install_prep/" target\.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers\. Use -Wno-author to suppress it\.
|
||||
+
|
||||
CMake Warning \(author\) at ComponentNames\.cmake:[0-9]+ \(install\):
|
||||
An install rule in the component named "all" uses EXCLUDE_FROM_ALL and has
|
||||
build dependencies, but no install_prep/ target builds them:
|
||||
install_prep/all omits EXCLUDE_FROM_ALL rules, and the "all" component has
|
||||
no preparation target of its own\. Rename the component or remove
|
||||
EXCLUDE_FROM_ALL\.
|
||||
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,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\.$
|
||||
@@ -2,7 +2,14 @@ enable_language(C)
|
||||
|
||||
# Generators that can depend on individual files prepare a generated file by
|
||||
# running only the custom command that produces it.
|
||||
set(generated_target_source "${CMAKE_CURRENT_LIST_DIR}/neverbuild.c")
|
||||
#
|
||||
# The Makefile generators build the whole target instead, so its sources must
|
||||
# compile there.
|
||||
if(CMAKE_GENERATOR MATCHES "Make")
|
||||
set(generated_target_source "${CMAKE_CURRENT_LIST_DIR}/lib.c")
|
||||
else()
|
||||
set(generated_target_source "${CMAKE_CURRENT_LIST_DIR}/neverbuild.c")
|
||||
endif()
|
||||
|
||||
# Add a custom command that generates the named file in the current binary
|
||||
# directory and store its full path in the given variable.
|
||||
|
||||
@@ -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\.$
|
||||
@@ -0,0 +1,8 @@
|
||||
check_installed([[^bin;bin/relink$]])
|
||||
|
||||
foreach(program IN ITEMS "${RunCMake_TEST_BINARY_DIR}/relink" "${CMAKE_INSTALL_PREFIX}/bin/relink")
|
||||
execute_process(COMMAND "${program}" RESULT_VARIABLE result)
|
||||
if(NOT result EQUAL 0)
|
||||
set(RunCMake_TEST_FAILED "Relinked executable ${program} failed: ${result}")
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -0,0 +1,17 @@
|
||||
enable_language(C)
|
||||
|
||||
# Use different dummy RPATHs and disable binary RPATH editing to force the
|
||||
# Makefile generator's relink-before-install path.
|
||||
set(CMAKE_NO_BUILTIN_CHRPATH 1)
|
||||
|
||||
add_executable(relink EXCLUDE_FROM_ALL runtime_main.c)
|
||||
set_target_properties(relink PROPERTIES
|
||||
BUILD_RPATH foo
|
||||
INSTALL_RPATH bar
|
||||
)
|
||||
install(TARGETS relink
|
||||
RUNTIME DESTINATION bin
|
||||
COMPONENT Relink
|
||||
)
|
||||
|
||||
add_library(unit_tests STATIC neverbuild.c)
|
||||
@@ -61,7 +61,17 @@ macro(configure_install_prep test config)
|
||||
if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=${config})
|
||||
endif()
|
||||
# Some generators issue additional diagnostics.
|
||||
set(stderr_variant "")
|
||||
if(RunCMake_GENERATOR MATCHES "Make")
|
||||
set(stderr_variant make)
|
||||
endif()
|
||||
if(stderr_variant AND
|
||||
EXISTS "${RunCMake_SOURCE_DIR}/${test}-stderr-${stderr_variant}.txt")
|
||||
set(RunCMake-stderr-file ${test}-stderr-${stderr_variant}.txt)
|
||||
endif()
|
||||
run_cmake(${test})
|
||||
unset(RunCMake-stderr-file)
|
||||
set(RunCMake_TEST_NO_CLEAN TRUE)
|
||||
endmacro()
|
||||
|
||||
@@ -130,8 +140,14 @@ block()
|
||||
configure_install_prep(ComponentNames Debug)
|
||||
run_cmake_command(ComponentNames-all-build ${CMAKE_COMMAND}
|
||||
--build . --config Debug --target install_prep/all)
|
||||
if(RunCMake_GENERATOR MATCHES "Make")
|
||||
set(RunCMake_TEST_EXPECT_RESULT "[^0]")
|
||||
set(RunCMake_TEST_OUTPUT_MERGE TRUE)
|
||||
endif()
|
||||
run_cmake_command(ComponentNames-colon-build ${CMAKE_COMMAND}
|
||||
--build . --config Debug --target install_prep/Colon:Name)
|
||||
unset(RunCMake_TEST_EXPECT_RESULT)
|
||||
unset(RunCMake_TEST_OUTPUT_MERGE)
|
||||
run_missing_install_prep(ComponentNames-dotdot install_prep/Unsafe/../Name)
|
||||
run_missing_install_prep(ComponentNames-empty-segment
|
||||
install_prep/Empty//Segment)
|
||||
@@ -181,3 +197,17 @@ endif()
|
||||
if(CMAKE_HOST_SYSTEM_NAME MATCHES "^(Linux|Darwin)$")
|
||||
run_install_prep(Namelink install_prep/Namelink Namelink)
|
||||
endif()
|
||||
|
||||
if(RunCMake_GENERATOR MATCHES "Make" AND
|
||||
CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
|
||||
block()
|
||||
configure_install_prep(MakefilePreinstall Debug)
|
||||
run_cmake_command(MakefilePreinstall-prep ${CMAKE_COMMAND}
|
||||
--build . --config Debug --target install_prep/Relink)
|
||||
run_cmake_command(MakefilePreinstall-run
|
||||
${RunCMake_TEST_BINARY_DIR}/relink)
|
||||
set(RunCMake-check-file MakefilePreinstall-install-check.cmake)
|
||||
run_cmake_command(MakefilePreinstall-install ${CMAKE_COMMAND}
|
||||
--install . --config Debug --component Relink)
|
||||
endblock()
|
||||
endif()
|
||||
Reference in new issue
Block a user