summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml6
-rw-r--r--.gitlab/os-linux.yml2
-rw-r--r--Help/generator/Ninja Multi-Config.rst3
-rw-r--r--Help/manual/cmake.1.rst28
-rw-r--r--Help/manual/presets/example.json23
-rw-r--r--Help/release/dev/0-sample-topic.rst7
-rw-r--r--Help/release/index.rst2
-rw-r--r--Source/CMakeVersion.cmake4
-rw-r--r--Source/cmAddCustomCommandCommand.cxx13
-rw-r--r--Source/cmGeneratorTarget.cxx5
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx6
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx14
-rw-r--r--Source/cmLocalGenerator.cxx200
-rw-r--r--Source/cmLocalGenerator.h73
-rw-r--r--Source/cmMakefile.cxx252
-rw-r--r--Source/cmMakefile.h93
-rw-r--r--Tests/RunCMake/CMakePresets/DocumentationExample.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt2
19 files changed, 346 insertions, 399 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index eda96ae..1a94a3d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -52,7 +52,7 @@ prep:doc-package:
- .cmake_doc_artifacts
- .run_only_for_package
-.upload:source-package:
+upload:source-package:
extends:
- .rsync_upload
- .run_only_for_package
@@ -175,7 +175,7 @@ build:linux-x86_64-package:
needs:
- prep:doc-package
-.upload:linux-x86_64-package:
+upload:linux-x86_64-package:
extends:
- .rsync_upload
- .run_only_for_package
@@ -250,7 +250,7 @@ build:macos-package:
needs:
- prep:doc-package
-.upload:macos-package:
+upload:macos-package:
extends:
- .rsync_upload
- .run_only_for_package
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 8e7a854..217442f 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -52,7 +52,7 @@
image: "kitware/cmake:ci-fedora31-x86_64-2020-10-03"
variables:
- GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci/long file name for testing purposes"
#### Lint builds
diff --git a/Help/generator/Ninja Multi-Config.rst b/Help/generator/Ninja Multi-Config.rst
index e6c7a1c..112db74 100644
--- a/Help/generator/Ninja Multi-Config.rst
+++ b/Help/generator/Ninja Multi-Config.rst
@@ -21,8 +21,7 @@ are intended to be run with ``ninja -f build-<Config>.ninja``. A
``cmake --build . --config <Config>`` will always use ``build-<Config>.ninja``
to build. If no ``--config`` argument is specified, ``cmake --build .`` will
-default to ``build-Debug.ninja``, unless a ``build.ninja`` is generated (see
-below), in which case that will be used instead.
+use ``build.ninja``.
Each ``build-<Config>.ninja`` file contains ``<target>`` targets as well as
``<target>:<Config>`` targets, where ``<Config>`` is the same as the
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 0f00f53..b345db0 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -174,32 +174,8 @@ source and build trees and generate a buildsystem:
The files are a JSON document with an object as the root:
- .. code-block:: json
-
- {
- "version": 1,
- "cmakeMinimumRequired": {
- "major": 3,
- "minor": 19,
- "patch": 0
- },
- "configurePresets": [
- {
- "name": "default",
- "displayName": "Default Config",
- "description": "Default build using Ninja generator",
- "generator": "Ninja",
- "binaryDir": "${sourceDir}/build/default",
- "cacheVariables": [
- {
- "name": "MY_CACHE_VARIABLE",
- "type": "BOOL",
- "value": "OFF"
- }
- ]
- }
- ]
- }
+ .. literalinclude:: presets/example.json
+ :language: json
The root object recognizes the following fields:
diff --git a/Help/manual/presets/example.json b/Help/manual/presets/example.json
new file mode 100644
index 0000000..a299a06
--- /dev/null
+++ b/Help/manual/presets/example.json
@@ -0,0 +1,23 @@
+{
+ "version": 1,
+ "cmakeMinimumRequired": {
+ "major": 3,
+ "minor": 19,
+ "patch": 0
+ },
+ "configurePresets": [
+ {
+ "name": "default",
+ "displayName": "Default Config",
+ "description": "Default build using Ninja generator",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build/default",
+ "cacheVariables": {
+ "MY_CACHE_VARIABLE": {
+ "type": "BOOL",
+ "value": "OFF"
+ }
+ }
+ }
+ ]
+}
diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst
new file mode 100644
index 0000000..e4cc01e
--- /dev/null
+++ b/Help/release/dev/0-sample-topic.rst
@@ -0,0 +1,7 @@
+0-sample-topic
+--------------
+
+* This is a sample release note for the change in a topic.
+ Developers should add similar notes for each topic branch
+ making a noteworthy change. Each document should be named
+ and titled to match the topic name to avoid merge conflicts.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 6fb0f1a..a8329a6 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -7,6 +7,8 @@ CMake Release Notes
This file should include the adjacent "dev.txt" file
in development versions but not in release versions.
+.. include:: dev.txt
+
Releases
========
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 8c36e7a..d1cc7e4 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,8 +1,8 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 19)
-set(CMake_VERSION_PATCH 0)
-set(CMake_VERSION_RC 0)
+set(CMake_VERSION_PATCH 20201012)
+#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
# Start with the full version number used in tags. It has no dev info.
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index 231a2d6..bea89c0 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -314,16 +314,9 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
// Check for an append request.
if (append) {
- if (mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends,
- commandLines)) {
- return true;
- }
-
- // No command for this output exists.
- status.SetError(
- cmStrCat("given APPEND option with output\n ", output[0],
- "\nwhich is not already a custom command output."));
- return false;
+ mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends,
+ commandLines);
+ return true;
}
if (uses_terminal && !job_pool.empty()) {
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index bdea9fa..6ebc9e1 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -2986,7 +2986,8 @@ void cmTargetTraceDependencies::FollowName(std::string const& name)
auto i = this->NameMap.lower_bound(name);
if (i == this->NameMap.end() || i->first != name) {
// Check if we know how to generate this file.
- cmSourcesWithOutput sources = this->Makefile->GetSourcesWithOutput(name);
+ cmSourcesWithOutput sources =
+ this->LocalGenerator->GetSourcesWithOutput(name);
// If we failed to find a target or source and we have a relative path, it
// might be a valid source if made relative to the current binary
// directory.
@@ -2996,7 +2997,7 @@ void cmTargetTraceDependencies::FollowName(std::string const& name)
cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name);
fullname = cmSystemTools::CollapseFullPath(
fullname, this->Makefile->GetHomeOutputDirectory());
- sources = this->Makefile->GetSourcesWithOutput(fullname);
+ sources = this->LocalGenerator->GetSourcesWithOutput(fullname);
}
i = this->NameMap.emplace_hint(i, name, sources);
}
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index a8f8f57..ed50067 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -763,9 +763,9 @@ bool cmGhsMultiTargetGenerator::VisitCustomCommand(
/* set temporary mark; check if revisit*/
if (temp.insert(si).second) {
for (auto& di : si->GetCustomCommand()->GetDepends()) {
- cmSourceFile const* sf = this->GeneratorTarget->GetLocalGenerator()
- ->GetMakefile()
- ->GetSourceFileWithOutput(di);
+ cmSourceFile const* sf =
+ this->GeneratorTarget->GetLocalGenerator()->GetSourceFileWithOutput(
+ di);
/* if sf exists then visit */
if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
return true;
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 6b9a0f3..985f430 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -2532,14 +2532,14 @@ bool cmGlobalNinjaMultiGenerator::OpenBuildFileStreams()
return false;
}
- if (!this->DefaultFileConfig.empty()) {
- if (!this->OpenFileStream(this->DefaultFileStream, NINJA_BUILD_FILE)) {
- return false;
- }
- *this->DefaultFileStream
- << "# Build using rules for '" << this->DefaultFileConfig << "'.\n\n"
- << "include " << GetNinjaImplFilename(this->DefaultFileConfig) << "\n\n";
+ if (!this->OpenFileStream(this->DefaultFileStream, NINJA_BUILD_FILE)) {
+ return false;
}
+ *this->DefaultFileStream << "# Build using rules for '"
+ << this->DefaultFileConfig << "'.\n\n"
+ << "include "
+ << GetNinjaImplFilename(this->DefaultFileConfig)
+ << "\n\n";
// Write a comment about this file.
*this->CommonFileStream
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 4e6010c..b7ad78a 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -3918,10 +3918,35 @@ cmSourceFile* AddCustomCommand(
cc->SetJobPool(job_pool);
file->SetCustomCommand(std::move(cc));
- mf->AddSourceOutputs(file, outputs, byproducts);
+ lg.AddSourceOutputs(file, outputs, byproducts);
}
return file;
}
+
+bool AnyOutputMatches(const std::string& name,
+ const std::vector<std::string>& outputs)
+{
+ for (std::string const& output : outputs) {
+ std::string::size_type pos = output.rfind(name);
+ // If the output matches exactly
+ if (pos != std::string::npos && pos == output.size() - name.size() &&
+ (pos == 0 || output[pos - 1] == '/')) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AnyTargetCommandOutputMatches(
+ const std::string& name, const std::vector<cmCustomCommand>& commands)
+{
+ for (cmCustomCommand const& command : commands) {
+ if (AnyOutputMatches(name, command.GetByproducts())) {
+ return true;
+ }
+ }
+ return false;
+}
}
namespace detail {
@@ -3937,8 +3962,6 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg,
const std::string& job_pool,
bool command_expand_lists, bool stdPipesUTF8)
{
- cmMakefile* mf = lg.GetMakefile();
-
// Always create the byproduct sources and mark them generated.
CreateGeneratedSources(lg, byproducts, origin, lfbt);
@@ -3964,7 +3987,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg,
break;
}
- mf->AddTargetByproducts(target, byproducts);
+ lg.AddTargetByproducts(target, byproducts);
}
cmSourceFile* AddCustomCommandToOutput(
@@ -3996,7 +4019,7 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
const cmCustomCommandLines& commandLines)
{
// Lookup an existing command.
- if (cmSourceFile* sf = lg.GetMakefile()->GetSourceFileWithOutput(output)) {
+ if (cmSourceFile* sf = lg.GetSourceFileWithOutput(output)) {
if (cmCustomCommand* cc = sf->GetCustomCommand()) {
cc->AppendCommands(commandLines);
cc->AppendDepends(depends);
@@ -4008,7 +4031,7 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
// No existing command found.
lg.GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
- cmStrCat("Attempt to append to output\n ", output,
+ cmStrCat("Attempt to APPEND to custom command with output\n ", output,
"\nwhich is not already a custom command output."),
lfbt);
}
@@ -4040,7 +4063,7 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
/*replace=*/false, escapeOldStyle, uses_terminal, command_expand_lists,
/*depfile=*/"", job_pool, stdPipesUTF8);
if (rule) {
- lg.GetMakefile()->AddTargetByproducts(target, byproducts);
+ lg.AddTargetByproducts(target, byproducts);
}
if (!force.NameCMP0049.empty()) {
@@ -4088,3 +4111,166 @@ std::vector<std::string> ComputeISPCExtraObjects(
return computedObjects;
}
}
+
+cmSourcesWithOutput cmLocalGenerator::GetSourcesWithOutput(
+ const std::string& name) const
+{
+ // Linear search? Also see GetSourceFileWithOutput for detail.
+ if (!cmSystemTools::FileIsFullPath(name)) {
+ cmSourcesWithOutput sources;
+ sources.Target = this->LinearGetTargetWithOutput(name);
+ sources.Source = this->LinearGetSourceFileWithOutput(
+ name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct);
+ return sources;
+ }
+ // Otherwise we use an efficient lookup map.
+ auto o = this->OutputToSource.find(name);
+ if (o != this->OutputToSource.end()) {
+ return o->second.Sources;
+ }
+ return {};
+}
+
+cmSourceFile* cmLocalGenerator::GetSourceFileWithOutput(
+ const std::string& name, cmSourceOutputKind kind) const
+{
+ // If the queried path is not absolute we use the backward compatible
+ // linear-time search for an output with a matching suffix.
+ if (!cmSystemTools::FileIsFullPath(name)) {
+ bool byproduct = false;
+ return this->LinearGetSourceFileWithOutput(name, kind, byproduct);
+ }
+ // Otherwise we use an efficient lookup map.
+ auto o = this->OutputToSource.find(name);
+ if (o != this->OutputToSource.end() &&
+ (!o->second.Sources.SourceIsByproduct ||
+ kind == cmSourceOutputKind::OutputOrByproduct)) {
+ // Source file could also be null pointer for example if we found the
+ // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD
+ // command of a target, or a not yet created custom command.
+ return o->second.Sources.Source;
+ }
+ return nullptr;
+}
+
+void cmLocalGenerator::AddTargetByproducts(
+ cmTarget* target, const std::vector<std::string>& byproducts)
+{
+ for (std::string const& o : byproducts) {
+ this->UpdateOutputToSourceMap(o, target);
+ }
+}
+
+void cmLocalGenerator::AddSourceOutputs(
+ cmSourceFile* source, const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts)
+{
+ for (std::string const& o : outputs) {
+ this->UpdateOutputToSourceMap(o, source, false);
+ }
+ for (std::string const& o : byproducts) {
+ this->UpdateOutputToSourceMap(o, source, true);
+ }
+}
+
+void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& byproduct,
+ cmTarget* target)
+{
+ SourceEntry entry;
+ entry.Sources.Target = target;
+
+ auto pr = this->OutputToSource.emplace(byproduct, entry);
+ if (!pr.second) {
+ SourceEntry& current = pr.first->second;
+ // Has the target already been set?
+ if (!current.Sources.Target) {
+ current.Sources.Target = target;
+ } else {
+ // Multiple custom commands/targets produce the same output (source file
+ // or target). See also comment in other UpdateOutputToSourceMap
+ // overload.
+ //
+ // TODO: Warn the user about this case.
+ }
+ }
+}
+
+void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& output,
+ cmSourceFile* source,
+ bool byproduct)
+{
+ SourceEntry entry;
+ entry.Sources.Source = source;
+ entry.Sources.SourceIsByproduct = byproduct;
+
+ auto pr = this->OutputToSource.emplace(output, entry);
+ if (!pr.second) {
+ SourceEntry& current = pr.first->second;
+ // Outputs take precedence over byproducts
+ if (!current.Sources.Source ||
+ (current.Sources.SourceIsByproduct && !byproduct)) {
+ current.Sources.Source = source;
+ current.Sources.SourceIsByproduct = false;
+ } else {
+ // Multiple custom commands produce the same output but may
+ // be attached to a different source file (MAIN_DEPENDENCY).
+ // LinearGetSourceFileWithOutput would return the first one,
+ // so keep the mapping for the first one.
+ //
+ // TODO: Warn the user about this case. However, the VS 8 generator
+ // triggers it for separate generate.stamp rules in ZERO_CHECK and
+ // individual targets.
+ }
+ }
+}
+
+cmTarget* cmLocalGenerator::LinearGetTargetWithOutput(
+ const std::string& name) const
+{
+ // We go through the ordered vector of targets to get reproducible results
+ // should multiple names match.
+ for (cmTarget* t : this->Makefile->GetOrderedTargets()) {
+ // Does the output of any command match the source file name?
+ if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) {
+ return t;
+ }
+ if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) {
+ return t;
+ }
+ if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) {
+ return t;
+ }
+ }
+ return nullptr;
+}
+
+cmSourceFile* cmLocalGenerator::LinearGetSourceFileWithOutput(
+ const std::string& name, cmSourceOutputKind kind, bool& byproduct) const
+{
+ // Outputs take precedence over byproducts.
+ byproduct = false;
+ cmSourceFile* fallback = nullptr;
+
+ // Look through all the source files that have custom commands and see if the
+ // custom command has the passed source file as an output.
+ for (const auto& src : this->Makefile->GetSourceFiles()) {
+ // Does this source file have a custom command?
+ if (src->GetCustomCommand()) {
+ // Does the output of the custom command match the source file name?
+ if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
+ // Return the first matching output.
+ return src.get();
+ }
+ if (kind == cmSourceOutputKind::OutputOrByproduct) {
+ if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
+ // Do not return the source yet as there might be a matching output.
+ fallback = src.get();
+ }
+ }
+ }
+ }
+
+ // Did we find a byproduct?
+ byproduct = fallback != nullptr;
+ return fallback;
+}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 22d3599..162e70f 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -36,6 +36,24 @@ class cmState;
class cmTarget;
class cmake;
+/** Flag if byproducts shall also be considered. */
+enum class cmSourceOutputKind
+{
+ OutputOnly,
+ OutputOrByproduct
+};
+
+/** Target and source file which have a specific output. */
+struct cmSourcesWithOutput
+{
+ /** Target with byproduct. */
+ cmTarget* Target = nullptr;
+
+ /** Source file with output or byproduct. */
+ cmSourceFile* Source = nullptr;
+ bool SourceIsByproduct = false;
+};
+
/** \class cmLocalGenerator
* \brief Create required build files for a directory.
*
@@ -337,6 +355,34 @@ public:
bool command_expand_lists = false, const std::string& job_pool = "",
bool stdPipesUTF8 = false);
+ /**
+ * Add target byproducts.
+ */
+ void AddTargetByproducts(cmTarget* target,
+ const std::vector<std::string>& byproducts);
+
+ /**
+ * Add source file outputs.
+ */
+ void AddSourceOutputs(cmSourceFile* source,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts);
+
+ /**
+ * Return the target if the provided source name is a byproduct of a utility
+ * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command.
+ * Return the source file which has the provided source name as output.
+ */
+ cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const;
+
+ /**
+ * Is there a source file that has the provided source name as an output?
+ * If so then return it.
+ */
+ cmSourceFile* GetSourceFileWithOutput(
+ const std::string& name,
+ cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const;
+
std::string GetProjectName() const;
/** Compute the language used to compile the given source file. */
@@ -532,6 +578,33 @@ protected:
bool BackwardsCompatibilityFinal;
private:
+ /**
+ * See LinearGetSourceFileWithOutput for background information
+ */
+ cmTarget* LinearGetTargetWithOutput(const std::string& name) const;
+
+ /**
+ * Generalized old version of GetSourceFileWithOutput kept for
+ * backward-compatibility. It implements a linear search and supports
+ * relative file paths. It is used as a fall back by GetSourceFileWithOutput
+ * and GetSourcesWithOutput.
+ */
+ cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name,
+ cmSourceOutputKind kind,
+ bool& byproduct) const;
+ struct SourceEntry
+ {
+ cmSourcesWithOutput Sources;
+ };
+
+ // A map for fast output to input look up.
+ using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>;
+ OutputToSourceMap OutputToSource;
+
+ void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target);
+ void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source,
+ bool byproduct);
+
void AddSharedFlags(std::string& flags, const std::string& lang,
bool shared);
bool GetShouldUseOldFlags(bool shared, const std::string& lang) const;
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 14ec689..9286e93 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -939,8 +939,6 @@ void cmMakefile::DoGenerate(cmLocalGenerator& lg)
action.Value(lg, action.Backtrace);
}
this->GeneratorActionsInvoked = true;
- this->DelayedOutputFiles.clear();
- this->DelayedOutputFilesHaveGenex = false;
// go through all configured files and see which ones still exist.
// we don't want cmake to re-run if a configured file is created and deleted
@@ -1104,7 +1102,7 @@ cmTarget* cmMakefile::AddCustomCommandToTarget(
}
// Always create the byproduct sources and mark them generated.
- this->CreateGeneratedByproducts(byproducts);
+ this->CreateGeneratedOutputs(byproducts);
// Strings could be moved into the callback function with C++14.
cm::optional<std::string> commentStr = MakeOptionalString(comment);
@@ -1163,7 +1161,7 @@ void cmMakefile::AddCustomCommandToOutput(
// Always create the output sources and mark them generated.
this->CreateGeneratedOutputs(outputs);
- this->CreateGeneratedByproducts(byproducts);
+ this->CreateGeneratedOutputs(byproducts);
// Strings could be moved into the callback function with C++14.
cm::optional<std::string> commentStr = MakeOptionalString(comment);
@@ -1247,16 +1245,11 @@ void cmMakefile::AddCustomCommandOldStyle(
}
}
-bool cmMakefile::AppendCustomCommandToOutput(
+void cmMakefile::AppendCustomCommandToOutput(
const std::string& output, const std::vector<std::string>& depends,
const cmImplicitDependsList& implicit_depends,
const cmCustomCommandLines& commandLines)
{
- // Check as good as we can if there will be a command for this output.
- if (!this->MightHaveCustomCommand(output)) {
- return false;
- }
-
// Validate custom commands.
if (this->ValidateCustomCommand(commandLines)) {
// Dispatch command creation to allow generator expressions in outputs.
@@ -1267,8 +1260,6 @@ bool cmMakefile::AppendCustomCommandToOutput(
implicit_depends, commandLines);
});
}
-
- return true;
}
cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target)
@@ -1313,7 +1304,7 @@ cmTarget* cmMakefile::AddUtilityCommand(
this->GetOrCreateGeneratedSource(force.Name);
// Always create the byproduct sources and mark them generated.
- this->CreateGeneratedByproducts(byproducts);
+ this->CreateGeneratedOutputs(byproducts);
// Strings could be moved into the callback function with C++14.
cm::optional<std::string> commentStr = MakeOptionalString(comment);
@@ -2154,213 +2145,6 @@ cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName,
}
namespace {
-bool AnyOutputMatches(const std::string& name,
- const std::vector<std::string>& outputs)
-{
- for (std::string const& output : outputs) {
- std::string::size_type pos = output.rfind(name);
- // If the output matches exactly
- if (pos != std::string::npos && pos == output.size() - name.size() &&
- (pos == 0 || output[pos - 1] == '/')) {
- return true;
- }
- }
- return false;
-}
-
-bool AnyTargetCommandOutputMatches(
- const std::string& name, const std::vector<cmCustomCommand>& commands)
-{
- for (cmCustomCommand const& command : commands) {
- if (AnyOutputMatches(name, command.GetByproducts())) {
- return true;
- }
- }
- return false;
-}
-}
-
-cmTarget* cmMakefile::LinearGetTargetWithOutput(const std::string& name) const
-{
- // We go through the ordered vector of targets to get reproducible results
- // should multiple names match.
- for (cmTarget* t : this->OrderedTargets) {
- // Does the output of any command match the source file name?
- if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) {
- return t;
- }
- if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) {
- return t;
- }
- if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) {
- return t;
- }
- }
- return nullptr;
-}
-
-cmSourceFile* cmMakefile::LinearGetSourceFileWithOutput(
- const std::string& name, cmSourceOutputKind kind, bool& byproduct) const
-{
- // Outputs take precedence over byproducts.
- byproduct = false;
- cmSourceFile* fallback = nullptr;
-
- // Look through all the source files that have custom commands and see if the
- // custom command has the passed source file as an output.
- for (const auto& src : this->SourceFiles) {
- // Does this source file have a custom command?
- if (src->GetCustomCommand()) {
- // Does the output of the custom command match the source file name?
- if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
- // Return the first matching output.
- return src.get();
- }
- if (kind == cmSourceOutputKind::OutputOrByproduct) {
- if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
- // Do not return the source yet as there might be a matching output.
- fallback = src.get();
- }
- }
- }
- }
-
- // Did we find a byproduct?
- byproduct = fallback != nullptr;
- return fallback;
-}
-
-cmSourcesWithOutput cmMakefile::GetSourcesWithOutput(
- const std::string& name) const
-{
- // Linear search? Also see GetSourceFileWithOutput for detail.
- if (!cmSystemTools::FileIsFullPath(name)) {
- cmSourcesWithOutput sources;
- sources.Target = this->LinearGetTargetWithOutput(name);
- sources.Source = this->LinearGetSourceFileWithOutput(
- name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct);
- return sources;
- }
- // Otherwise we use an efficient lookup map.
- auto o = this->OutputToSource.find(name);
- if (o != this->OutputToSource.end()) {
- return o->second.Sources;
- }
- return {};
-}
-
-cmSourceFile* cmMakefile::GetSourceFileWithOutput(
- const std::string& name, cmSourceOutputKind kind) const
-{
- // If the queried path is not absolute we use the backward compatible
- // linear-time search for an output with a matching suffix.
- if (!cmSystemTools::FileIsFullPath(name)) {
- bool byproduct = false;
- return this->LinearGetSourceFileWithOutput(name, kind, byproduct);
- }
- // Otherwise we use an efficient lookup map.
- auto o = this->OutputToSource.find(name);
- if (o != this->OutputToSource.end() &&
- (!o->second.Sources.SourceIsByproduct ||
- kind == cmSourceOutputKind::OutputOrByproduct)) {
- // Source file could also be null pointer for example if we found the
- // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD
- // command of a target, or a not yet created custom command.
- return o->second.Sources.Source;
- }
- return nullptr;
-}
-
-bool cmMakefile::MightHaveCustomCommand(const std::string& name) const
-{
- if (this->DelayedOutputFilesHaveGenex ||
- cmGeneratorExpression::Find(name) != std::string::npos) {
- // Could be more restrictive, but for now we assume that there could always
- // be a match when generator expressions are involved.
- return true;
- }
- // Also see LinearGetSourceFileWithOutput.
- if (!cmSystemTools::FileIsFullPath(name)) {
- return AnyOutputMatches(name, this->DelayedOutputFiles);
- }
- // Otherwise we use an efficient lookup map.
- auto o = this->OutputToSource.find(name);
- if (o != this->OutputToSource.end()) {
- return o->second.SourceMightBeOutput;
- }
- return false;
-}
-
-void cmMakefile::AddTargetByproducts(
- cmTarget* target, const std::vector<std::string>& byproducts)
-{
- for (std::string const& o : byproducts) {
- this->UpdateOutputToSourceMap(o, target);
- }
-}
-
-void cmMakefile::AddSourceOutputs(cmSourceFile* source,
- const std::vector<std::string>& outputs,
- const std::vector<std::string>& byproducts)
-{
- for (std::string const& o : outputs) {
- this->UpdateOutputToSourceMap(o, source, false);
- }
- for (std::string const& o : byproducts) {
- this->UpdateOutputToSourceMap(o, source, true);
- }
-}
-
-void cmMakefile::UpdateOutputToSourceMap(std::string const& byproduct,
- cmTarget* target)
-{
- SourceEntry entry;
- entry.Sources.Target = target;
-
- auto pr = this->OutputToSource.emplace(byproduct, entry);
- if (!pr.second) {
- SourceEntry& current = pr.first->second;
- // Has the target already been set?
- if (!current.Sources.Target) {
- current.Sources.Target = target;
- } else {
- // Multiple custom commands/targets produce the same output (source file
- // or target). See also comment in other UpdateOutputToSourceMap
- // overload.
- //
- // TODO: Warn the user about this case.
- }
- }
-}
-
-void cmMakefile::UpdateOutputToSourceMap(std::string const& output,
- cmSourceFile* source, bool byproduct)
-{
- SourceEntry entry;
- entry.Sources.Source = source;
- entry.Sources.SourceIsByproduct = byproduct;
- entry.SourceMightBeOutput = !byproduct;
-
- auto pr = this->OutputToSource.emplace(output, entry);
- if (!pr.second) {
- SourceEntry& current = pr.first->second;
- // Outputs take precedence over byproducts
- if (!current.Sources.Source ||
- (current.Sources.SourceIsByproduct && !byproduct)) {
- current.Sources.Source = source;
- current.Sources.SourceIsByproduct = false;
- current.SourceMightBeOutput = true;
- } else {
- // Multiple custom commands produce the same output but may
- // be attached to a different source file (MAIN_DEPENDENCY).
- // LinearGetSourceFileWithOutput would return the first one,
- // so keep the mapping for the first one.
- //
- // TODO: Warn the user about this case. However, the VS 8 generator
- // triggers it for separate generate.stamp rules in ZERO_CHECK and
- // individual targets.
- }
- }
}
#if !defined(CMAKE_BOOTSTRAP)
@@ -3676,38 +3460,10 @@ void cmMakefile::CreateGeneratedOutputs(
for (std::string const& o : outputs) {
if (cmGeneratorExpression::Find(o) == std::string::npos) {
this->GetOrCreateGeneratedSource(o);
- this->AddDelayedOutput(o);
- } else {
- this->DelayedOutputFilesHaveGenex = true;
}
}
}
-void cmMakefile::CreateGeneratedByproducts(
- const std::vector<std::string>& byproducts)
-{
- for (std::string const& o : byproducts) {
- if (cmGeneratorExpression::Find(o) == std::string::npos) {
- this->GetOrCreateGeneratedSource(o);
- }
- }
-}
-
-void cmMakefile::AddDelayedOutput(std::string const& output)
-{
- // Note that this vector might contain the output names in a different order
- // than in source file iteration order.
- this->DelayedOutputFiles.push_back(output);
-
- SourceEntry entry;
- entry.SourceMightBeOutput = true;
-
- auto pr = this->OutputToSource.emplace(output, entry);
- if (!pr.second) {
- pr.first->second.SourceMightBeOutput = true;
- }
-}
-
void cmMakefile::AddTargetObject(std::string const& tgtName,
std::string const& objFile)
{
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index c7940fb..ecc6aab 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -59,24 +59,6 @@ class cmTestGenerator;
class cmVariableWatch;
class cmake;
-/** Flag if byproducts shall also be considered. */
-enum class cmSourceOutputKind
-{
- OutputOnly,
- OutputOrByproduct
-};
-
-/** Target and source file which have a specific output. */
-struct cmSourcesWithOutput
-{
- /** Target with byproduct. */
- cmTarget* Target = nullptr;
-
- /** Source file with output or byproduct. */
- cmSourceFile* Source = nullptr;
- bool SourceIsByproduct = false;
-};
-
/** A type-safe wrapper for a string representing a directory id. */
class cmDirectoryId
{
@@ -225,25 +207,12 @@ public:
const std::string& source,
const cmCustomCommandLines& commandLines,
const char* comment);
- bool AppendCustomCommandToOutput(
+ void AppendCustomCommandToOutput(
const std::string& output, const std::vector<std::string>& depends,
const cmImplicitDependsList& implicit_depends,
const cmCustomCommandLines& commandLines);
/**
- * Add target byproducts.
- */
- void AddTargetByproducts(cmTarget* target,
- const std::vector<std::string>& byproducts);
-
- /**
- * Add source file outputs.
- */
- void AddSourceOutputs(cmSourceFile* source,
- const std::vector<std::string>& outputs,
- const std::vector<std::string>& byproducts);
-
- /**
* Add a define flag to the build.
*/
void AddDefineFlag(std::string const& definition);
@@ -753,20 +722,10 @@ public:
return this->SourceFiles;
}
- /**
- * Return the target if the provided source name is a byproduct of a utility
- * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command.
- * Return the source file which has the provided source name as output.
- */
- cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const;
-
- /**
- * Is there a source file that has the provided source name as an output?
- * If so then return it.
- */
- cmSourceFile* GetSourceFileWithOutput(
- const std::string& name,
- cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const;
+ std::vector<cmTarget*> const& GetOrderedTargets() const
+ {
+ return this->OrderedTargets;
+ }
//! Add a new cmTest to the list of tests for this makefile.
cmTest* CreateTest(const std::string& testName);
@@ -983,8 +942,7 @@ protected:
mutable cmTargetMap Targets;
std::map<std::string, std::string> AliasTargets;
- using TargetsVec = std::vector<cmTarget*>;
- TargetsVec OrderedTargets;
+ std::vector<cmTarget*> OrderedTargets;
std::vector<std::unique_ptr<cmSourceFile>> SourceFiles;
@@ -1129,48 +1087,9 @@ private:
bool ValidateCustomCommand(const cmCustomCommandLines& commandLines) const;
void CreateGeneratedOutputs(const std::vector<std::string>& outputs);
- void CreateGeneratedByproducts(const std::vector<std::string>& byproducts);
std::vector<BT<GeneratorAction>> GeneratorActions;
bool GeneratorActionsInvoked = false;
- bool DelayedOutputFilesHaveGenex = false;
- std::vector<std::string> DelayedOutputFiles;
-
- void AddDelayedOutput(std::string const& output);
-
- /**
- * See LinearGetSourceFileWithOutput for background information
- */
- cmTarget* LinearGetTargetWithOutput(const std::string& name) const;
-
- /**
- * Generalized old version of GetSourceFileWithOutput kept for
- * backward-compatibility. It implements a linear search and supports
- * relative file paths. It is used as a fall back by GetSourceFileWithOutput
- * and GetSourcesWithOutput.
- */
- cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name,
- cmSourceOutputKind kind,
- bool& byproduct) const;
-
- struct SourceEntry
- {
- cmSourcesWithOutput Sources;
- bool SourceMightBeOutput = false;
- };
-
- // A map for fast output to input look up.
- using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>;
- OutputToSourceMap OutputToSource;
-
- void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target);
- void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source,
- bool byproduct);
-
- /**
- * Return if the provided source file might have a custom command.
- */
- bool MightHaveCustomCommand(const std::string& name) const;
bool CheckSystemVars;
bool CheckCMP0000;
diff --git a/Tests/RunCMake/CMakePresets/DocumentationExample.cmake b/Tests/RunCMake/CMakePresets/DocumentationExample.cmake
new file mode 100644
index 0000000..1f2fc00
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/DocumentationExample.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(MY_CACHE_VARIABLE "BOOL" "OFF")
diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
index 4b430b3..18ea093 100644
--- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
@@ -1,3 +1,5 @@
+cmake_minimum_required(VERSION 3.19) # CMP0053
+
include(RunCMake)
# Fix Visual Studio generator name
@@ -214,3 +216,10 @@ unset(CMakePresets_WARN_UNUSED_CLI)
set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Debug.json.in")
run_cmake_presets(NoDebug)
run_cmake_presets(Debug)
+
+# Test the example from the documentation
+file(READ "${RunCMake_SOURCE_DIR}/../../../Help/manual/presets/example.json" _example)
+string(REPLACE "\"generator\": \"Ninja\"" "\"generator\": \"@RunCMake_GENERATOR@\"" _example "${_example}")
+file(WRITE "${RunCMake_BINARY_DIR}/example.json.in" "${_example}")
+set(CMakePresets_FILE "${RunCMake_BINARY_DIR}/example.json.in")
+run_cmake_presets(DocumentationExample --preset=default)
diff --git a/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt b/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt
index b7ee23a..9324302 100644
--- a/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt
+++ b/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt
@@ -1,5 +1,5 @@
CMake Error at AppendNotOutput.cmake:1 \(add_custom_command\):
- add_custom_command given APPEND option with output
+ Attempt to APPEND to custom command with output
.*RunCMake/add_custom_command/AppendNotOutput-build/out