mirror of
https://github.com/Kitware/CMake.git
synced 2026-11-06 05:16:58 +00:00
install: Add BUILD_DEPENDS option for install_prep targets
Add a `BUILD_DEPENDS` option to multiple `install` command signatures for projects to specify dependencies which CMake cannot infer. Co-authored-by: Tyler Yankee <tyler.yankee@kitware.com> Closes: #27643
This commit is contained in:
1 parent
e36cd0ac29
commit
41bb5b5e96
53 files changed
+552
-34
No files matched your search
@@ -141,6 +141,21 @@ signatures that specify them. The common options are:
|
||||
Specify that it is not an error if the file to be installed does
|
||||
not exist.
|
||||
|
||||
``BUILD_DEPENDS <dependency>...``
|
||||
.. versionadded:: 4.5
|
||||
|
||||
Specify targets or files that need to be built before the install rule
|
||||
runs. They are added as dependencies of the corresponding
|
||||
:ref:`Install Preparation Targets`. This is intended for dependencies
|
||||
that CMake cannot infer.
|
||||
|
||||
Each entry naming an existing target or alias is a target dependency.
|
||||
Any other entry names a file, which must exist or be generated by the build.
|
||||
A relative file path is interpreted with respect to the current source
|
||||
directory if the file exists there, and otherwise with respect to the current
|
||||
binary directory. If this option is used multiple times in a single call,
|
||||
its list of dependencies accumulates.
|
||||
|
||||
.. versionadded:: 3.1
|
||||
Command signatures that install files may print messages during
|
||||
installation. Use the :variable:`CMAKE_INSTALL_MESSAGE` variable
|
||||
@@ -600,6 +615,7 @@ Signatures
|
||||
[PERMISSIONS <permission>...]
|
||||
[CONFIGURATIONS <config>...]
|
||||
[COMPONENT <component>]
|
||||
[BUILD_DEPENDS <dependency>...]
|
||||
[RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])
|
||||
|
||||
The ``FILES`` form specifies rules for installing files for a project.
|
||||
@@ -614,6 +630,11 @@ Signatures
|
||||
programs that are not targets, such as shell scripts. Use the ``TARGETS``
|
||||
form to install targets built within the project.
|
||||
|
||||
.. versionadded:: 4.5
|
||||
Files named by the command that the build generates are inferred as
|
||||
dependencies of the :ref:`Install Preparation Targets`. Use the
|
||||
``BUILD_DEPENDS`` option to name any other dependencies.
|
||||
|
||||
The list of files given to ``FILES`` or ``PROGRAMS`` may use
|
||||
"generator expressions" with the syntax ``$<...>``. See the
|
||||
:manual:`cmake-generator-expressions(7)` manual for available expressions.
|
||||
@@ -713,6 +734,7 @@ Signatures
|
||||
[USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
|
||||
[CONFIGURATIONS <config>...]
|
||||
[COMPONENT <component>] [EXCLUDE_FROM_ALL]
|
||||
[BUILD_DEPENDS <dependency>...]
|
||||
[FILES_MATCHING]
|
||||
[<match-rule> <match-option>...]...
|
||||
)
|
||||
@@ -815,6 +837,15 @@ Signatures
|
||||
|
||||
Disable file installation status output.
|
||||
|
||||
``BUILD_DEPENDS <dependency>...``
|
||||
.. versionadded:: 4.5
|
||||
|
||||
See `Common Options`_. CMake enumerates the content of an installed
|
||||
directory during installation, so it cannot infer any dependencies of
|
||||
directories populated by build steps.
|
||||
|
||||
This option may not be given after a ``<match-rule>``.
|
||||
|
||||
``FILES_MATCHING``
|
||||
This option may be given before the first ``<match-rule>`` to
|
||||
disable installation of files (but not directories) not matched
|
||||
@@ -883,6 +914,7 @@ Signatures
|
||||
|
||||
install({ SCRIPT <file> | CODE <code> }...
|
||||
[ALL_COMPONENTS | COMPONENT <component>]
|
||||
[BUILD_DEPENDS <dependency>...]
|
||||
[EXCLUDE_FROM_ALL])
|
||||
|
||||
The ``SCRIPT`` form will invoke the given CMake script files during
|
||||
@@ -898,6 +930,11 @@ Signatures
|
||||
|
||||
will print a message during installation.
|
||||
|
||||
.. versionadded:: 4.5
|
||||
CMake cannot infer dependencies of installation code. Dependencies named
|
||||
by the ``BUILD_DEPENDS`` option apply to every ``SCRIPT`` or ``CODE``
|
||||
install rule created by the call.
|
||||
|
||||
.. versionadded:: 3.21
|
||||
When the ``ALL_COMPONENTS`` option is given, the custom installation
|
||||
script code will be executed for every component of a component-specific
|
||||
|
||||
@@ -1886,9 +1886,12 @@ For example:
|
||||
set_property(TARGET B PROPERTY PUBLIC_HEADER
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/byproduct.h")
|
||||
|
||||
Rules created by the ``DIRECTORY``, ``SCRIPT``, and ``CODE`` signatures of
|
||||
the :command:`install` command, or by the deprecated
|
||||
:command:`install_targets` command, do not imply build dependencies.
|
||||
The ``BUILD_DEPENDS`` option of the ``FILES``, ``PROGRAMS``, ``DIRECTORY``,
|
||||
``SCRIPT``, and ``CODE`` signatures of the :command:`install` command can
|
||||
be used to specify targets or files that CMake cannot infer. ``DIRECTORY``,
|
||||
``SCRIPT``, and ``CODE`` rules do not imply build dependencies without
|
||||
``BUILD_DEPENDS``. The deprecated :command:`install_targets` command does not
|
||||
contribute dependencies.
|
||||
|
||||
Install rules below a directory added with :prop_dir:`EXCLUDE_FROM_ALL` are
|
||||
ignored, matching installation from the parent directory.
|
||||
@@ -75,6 +75,16 @@ Instrumentation
|
||||
Generators
|
||||
----------
|
||||
|
||||
* The :ref:`Ninja Generators`, :ref:`Makefile Generators`, and
|
||||
:generator:`FASTBuild` generator now provide ``install_prep/all`` and
|
||||
``install_prep/<component>`` convenience build targets by default. The
|
||||
:variable:`CMAKE_SKIP_INSTALL_PREP_TARGETS` variable may be enabled to
|
||||
skip generating them. These targets build all known build dependencies for
|
||||
an installation that does not select a component, or for the named install
|
||||
component, respectively. This includes targets that produce installed C++
|
||||
module BMIs, module export metadata, or generated files. See
|
||||
:ref:`Install Preparation Targets`.
|
||||
|
||||
* The :generator:`FASTBuild` generator and the :ref:`Makefile Generators`
|
||||
now generate ``test_prep/<test-name>`` and ``test_prep/all`` convenience
|
||||
build targets when the :variable:`CMAKE_TEST_BUILD_DEPENDS` variable is
|
||||
@@ -186,6 +196,11 @@ Commands
|
||||
The option cannot be used with ``EXPORT`` and may only install runtime
|
||||
artifacts.
|
||||
|
||||
* The :command:`install` command's ``FILES``, ``PROGRAMS``, ``DIRECTORY``,
|
||||
``SCRIPT``, and ``CODE`` signatures gained a ``BUILD_DEPENDS`` option to
|
||||
specify targets or files needed to prepare files or run installation
|
||||
code. See :ref:`Install Preparation Targets`.
|
||||
|
||||
* The :command:`math` command gained new ``INCREMENT`` and ``DECREMENT`` modes.
|
||||
|
||||
* The :command:`project` and :command:`enable_language` commands, when
|
||||
|
||||
@@ -3571,7 +3571,8 @@ void cmGlobalGenerator::CheckInstallPrepTargets()
|
||||
"\nwhich is generated but is not the unique output of "
|
||||
"a build target, so \"install_prep/\" targets cannot "
|
||||
"build it with this generator. Produce the file with "
|
||||
"a custom command attached to a single target to "
|
||||
"a custom command attached to a single target, or name "
|
||||
"the target that produces it with BUILD_DEPENDS, to "
|
||||
"prepare it."),
|
||||
installer->GetDiagnosticContext());
|
||||
}
|
||||
|
||||
+32
-11
@@ -300,16 +300,16 @@ std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator(
|
||||
std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
|
||||
cmMakefile* mf, std::vector<std::string> const& absFiles,
|
||||
cmInstallCommandArguments const& args, bool programs,
|
||||
std::string const& destination,
|
||||
std::string const& destination, std::vector<std::string> const& buildDepends,
|
||||
cm::optional<std::vector<std::string>> const& configurations = {})
|
||||
{
|
||||
cmInstallGenerator::MessageLevel message =
|
||||
cmInstallGenerator::SelectMessageLevel(mf);
|
||||
return cm::make_unique<cmInstallFilesGenerator>(
|
||||
absFiles, destination, programs, args.GetPermissions(),
|
||||
SelectConfigurations(args, configurations), args.GetComponent(), message,
|
||||
args.GetExcludeFromAll(), args.GetRename(), args.GetOptional(),
|
||||
cmInstallGenerator::CaptureContext(mf));
|
||||
SelectConfigurations(args, configurations), args.GetComponent(),
|
||||
buildDepends, message, args.GetExcludeFromAll(), args.GetRename(),
|
||||
args.GetOptional(), cmInstallGenerator::CaptureContext(mf));
|
||||
}
|
||||
|
||||
std::unique_ptr<cmInstallFileSetGenerator> CreateInstallFileSetGenerator(
|
||||
@@ -865,7 +865,8 @@ bool CreateInstallGeneratorsForTarget(
|
||||
if (!artifactsSpecified || !privateHeaderArgs.GetDestination().empty()) {
|
||||
privateHeaderGenerator = CreateInstallFilesGenerator(
|
||||
helper.Makefile, absFiles, privateHeaderArgs, false,
|
||||
helper.GetIncludeDestination(&privateHeaderArgs), configurations);
|
||||
helper.GetIncludeDestination(&privateHeaderArgs),
|
||||
std::vector<std::string>(), configurations);
|
||||
privateHeaderGenerator->SetOwningTarget(target.GetName());
|
||||
} else {
|
||||
helper.Makefile->IssueDiagnostic(
|
||||
@@ -889,7 +890,8 @@ bool CreateInstallGeneratorsForTarget(
|
||||
if (!artifactsSpecified || !publicHeaderArgs.GetDestination().empty()) {
|
||||
publicHeaderGenerator = CreateInstallFilesGenerator(
|
||||
helper.Makefile, absFiles, publicHeaderArgs, false,
|
||||
helper.GetIncludeDestination(&publicHeaderArgs), configurations);
|
||||
helper.GetIncludeDestination(&publicHeaderArgs),
|
||||
std::vector<std::string>(), configurations);
|
||||
publicHeaderGenerator->SetOwningTarget(target.GetName());
|
||||
} else {
|
||||
helper.Makefile->IssueDiagnostic(
|
||||
@@ -913,7 +915,8 @@ bool CreateInstallGeneratorsForTarget(
|
||||
if (!resourceArgs.GetDestination().empty()) {
|
||||
resourceGenerator = CreateInstallFilesGenerator(
|
||||
helper.Makefile, absFiles, resourceArgs, false,
|
||||
resourceArgs.GetDestination(), configurations);
|
||||
resourceArgs.GetDestination(), std::vector<std::string>(),
|
||||
configurations);
|
||||
resourceGenerator->SetOwningTarget(target.GetName());
|
||||
} else if (!target.IsAppBundleOnApple()) {
|
||||
helper.Makefile->IssueDiagnostic(
|
||||
@@ -1076,6 +1079,7 @@ bool HandleScriptMode(std::vector<std::string> const& args,
|
||||
|
||||
std::vector<Script> Scripts;
|
||||
cm::optional<std::string> Component;
|
||||
ArgumentParser::MaybeEmpty<std::vector<std::string>> BuildDepends;
|
||||
bool ExcludeFromAll = false;
|
||||
bool AllComponents = false;
|
||||
};
|
||||
@@ -1086,6 +1090,7 @@ bool HandleScriptMode(std::vector<std::string> const& args,
|
||||
.Bind("CODE"_s, &Arguments::AddScript)
|
||||
.Bind("COMPONENT"_s, &Arguments::Component)
|
||||
.Bind("EXCLUDE_FROM_ALL"_s, &Arguments::ExcludeFromAll)
|
||||
.Bind("BUILD_DEPENDS"_s, &Arguments::BuildDepends)
|
||||
.Bind("ALL_COMPONENTS"_s, &Arguments::AllComponents);
|
||||
|
||||
std::vector<std::string> unknownArgs;
|
||||
@@ -1123,7 +1128,7 @@ bool HandleScriptMode(std::vector<std::string> const& args,
|
||||
cm::make_unique<cmInstallScriptGenerator>(
|
||||
std::move(script.Value), script.IsCode, component,
|
||||
arguments.ExcludeFromAll, arguments.AllComponents,
|
||||
helper.Makefile->GetBacktrace()));
|
||||
arguments.BuildDepends, helper.Makefile->GetBacktrace()));
|
||||
}
|
||||
|
||||
// Tell the global generator about any installation component names
|
||||
@@ -1831,7 +1836,9 @@ bool HandleFilesMode(std::vector<std::string> const& args,
|
||||
bool programs = (args[0] == "PROGRAMS");
|
||||
cmInstallCommandArguments ica(helper.DefaultComponentName, *helper.Makefile);
|
||||
ArgumentParser::MaybeEmpty<std::vector<std::string>> files;
|
||||
ArgumentParser::MaybeEmpty<std::vector<std::string>> depends;
|
||||
ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files);
|
||||
ica.Bind("BUILD_DEPENDS"_s, depends);
|
||||
std::vector<std::string> unknownArgs;
|
||||
ica.Parse(args, &unknownArgs);
|
||||
|
||||
@@ -1850,6 +1857,7 @@ bool HandleFilesMode(std::vector<std::string> const& args,
|
||||
}
|
||||
|
||||
std::vector<std::string> const& filesVector = files;
|
||||
std::vector<std::string> const& buildDepends = depends;
|
||||
|
||||
// Check if there is something to do.
|
||||
if (filesVector.empty()) {
|
||||
@@ -1903,7 +1911,7 @@ bool HandleFilesMode(std::vector<std::string> const& args,
|
||||
|
||||
// Create the files install generator.
|
||||
helper.Makefile->AddInstallGenerator(CreateInstallFilesGenerator(
|
||||
helper.Makefile, absFiles, ica, programs, destination));
|
||||
helper.Makefile, absFiles, ica, programs, destination, buildDepends));
|
||||
|
||||
// Tell the global generator about any installation component names
|
||||
// specified.
|
||||
@@ -1930,6 +1938,7 @@ bool HandleDirectoryMode(std::vector<std::string> const& args,
|
||||
DoingPermsMatch,
|
||||
DoingConfigurations,
|
||||
DoingComponent,
|
||||
DoingBuildDepends,
|
||||
DoingType
|
||||
};
|
||||
Doing doing = DoingDirs;
|
||||
@@ -1943,6 +1952,7 @@ bool HandleDirectoryMode(std::vector<std::string> const& args,
|
||||
std::string permissionsDir;
|
||||
std::vector<std::string> configurations;
|
||||
std::string component = helper.DefaultComponentName;
|
||||
std::vector<std::string> buildDepends;
|
||||
std::string literalArgs;
|
||||
std::string type;
|
||||
for (unsigned int i = 1; i < args.size(); ++i) {
|
||||
@@ -2067,6 +2077,15 @@ bool HandleDirectoryMode(std::vector<std::string> const& args,
|
||||
|
||||
// Switch to setting the component property.
|
||||
doing = DoingComponent;
|
||||
} else if (args[i] == "BUILD_DEPENDS") {
|
||||
if (inMatchMode) {
|
||||
status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
|
||||
"\" after PATTERN or REGEX."));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Switch to adding build dependencies.
|
||||
doing = DoingBuildDepends;
|
||||
} else if (args[i] == "EXCLUDE_FROM_ALL") {
|
||||
if (inMatchMode) {
|
||||
status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
|
||||
@@ -2151,6 +2170,8 @@ bool HandleDirectoryMode(std::vector<std::string> const& args,
|
||||
} else if (doing == DoingComponent) {
|
||||
component = args[i];
|
||||
doing = DoingNone;
|
||||
} else if (doing == DoingBuildDepends) {
|
||||
buildDepends.push_back(args[i]);
|
||||
} else if (doing == DoingPermsFile) {
|
||||
// Check the requested permission.
|
||||
if (!cmInstallCommandArguments::CheckPermissions(args[i],
|
||||
@@ -2215,8 +2236,8 @@ bool HandleDirectoryMode(std::vector<std::string> const& args,
|
||||
helper.Makefile->AddInstallGenerator(
|
||||
cm::make_unique<cmInstallDirectoryGenerator>(
|
||||
dirs, *destination, permissionsFile, permissionsDir, configurations,
|
||||
component, message, excludeFromAll, literalArgs, optional,
|
||||
helper.CaptureContext()));
|
||||
component, std::move(buildDepends), message, excludeFromAll, literalArgs,
|
||||
optional, helper.CaptureContext()));
|
||||
|
||||
// Tell the global generator about any installation component names
|
||||
// specified.
|
||||
|
||||
@@ -18,14 +18,16 @@ cmInstallDirectoryGenerator::cmInstallDirectoryGenerator(
|
||||
std::vector<std::string> const& dirs, std::string const& dest,
|
||||
std::string filePermissions, std::string dirPermissions,
|
||||
std::vector<std::string> const& configurations, std::string const& component,
|
||||
MessageLevel message, bool excludeFromAll, std::string literalArgs,
|
||||
bool optional, cmDiagnosticContext context)
|
||||
std::vector<std::string> buildDepends, MessageLevel message,
|
||||
bool excludeFromAll, std::string literalArgs, bool optional,
|
||||
cmDiagnosticContext context)
|
||||
: cmInstallGenerator(dest, configurations, component, message,
|
||||
excludeFromAll, false, std::move(context))
|
||||
, Directories(dirs)
|
||||
, FilePermissions(std::move(filePermissions))
|
||||
, DirPermissions(std::move(dirPermissions))
|
||||
, LiteralArguments(std::move(literalArgs))
|
||||
, BuildDepends(std::move(buildDepends))
|
||||
, Optional(optional)
|
||||
{
|
||||
// We need per-config actions if destination have generator expressions.
|
||||
@@ -49,7 +51,15 @@ cmInstallDirectoryGenerator::~cmInstallDirectoryGenerator() = default;
|
||||
bool cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg)
|
||||
{
|
||||
this->LocalGenerator = lg;
|
||||
return true;
|
||||
return this->ResolveBuildDepends(lg, "DIRECTORY", this->BuildDepends,
|
||||
this->ResolvedBuildDepends);
|
||||
}
|
||||
|
||||
void cmInstallDirectoryGenerator::GetInstallBuildDependencies(
|
||||
std::string const& config, std::vector<BuildDependency>& dependencies) const
|
||||
{
|
||||
AddBuildDependsDependencies(this->LocalGenerator, config,
|
||||
this->ResolvedBuildDepends, dependencies);
|
||||
}
|
||||
|
||||
std::vector<std::string> cmInstallDirectoryGenerator::GetDirectories(
|
||||
|
||||
@@ -23,12 +23,17 @@ public:
|
||||
std::vector<std::string> const& dirs, std::string const& dest,
|
||||
std::string filePermissions, std::string dirPermissions,
|
||||
std::vector<std::string> const& configurations,
|
||||
std::string const& component, MessageLevel message, bool excludeFromAll,
|
||||
std::string literalArgs, bool optional, cmDiagnosticContext context);
|
||||
std::string const& component, std::vector<std::string> buildDepends,
|
||||
MessageLevel message, bool excludeFromAll, std::string literalArgs,
|
||||
bool optional, cmDiagnosticContext context);
|
||||
~cmInstallDirectoryGenerator() override;
|
||||
|
||||
bool Compute(cmLocalGenerator* lg) override;
|
||||
|
||||
void GetInstallBuildDependencies(
|
||||
std::string const& config,
|
||||
std::vector<BuildDependency>& dependencies) const override;
|
||||
|
||||
std::string GetDestination(std::string const& config) const;
|
||||
std::vector<std::string> GetDirectories(std::string const& config) const;
|
||||
|
||||
@@ -46,5 +51,7 @@ protected:
|
||||
std::string const FilePermissions;
|
||||
std::string const DirPermissions;
|
||||
std::string const LiteralArguments;
|
||||
std::vector<std::string> const BuildDepends;
|
||||
BuildDependsEntries ResolvedBuildDepends;
|
||||
bool const Optional;
|
||||
};
|
||||
@@ -131,7 +131,7 @@ static void CreateInstallGenerator(cmMakefile& makefile,
|
||||
cmInstallGenerator::SelectMessageLevel(&makefile);
|
||||
makefile.AddInstallGenerator(cm::make_unique<cmInstallFilesGenerator>(
|
||||
files, destination, false, no_permissions, no_configurations, no_component,
|
||||
message, no_exclude_from_all, no_rename, false,
|
||||
std::vector<std::string>(), message, no_exclude_from_all, no_rename, false,
|
||||
cmInstallGenerator::CaptureContext(makefile)));
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,15 @@ cmInstallFilesGenerator::cmInstallFilesGenerator(
|
||||
std::vector<std::string> const& files, std::string const& dest,
|
||||
bool programs, std::string filePermissions,
|
||||
std::vector<std::string> const& configurations, std::string const& component,
|
||||
MessageLevel message, bool excludeFromAll, std::string rename, bool optional,
|
||||
std::vector<std::string> buildDepends, MessageLevel message,
|
||||
bool excludeFromAll, std::string rename, bool optional,
|
||||
cmDiagnosticContext context)
|
||||
: cmInstallGenerator(dest, configurations, component, message,
|
||||
excludeFromAll, false, std::move(context))
|
||||
, Files(files)
|
||||
, FilePermissions(std::move(filePermissions))
|
||||
, Rename(std::move(rename))
|
||||
, BuildDepends(std::move(buildDepends))
|
||||
, Programs(programs)
|
||||
, Optional(optional)
|
||||
{
|
||||
@@ -52,15 +54,27 @@ bool cmInstallFilesGenerator::Compute(cmLocalGenerator* lg)
|
||||
if (!this->OwningTargetName.empty()) {
|
||||
this->OwningTarget = lg->FindGeneratorTargetToUse(this->OwningTargetName);
|
||||
}
|
||||
return true;
|
||||
return this->ResolveBuildDepends(lg, this->Programs ? "PROGRAMS" : "FILES",
|
||||
this->BuildDepends,
|
||||
this->ResolvedBuildDepends);
|
||||
}
|
||||
|
||||
void cmInstallFilesGenerator::GetInstallBuildDependencies(
|
||||
std::string const& config, std::vector<BuildDependency>& dependencies) const
|
||||
{
|
||||
AddBuildDependsDependencies(this->LocalGenerator, config,
|
||||
this->ResolvedBuildDepends, dependencies);
|
||||
std::vector<BuildDependency> generated;
|
||||
AddGeneratedFileDependencies(this->LocalGenerator->GetGlobalGenerator(),
|
||||
config, this->OwningTarget,
|
||||
this->GetFiles(config), dependencies);
|
||||
this->GetFiles(config), generated);
|
||||
for (BuildDependency& dependency : generated) {
|
||||
// A generated file that no target prepares is assumed to be produced by
|
||||
// the targets named by BUILD_DEPENDS, if any.
|
||||
if (dependency.Target || this->ResolvedBuildDepends.Targets.empty()) {
|
||||
dependencies.push_back(std::move(dependency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string cmInstallFilesGenerator::GetDestination(
|
||||
|
||||
@@ -25,9 +25,11 @@ public:
|
||||
std::string const& dest, bool programs,
|
||||
std::string filePermissions,
|
||||
std::vector<std::string> const& configurations,
|
||||
std::string const& component, MessageLevel message,
|
||||
bool excludeFromAll, std::string rename,
|
||||
bool optional, cmDiagnosticContext context);
|
||||
std::string const& component,
|
||||
std::vector<std::string> buildDepends,
|
||||
MessageLevel message, bool excludeFromAll,
|
||||
std::string rename, bool optional,
|
||||
cmDiagnosticContext context);
|
||||
~cmInstallFilesGenerator() override;
|
||||
|
||||
bool Compute(cmLocalGenerator* lg) override;
|
||||
@@ -58,6 +60,8 @@ protected:
|
||||
std::vector<std::string> const Files;
|
||||
std::string const FilePermissions;
|
||||
std::string const Rename;
|
||||
std::vector<std::string> const BuildDepends;
|
||||
BuildDependsEntries ResolvedBuildDepends;
|
||||
std::string OwningTargetName;
|
||||
cmGeneratorTarget const* OwningTarget = nullptr;
|
||||
bool const Programs;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#include "cmInstallGenerator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
@@ -12,6 +13,7 @@
|
||||
#include "cmGlobalGenerator.h"
|
||||
#include "cmLocalGenerator.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
@@ -272,6 +274,57 @@ cmDiagnosticContext cmInstallGenerator::CaptureContext(cmMakefile const& mf)
|
||||
return context;
|
||||
}
|
||||
|
||||
bool cmInstallGenerator::ResolveBuildDepends(
|
||||
cmLocalGenerator* lg, std::string const& signature,
|
||||
std::vector<std::string> const& names, BuildDependsEntries& entries)
|
||||
{
|
||||
entries = BuildDependsEntries();
|
||||
cmGlobalGenerator* gg = lg->GetGlobalGenerator();
|
||||
std::vector<std::string> const configs =
|
||||
lg->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
|
||||
auto const isArtifact = [gg, &configs](std::string const& file) {
|
||||
return std::any_of(configs.begin(), configs.end(),
|
||||
[gg, &file](std::string const& config) {
|
||||
return gg->FindArtifactOwningTarget(file, config);
|
||||
});
|
||||
};
|
||||
for (std::string const& name : names) {
|
||||
if (cmGeneratorTarget const* target = lg->FindGeneratorTargetToUse(name)) {
|
||||
entries.Targets.push_back(target);
|
||||
continue;
|
||||
}
|
||||
// A relative path is interpreted with respect to the current source
|
||||
// directory if the file exists there, and otherwise the current binary
|
||||
// directory.
|
||||
std::string file = lg->GetRealFileDependency(name);
|
||||
if (gg->IsGeneratedByBuild(file) || isArtifact(file) ||
|
||||
cmSystemTools::FileExists(file)) {
|
||||
entries.Files.push_back(std::move(file));
|
||||
} else {
|
||||
lg->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("install(", signature, ") BUILD_DEPENDS entry \"", name,
|
||||
"\" is neither a target nor a file that exists or is "
|
||||
"generated by the build."),
|
||||
this->GetBacktrace());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cmInstallGenerator::AddBuildDependsDependencies(
|
||||
cmLocalGenerator* lg, std::string const& config,
|
||||
BuildDependsEntries const& entries,
|
||||
std::vector<BuildDependency>& dependencies)
|
||||
{
|
||||
for (cmGeneratorTarget const* target : entries.Targets) {
|
||||
dependencies.push_back({ target, BuildDependencyType::Normal });
|
||||
}
|
||||
AddGeneratedFileDependencies(lg->GetGlobalGenerator(), config, nullptr,
|
||||
entries.Files, dependencies);
|
||||
}
|
||||
|
||||
std::string cmInstallGenerator::GetDestDirPath(std::string const& file)
|
||||
{
|
||||
// Construct the path of the file on disk after installation on
|
||||
|
||||
@@ -148,6 +148,26 @@ protected:
|
||||
std::vector<std::string> const& files,
|
||||
TweakMethod const& tweak);
|
||||
|
||||
// BUILD_DEPENDS entries of an install(<signature>) rule, resolved.
|
||||
struct BuildDependsEntries
|
||||
{
|
||||
std::vector<cmGeneratorTarget const*> Targets;
|
||||
std::vector<std::string> Files;
|
||||
};
|
||||
|
||||
// Resolve each BUILD_DEPENDS entry to a target or file. Returns false after
|
||||
// reporting an error if an entry names neither a target nor a file that
|
||||
// exists or that the build produces.
|
||||
bool ResolveBuildDepends(cmLocalGenerator* lg, std::string const& signature,
|
||||
std::vector<std::string> const& names,
|
||||
BuildDependsEntries& entries);
|
||||
|
||||
// Add dependencies for resolved BUILD_DEPENDS entries.
|
||||
static void AddBuildDependsDependencies(
|
||||
cmLocalGenerator* lg, std::string const& config,
|
||||
BuildDependsEntries const& entries,
|
||||
std::vector<BuildDependency>& dependencies);
|
||||
|
||||
// Add dependencies for the files that the build produces among the given
|
||||
// files. A file linked by a target depends on building that target. Any
|
||||
// other generated file is attributed to the target owning the custom
|
||||
|
||||
@@ -104,7 +104,7 @@ static void FinalAction(cmMakefile& makefile, std::string const& dest,
|
||||
cmInstallGenerator::SelectMessageLevel(&makefile);
|
||||
makefile.AddInstallGenerator(cm::make_unique<cmInstallFilesGenerator>(
|
||||
files, destination, true, no_permissions, no_configurations, no_component,
|
||||
message, no_exclude_from_all, no_rename, false,
|
||||
std::vector<std::string>(), message, no_exclude_from_all, no_rename, false,
|
||||
cmInstallGenerator::CaptureContext(makefile)));
|
||||
}
|
||||
|
||||
|
||||
@@ -14,12 +14,14 @@
|
||||
|
||||
cmInstallScriptGenerator::cmInstallScriptGenerator(
|
||||
std::string script, bool code, std::string const& component,
|
||||
bool excludeFromAll, bool allComponents, cmListFileBacktrace backtrace)
|
||||
bool excludeFromAll, bool allComponents,
|
||||
std::vector<std::string> buildDepends, cmListFileBacktrace backtrace)
|
||||
: cmInstallGenerator("", std::vector<std::string>(), component,
|
||||
MessageDefault, excludeFromAll, allComponents,
|
||||
cmDiagnosticContext{ std::move(backtrace) })
|
||||
, Script(std::move(script))
|
||||
, Code(code)
|
||||
, BuildDepends(std::move(buildDepends))
|
||||
{
|
||||
// We need per-config actions if the script has generator expressions.
|
||||
if (cmGeneratorExpression::Find(this->Script) != std::string::npos) {
|
||||
@@ -32,6 +34,11 @@ cmInstallScriptGenerator::~cmInstallScriptGenerator() = default;
|
||||
bool cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
|
||||
{
|
||||
this->LocalGenerator = lg;
|
||||
if (!this->ResolveBuildDepends(lg, this->Code ? "CODE" : "SCRIPT",
|
||||
this->BuildDepends,
|
||||
this->ResolvedBuildDepends)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->ActionsPerConfig) {
|
||||
switch (this->LocalGenerator->GetPolicyStatus(cmPolicies::CMP0087)) {
|
||||
@@ -49,6 +56,13 @@ bool cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
|
||||
return true;
|
||||
}
|
||||
|
||||
void cmInstallScriptGenerator::GetInstallBuildDependencies(
|
||||
std::string const& config, std::vector<BuildDependency>& dependencies) const
|
||||
{
|
||||
AddBuildDependsDependencies(this->LocalGenerator, config,
|
||||
this->ResolvedBuildDepends, dependencies);
|
||||
}
|
||||
|
||||
std::string cmInstallScriptGenerator::GetScript(
|
||||
std::string const& config) const
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cmInstallGenerator.h"
|
||||
#include "cmListFileCache.h"
|
||||
@@ -21,11 +22,16 @@ public:
|
||||
cmInstallScriptGenerator(
|
||||
std::string script, bool code, std::string const& component,
|
||||
bool excludeFromAll, bool allComponents,
|
||||
std::vector<std::string> buildDepends = {},
|
||||
cmListFileBacktrace backtrace = cmListFileBacktrace());
|
||||
~cmInstallScriptGenerator() override;
|
||||
|
||||
bool Compute(cmLocalGenerator* lg) override;
|
||||
|
||||
void GetInstallBuildDependencies(
|
||||
std::string const& config,
|
||||
std::vector<BuildDependency>& dependencies) const override;
|
||||
|
||||
bool IsCode() const { return this->Code; }
|
||||
|
||||
std::string GetScript(std::string const& config) const;
|
||||
@@ -39,6 +45,8 @@ protected:
|
||||
|
||||
std::string const Script;
|
||||
bool const Code;
|
||||
std::vector<std::string> const BuildDepends;
|
||||
BuildDependsEntries ResolvedBuildDepends;
|
||||
cmLocalGenerator* LocalGenerator;
|
||||
bool AllowGenex = false;
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
enable_language(C)
|
||||
|
||||
# Files generated by custom targets can only be installed after the
|
||||
# preparation target has built them.
|
||||
set(file_payload "${CMAKE_CURRENT_BINARY_DIR}/file-payload.txt")
|
||||
add_custom_target(generate_file_payload
|
||||
COMMAND ${CMAKE_COMMAND} -E touch "${file_payload}"
|
||||
BYPRODUCTS "${file_payload}"
|
||||
)
|
||||
install(FILES "${file_payload}"
|
||||
DESTINATION share/install-prep
|
||||
COMPONENT Payload
|
||||
BUILD_DEPENDS generate_file_payload
|
||||
)
|
||||
|
||||
set(code_payload "${CMAKE_CURRENT_BINARY_DIR}/code-payload.txt")
|
||||
add_custom_target(generate_code_payload
|
||||
COMMAND ${CMAKE_COMMAND} -E touch "${code_payload}"
|
||||
BYPRODUCTS "${code_payload}"
|
||||
)
|
||||
install(CODE "
|
||||
if(NOT EXISTS \"${code_payload}\")
|
||||
message(FATAL_ERROR \"Preparation did not generate code-payload.txt\")
|
||||
endif()
|
||||
"
|
||||
COMPONENT Payload
|
||||
BUILD_DEPENDS generate_code_payload
|
||||
)
|
||||
|
||||
# Directory content generated by a custom target can only be installed
|
||||
# after the preparation target has generated it.
|
||||
set(dir_payload "${CMAKE_CURRENT_BINARY_DIR}/dir-payload")
|
||||
add_custom_target(generate_dir_payload
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${dir_payload}"
|
||||
COMMAND ${CMAKE_COMMAND} -E touch "${dir_payload}/dir-payload.txt"
|
||||
)
|
||||
install(DIRECTORY "${dir_payload}/"
|
||||
DESTINATION share/install-prep
|
||||
COMPONENT Payload
|
||||
BUILD_DEPENDS generate_dir_payload
|
||||
)
|
||||
|
||||
# BUILD_DEPENDS may also name files. A file that the build generates is
|
||||
# prepared like an installed file, and an existing file needs no preparation.
|
||||
set(code_file "${CMAKE_CURRENT_BINARY_DIR}/code-file.txt")
|
||||
add_custom_command(OUTPUT "${code_file}"
|
||||
COMMAND ${CMAKE_COMMAND} -E touch "${code_file}"
|
||||
)
|
||||
add_custom_target(generate_code_file DEPENDS "${code_file}")
|
||||
install(CODE "
|
||||
if(NOT EXISTS \"${code_file}\")
|
||||
message(FATAL_ERROR \"Preparation did not generate code-file.txt\")
|
||||
endif()
|
||||
"
|
||||
COMPONENT Payload
|
||||
BUILD_DEPENDS "${code_file}" "${CMAKE_CURRENT_SOURCE_DIR}/lib.c"
|
||||
)
|
||||
|
||||
add_subdirectory(build-depends)
|
||||
|
||||
# BUILD_DEPENDS may also name the artifact linked by a target.
|
||||
set(artifact_dir "${CMAKE_CURRENT_BINARY_DIR}/artifacts")
|
||||
add_library(depends_artifact STATIC EXCLUDE_FROM_ALL lib.c)
|
||||
set_property(TARGET depends_artifact
|
||||
PROPERTY ARCHIVE_OUTPUT_DIRECTORY "$<1:${artifact_dir}>")
|
||||
set(depends_artifact_file "${artifact_dir}/${CMAKE_STATIC_LIBRARY_PREFIX}depends_artifact${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
install(CODE "
|
||||
if(NOT EXISTS \"${depends_artifact_file}\")
|
||||
message(FATAL_ERROR \"Preparation did not build depends_artifact\")
|
||||
endif()
|
||||
"
|
||||
COMPONENT Payload
|
||||
BUILD_DEPENDS "${depends_artifact_file}"
|
||||
)
|
||||
|
||||
add_library(unit_tests STATIC neverbuild.c)
|
||||
@@ -122,6 +122,7 @@ run_install_prep(Imported install_prep/Imported Imported)
|
||||
run_install_prep(Documentation install_prep/Documentation Documentation)
|
||||
run_install_prep(ExcludedSubdirectory
|
||||
install_prep/ExcludedSubdirectory ExcludedSubdirectory)
|
||||
run_install_prep(BuildDepends install_prep/Payload Payload)
|
||||
run_install_prep(GeneratedFileSetHeaders install_prep/Headers Headers)
|
||||
run_install_prep(GeneratedTargetProperties install_prep/Headers Headers)
|
||||
run_install_prep(GeneratedByOtherTarget install_prep/Headers Headers)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Relative BUILD_DEPENDS files are interpreted with respect to this directory:
|
||||
# the source directory if the file exists there, and otherwise the binary
|
||||
# directory.
|
||||
add_custom_command(OUTPUT relative-file.txt
|
||||
COMMAND ${CMAKE_COMMAND} -E touch relative-file.txt
|
||||
)
|
||||
add_custom_target(generate_relative_file DEPENDS relative-file.txt)
|
||||
install(CODE "
|
||||
if(NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/relative-file.txt\")
|
||||
message(FATAL_ERROR \"Preparation did not generate relative-file.txt\")
|
||||
endif()
|
||||
"
|
||||
COMPONENT Payload
|
||||
BUILD_DEPENDS relative-file.txt CMakeLists.txt
|
||||
)
|
||||
@@ -0,0 +1,2 @@
|
||||
check_installed([[^$]])
|
||||
check_prepared(all_components_dependency)
|
||||
@@ -0,0 +1,9 @@
|
||||
enable_language(C)
|
||||
|
||||
add_library(all_components_dependency STATIC obj1.c)
|
||||
install(CODE [[message(STATUS "CODE-BUILD_DEPENDS-all-components executed")]]
|
||||
BUILD_DEPENDS all_components_dependency ALL_COMPONENTS)
|
||||
|
||||
install(CODE "message(STATUS dev)" COMPONENT dev)
|
||||
install(CODE "message(STATUS other)" COMPONENT other)
|
||||
add_library(unrelated STATIC never-build.c)
|
||||
@@ -0,0 +1,2 @@
|
||||
check_installed([[^$]])
|
||||
check_prepared(code_dependency_one code_dependency_two)
|
||||
@@ -0,0 +1,13 @@
|
||||
enable_language(C)
|
||||
|
||||
add_library(code_dependency_one STATIC obj1.c)
|
||||
add_library(code_dependency_two STATIC obj1.c)
|
||||
|
||||
install(CODE [[message(STATUS "CODE-BUILD_DEPENDS executed")]]
|
||||
BUILD_DEPENDS code_dependency_one
|
||||
BUILD_DEPENDS code_dependency_two
|
||||
COMPONENT dev)
|
||||
|
||||
add_library(unrelated STATIC never-build.c)
|
||||
add_library(other_dependency STATIC never-build.c)
|
||||
install(CODE "message(STATUS other)" BUILD_DEPENDS other_dependency COMPONENT other)
|
||||
@@ -0,0 +1,2 @@
|
||||
check_installed([[^empty\.txt$]])
|
||||
check_prepared(dir_dependency_one dir_dependency_two)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,8 @@
|
||||
^CMake Error at DIRECTORY-BUILD_DEPENDS-missing-target\.cmake:[0-9]+ \(install\):
|
||||
install\(DIRECTORY\) BUILD_DEPENDS entry "missing_target" is neither a target
|
||||
nor a file that exists or is generated by the build\.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Generate step failed\. Build files cannot be regenerated correctly\.$
|
||||
@@ -0,0 +1 @@
|
||||
install(DIRECTORY dir/ DESTINATION . BUILD_DEPENDS missing_target)
|
||||
@@ -0,0 +1,19 @@
|
||||
enable_language(C)
|
||||
|
||||
install(DIRECTORY dir/
|
||||
DESTINATION .
|
||||
BUILD_DEPENDS dir_dependency_one
|
||||
BUILD_DEPENDS dir_dependency_two
|
||||
COMPONENT dev)
|
||||
|
||||
# Resolve dependency names during generation, after these targets are defined.
|
||||
add_library(dir_dependency_one STATIC obj1.c)
|
||||
add_library(dir_dependency_two STATIC obj1.c)
|
||||
|
||||
# Only rules for the selected component and configuration may add dependencies.
|
||||
add_library(unrelated STATIC never-build.c)
|
||||
add_library(other_dependency STATIC never-build.c)
|
||||
install(DIRECTORY missing/ DESTINATION . OPTIONAL
|
||||
BUILD_DEPENDS other_dependency COMPONENT other)
|
||||
install(DIRECTORY missing/ DESTINATION . OPTIONAL
|
||||
BUILD_DEPENDS other_dependency COMPONENT dev CONFIGURATIONS Release)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,4 @@
|
||||
^CMake Error at DIRECTORY-PATTERN-BUILD_DEPENDS\.cmake:[0-9]+ \(install\):
|
||||
install DIRECTORY does not allow "BUILD_DEPENDS" after PATTERN or REGEX\.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
@@ -0,0 +1 @@
|
||||
install(DIRECTORY src DESTINATION src PATTERN *.txt BUILD_DEPENDS dep)
|
||||
@@ -0,0 +1,2 @@
|
||||
check_installed([[^one\.txt$]])
|
||||
check_prepared(alias_dependency)
|
||||
@@ -0,0 +1,10 @@
|
||||
enable_language(C)
|
||||
|
||||
add_library(alias_dependency STATIC obj1.c)
|
||||
add_library(Upstream::alias_dependency ALIAS alias_dependency)
|
||||
|
||||
install(FILES one.txt DESTINATION .
|
||||
BUILD_DEPENDS Upstream::alias_dependency
|
||||
COMPONENT dev)
|
||||
|
||||
add_library(unrelated STATIC never-build.c)
|
||||
@@ -0,0 +1,2 @@
|
||||
check_installed([[^one\.txt;two\.txt$]])
|
||||
check_prepared(file_dependency_one file_dependency_two)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,8 @@
|
||||
^CMake Error at FILES-BUILD_DEPENDS-missing-target\.cmake:[0-9]+ \(install\):
|
||||
install\(FILES\) BUILD_DEPENDS entry "missing_target" is neither a target nor
|
||||
a file that exists or is generated by the build\.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Generate step failed\. Build files cannot be regenerated correctly\.$
|
||||
@@ -0,0 +1 @@
|
||||
install(FILES empty.c DESTINATION . BUILD_DEPENDS missing_target)
|
||||
@@ -0,0 +1,19 @@
|
||||
enable_language(C)
|
||||
|
||||
install(FILES one.txt two.txt
|
||||
DESTINATION .
|
||||
BUILD_DEPENDS file_dependency_one
|
||||
BUILD_DEPENDS file_dependency_two
|
||||
COMPONENT dev)
|
||||
|
||||
# Resolve dependency names during generation, after these targets are defined.
|
||||
add_library(file_dependency_one STATIC obj1.c)
|
||||
add_library(file_dependency_two STATIC obj1.c)
|
||||
|
||||
# Only rules for the selected component and configuration may add dependencies.
|
||||
add_library(unrelated STATIC never-build.c)
|
||||
add_library(other_dependency STATIC never-build.c)
|
||||
install(FILES missing.txt DESTINATION .
|
||||
BUILD_DEPENDS other_dependency COMPONENT other)
|
||||
install(FILES missing.txt DESTINATION .
|
||||
BUILD_DEPENDS other_dependency COMPONENT dev CONFIGURATIONS Release)
|
||||
@@ -0,0 +1,2 @@
|
||||
check_installed([[^program\.sh$]])
|
||||
check_prepared(program_dependency)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,8 @@
|
||||
^CMake Error at PROGRAMS-BUILD_DEPENDS-missing-target\.cmake:[0-9]+ \(install\):
|
||||
install\(PROGRAMS\) BUILD_DEPENDS entry "missing_target" is neither a target
|
||||
nor a file that exists or is generated by the build\.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Generate step failed\. Build files cannot be regenerated correctly\.$
|
||||
@@ -0,0 +1 @@
|
||||
install(PROGRAMS empty.c DESTINATION . BUILD_DEPENDS missing_target)
|
||||
@@ -0,0 +1,10 @@
|
||||
enable_language(C)
|
||||
|
||||
add_library(program_dependency STATIC obj1.c)
|
||||
install(PROGRAMS program.sh
|
||||
DESTINATION . BUILD_DEPENDS program_dependency COMPONENT tools)
|
||||
|
||||
add_library(unrelated STATIC never-build.c)
|
||||
add_library(excluded_dependency STATIC never-build.c)
|
||||
install(PROGRAMS missing.sh DESTINATION .
|
||||
BUILD_DEPENDS excluded_dependency COMPONENT hidden EXCLUDE_FROM_ALL)
|
||||
@@ -3,20 +3,47 @@ include(RunCMake)
|
||||
|
||||
# Function to build and install a project. The latter step *-check.cmake
|
||||
# scripts can check installed files using the check_installed function.
|
||||
# Optional second and third arguments select an install component and configuration.
|
||||
function(run_install_test case)
|
||||
set(COMPONENT all)
|
||||
set(COMPONENT_ARGS)
|
||||
if(ARGC GREATER 1)
|
||||
set(COMPONENT "${ARGV1}")
|
||||
set(COMPONENT_ARGS "-DCOMPONENT=${COMPONENT}")
|
||||
endif()
|
||||
set(CONFIG Debug)
|
||||
if(ARGC GREATER 2)
|
||||
set(CONFIG "${ARGV2}")
|
||||
endif()
|
||||
set(RunCMake_TEST_CONFIG "")
|
||||
if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
set(RunCMake_TEST_CONFIG "${CONFIG}")
|
||||
endif()
|
||||
set(BUILD_ARGS)
|
||||
if(run_install_test_prep)
|
||||
set(BUILD_ARGS --target install_prep/${COMPONENT})
|
||||
endif()
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
|
||||
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
|
||||
set(RunCMake_TEST_RAW_ARGS -DCMAKE_BUILD_TYPE:STRING=Debug)
|
||||
set(CMAKE_INSTALL_PREFIX ${RunCMake_TEST_BINARY_DIR}/root-${COMPONENT})
|
||||
if(run_install_test_prep)
|
||||
list(APPEND RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
set(RunCMake_TEST_RAW_ARGS -DCMAKE_BUILD_TYPE:STRING=${CONFIG})
|
||||
run_cmake(${case})
|
||||
unset(RunCMake_TEST_RAW_ARGS)
|
||||
set(RunCMake_TEST_OUTPUT_MERGE 1)
|
||||
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug)
|
||||
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config ${CONFIG} ${BUILD_ARGS})
|
||||
unset(RunCMake_TEST_OUTPUT_MERGE)
|
||||
# Check "all" components.
|
||||
set(CMAKE_INSTALL_PREFIX ${RunCMake_TEST_BINARY_DIR}/root-all)
|
||||
run_cmake_command(${case}-all ${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DBUILD_TYPE=Debug -P cmake_install.cmake)
|
||||
if(run_install_test_prep)
|
||||
if(EXISTS "${CMAKE_INSTALL_PREFIX}")
|
||||
message(SEND_ERROR "${case}: preparation ran installation.")
|
||||
endif()
|
||||
set(RunCMake-check-file ${case}-install-check.cmake)
|
||||
endif()
|
||||
run_cmake_command(${case}-${COMPONENT} ${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DBUILD_TYPE=${CONFIG} ${COMPONENT_ARGS} -P cmake_install.cmake)
|
||||
|
||||
if(run_install_test_components)
|
||||
# Check unspecified component.
|
||||
@@ -68,6 +95,19 @@ function(check_namelink link expect)
|
||||
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Function called in *-check.cmake scripts to check that preparing for
|
||||
# installation built the given static library targets.
|
||||
function(check_prepared)
|
||||
foreach(target IN LISTS ARGN)
|
||||
if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${RunCMake_TEST_CONFIG}/lib${target}.a" AND
|
||||
NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${RunCMake_TEST_CONFIG}/${target}.lib" AND
|
||||
NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${RunCMake_TEST_CONFIG}/${target}.l")
|
||||
set(RunCMake_TEST_FAILED "Build did not produce ${target}." PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# Wrapper for run_cmake() that skips platforms on which we do not support editing the RPATH.
|
||||
function(run_cmake_EDIT_RPATH_only case)
|
||||
if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT MATCHES "^(ELF|XCOFF)$")
|
||||
@@ -93,6 +133,27 @@ if (CMake_TEST_install_VARIANT STREQUAL "Files")
|
||||
run_cmake(SkipInstallRulesNoWarning1)
|
||||
run_cmake(SkipInstallRulesNoWarning2)
|
||||
run_cmake(SCRIPT-CODE-arguments)
|
||||
run_cmake(DIRECTORY-PATTERN-BUILD_DEPENDS)
|
||||
run_cmake(SCRIPT-BUILD_DEPENDS-missing-target)
|
||||
run_cmake(FILES-BUILD_DEPENDS-missing-target)
|
||||
run_cmake(PROGRAMS-BUILD_DEPENDS-missing-target)
|
||||
run_cmake(DIRECTORY-BUILD_DEPENDS-missing-target)
|
||||
if(RunCMake_GENERATOR MATCHES "Ninja|Make|FASTBuild")
|
||||
block()
|
||||
set(run_install_test_prep 1)
|
||||
run_install_test(CODE-BUILD_DEPENDS dev)
|
||||
run_install_test(CODE-BUILD_DEPENDS-all-components)
|
||||
run_install_test(CODE-BUILD_DEPENDS-all-components dev)
|
||||
run_install_test(CODE-BUILD_DEPENDS-all-components other)
|
||||
run_install_test(SCRIPT-BUILD_DEPENDS)
|
||||
run_install_test(SCRIPT-BUILD_DEPENDS Unspecified)
|
||||
run_install_test(FILES-BUILD_DEPENDS dev)
|
||||
run_install_test(PROGRAMS-BUILD_DEPENDS)
|
||||
run_install_test(PROGRAMS-BUILD_DEPENDS tools)
|
||||
run_install_test(FILES-BUILD_DEPENDS-alias dev)
|
||||
run_install_test(DIRECTORY-BUILD_DEPENDS dev)
|
||||
endblock()
|
||||
endif()
|
||||
run_cmake(DIRECTORY-DIRECTORY-bad)
|
||||
run_cmake(DIRECTORY-DESTINATION-bad)
|
||||
run_cmake(FILES-DESTINATION-bad)
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
check_installed([[^empty1\.txt$]])
|
||||
check_prepared(script_dependency)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,8 @@
|
||||
^CMake Error at SCRIPT-BUILD_DEPENDS-missing-target\.cmake:[0-9]+ \(install\):
|
||||
install\(SCRIPT\) BUILD_DEPENDS entry "missing_target" is neither a target
|
||||
nor a file that exists or is generated by the build\.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Generate step failed\. Build files cannot be regenerated correctly\.$
|
||||
@@ -0,0 +1,3 @@
|
||||
install(SCRIPT install_script.cmake
|
||||
BUILD_DEPENDS missing_target
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
enable_language(C)
|
||||
|
||||
add_library(script_dependency STATIC obj1.c)
|
||||
install(SCRIPT install_script.cmake BUILD_DEPENDS script_dependency)
|
||||
|
||||
# Full preparation must omit both unrelated and excluded dependencies.
|
||||
add_library(unrelated STATIC never-build.c)
|
||||
add_library(excluded_dependency STATIC never-build.c)
|
||||
install(CODE "message(STATUS hidden)" BUILD_DEPENDS excluded_dependency
|
||||
COMPONENT hidden EXCLUDE_FROM_ALL)
|
||||
@@ -0,0 +1 @@
|
||||
#error install_prep built an unexpected target
|
||||
@@ -0,0 +1 @@
|
||||
one
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
exit 0
|
||||
@@ -0,0 +1 @@
|
||||
script payload
|
||||
@@ -0,0 +1 @@
|
||||
two
|
||||
Reference in new issue
Block a user