summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorDaniel Eiband <daniel.eiband@brainlab.com>2019-10-17 17:02:20 +0200
committerDaniel Eiband <daniel.eiband@brainlab.com>2019-11-24 20:32:43 +0100
commit777ceaea94cec5c4388e3b11495904ad8e408535 (patch)
tree200a986e08bb827255315101fb1e52d843e220ab /Source
parent4e37508c8570bd6b846aa67478e97ec370ab4feb (diff)
downloadcmake-777ceaea94cec5c4388e3b11495904ad8e408535.tar.gz
cmMakefile: Delay custom command creation
Move custom command creation to cmLocalGenerator and dispatch custom commands in cmMakefile to generate time. Generators add custom commands using the new methods provided by cmLocalGenerator. Issue: #12877
Diffstat (limited to 'Source')
-rw-r--r--Source/cmAddCustomCommandCommand.cxx2
-rw-r--r--Source/cmAddCustomTargetCommand.cxx7
-rw-r--r--Source/cmCPluginAPI.cxx6
-rw-r--r--Source/cmGlobalVisualStudio8Generator.cxx11
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx6
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx19
-rw-r--r--Source/cmLocalGenerator.cxx338
-rw-r--r--Source/cmLocalGenerator.h91
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx12
-rw-r--r--Source/cmMakefile.cxx396
-rw-r--r--Source/cmMakefile.h77
-rw-r--r--Source/cmQtAutoGenGlobalInitializer.cxx13
-rw-r--r--Source/cmQtAutoGenInitializer.cxx15
13 files changed, 667 insertions, 326 deletions
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index 6e04ce5829..52fc5d5fd5 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -343,7 +343,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
// Target is empty, use the output.
mf.AddCustomCommandToOutput(
output, byproducts, depends, main_dependency, implicit_depends,
- commandLines, comment, working.c_str(), false, escapeOldStyle,
+ commandLines, comment, working.c_str(), nullptr, false, escapeOldStyle,
uses_terminal, command_expand_lists, depfile, job_pool);
} else if (!byproducts.empty()) {
status.SetError("BYPRODUCTS may not be specified with SOURCE signatures");
diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx
index e27b126dd8..aa98d8949a 100644
--- a/Source/cmAddCustomTargetCommand.cxx
+++ b/Source/cmAddCustomTargetCommand.cxx
@@ -6,7 +6,6 @@
#include "cmCheckCustomOutputs.h"
#include "cmCustomCommandLines.h"
-#include "cmCustomCommandTypes.h"
#include "cmExecutionStatus.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
@@ -215,9 +214,9 @@ bool cmAddCustomTargetCommand(std::vector<std::string> const& args,
// Add the utility target to the makefile.
bool escapeOldStyle = !verbatim;
cmTarget* target = mf.AddUtilityCommand(
- targetName, cmCommandOrigin::Project, excludeFromAll,
- working_directory.c_str(), byproducts, depends, commandLines,
- escapeOldStyle, comment, uses_terminal, command_expand_lists, job_pool);
+ targetName, excludeFromAll, working_directory.c_str(), byproducts, depends,
+ commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists,
+ job_pool);
// Add additional user-specified source files to the target.
target->AddSources(sources);
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
index 177bca889a..b5c7e9693a 100644
--- a/Source/cmCPluginAPI.cxx
+++ b/Source/cmCPluginAPI.cxx
@@ -221,10 +221,10 @@ void CCONV cmAddUtilityCommand(void* arg, const char* utilityName,
// Pass the call to the makefile instance.
std::vector<std::string> no_byproducts;
- mf->AddUtilityCommand(utilityName, cmCommandOrigin::Project,
- (all ? false : true), nullptr, no_byproducts, depends2,
- commandLines);
+ mf->AddUtilityCommand(utilityName, (all ? false : true), nullptr,
+ no_byproducts, depends2, commandLines);
}
+
void CCONV cmAddCustomCommand(void* arg, const char* source,
const char* command, int numArgs,
const char** args, int numDepends,
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index d39d42a0db..ea603b0938 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -101,15 +101,14 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
std::vector<cmLocalGenerator*> const& generators = this->LocalGenerators;
cmLocalVisualStudio7Generator* lg =
static_cast<cmLocalVisualStudio7Generator*>(generators[0]);
- cmMakefile* mf = lg->GetMakefile();
const char* no_working_directory = nullptr;
std::vector<std::string> no_byproducts;
std::vector<std::string> no_depends;
cmCustomCommandLines no_commands;
- cmTarget* tgt = mf->AddUtilityCommand(
- CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmCommandOrigin::Generator, false,
- no_working_directory, no_byproducts, no_depends, no_commands);
+ cmTarget* tgt = lg->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false,
+ no_working_directory, no_byproducts,
+ no_depends, no_commands);
auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, lg);
auto gt = ptr.get();
@@ -156,7 +155,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
std::vector<std::string> byproducts;
byproducts.push_back(cm->GetGlobVerifyStamp());
- mf->AddCustomCommandToTarget(
+ lg->AddCustomCommandToTarget(
CMAKE_CHECK_BUILD_SYSTEM_TARGET, byproducts, no_depends,
verifyCommandLines, cmCustomCommandType::PRE_BUILD,
"Checking File Globs", no_working_directory, false);
@@ -188,7 +187,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
// (this could be avoided with per-target source files)
std::string no_main_dependency;
cmImplicitDependsList no_implicit_depends;
- if (cmSourceFile* file = mf->AddCustomCommandToOutput(
+ if (cmSourceFile* file = lg->AddCustomCommandToOutput(
stamps, no_byproducts, listFiles, no_main_dependency,
no_implicit_depends, commandLines, "Checking Build System",
no_working_directory, true, false)) {
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index b687e56073..be5cfd4a6f 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -197,9 +197,9 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets()
if (!gen.empty()) {
// Use no actual command lines so that the target itself is not
// considered always out of date.
- cmTarget* allBuild = gen[0]->GetMakefile()->AddUtilityCommand(
- "ALL_BUILD", cmCommandOrigin::Generator, true, no_working_dir,
- no_byproducts, no_depends, no_commands, false, "Build all projects");
+ cmTarget* allBuild = gen[0]->AddUtilityCommand(
+ "ALL_BUILD", true, no_working_dir, no_byproducts, no_depends,
+ no_commands, false, "Build all projects");
gen[0]->AddGeneratorTarget(
cm::make_unique<cmGeneratorTarget>(allBuild, gen[0]));
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 280ac26919..d75c489922 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -500,16 +500,13 @@ std::string cmGlobalXCodeGenerator::PostBuildMakeTarget(
void cmGlobalXCodeGenerator::AddExtraTargets(
cmLocalGenerator* root, std::vector<cmLocalGenerator*>& gens)
{
- cmMakefile* mf = root->GetMakefile();
-
const char* no_working_directory = nullptr;
std::vector<std::string> no_byproducts;
std::vector<std::string> no_depends;
// Add ALL_BUILD
- cmTarget* allbuild = mf->AddUtilityCommand(
- "ALL_BUILD", cmCommandOrigin::Generator, true, no_working_directory,
- no_byproducts, no_depends,
+ cmTarget* allbuild = root->AddUtilityCommand(
+ "ALL_BUILD", true, no_working_directory, no_byproducts, no_depends,
cmMakeSingleCommandLine({ "echo", "Build all projects" }));
root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(allbuild, root));
@@ -523,7 +520,7 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
// Add ZERO_CHECK
bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
bool generateTopLevelProjectOnly =
- mf->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY");
+ root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY");
bool isTopLevel =
!root->GetStateSnapshot().GetBuildsystemDirectoryParent().IsValid();
if (regenerate && (isTopLevel || !generateTopLevelProjectOnly)) {
@@ -531,10 +528,10 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
std::string file =
this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile);
cmSystemTools::ReplaceString(file, "\\ ", " ");
- cmTarget* check = mf->AddUtilityCommand(
- CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmCommandOrigin::Generator, true,
- no_working_directory, no_byproducts, no_depends,
- cmMakeSingleCommandLine({ "make", "-f", file }));
+ cmTarget* check =
+ root->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, true,
+ no_working_directory, no_byproducts, no_depends,
+ cmMakeSingleCommandLine({ "make", "-f", file }));
root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(check, root));
}
@@ -559,7 +556,7 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
commandLines.front().back() = // fill placeholder
this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)");
- gen->GetMakefile()->AddCustomCommandToTarget(
+ gen->AddCustomCommandToTarget(
target->GetName(), no_byproducts, no_depends, commandLines,
cmCustomCommandType::POST_BUILD, "Depend check for xcode",
dir.c_str(), true, false, "", "", false,
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index bdc0358fde..c88805f7ef 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -14,6 +14,7 @@
#include <utility>
#include <vector>
+#include <cm/memory>
#include <cm/string_view>
#include "cmsys/RegularExpression.hxx"
@@ -988,6 +989,91 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
}
}
+cmTarget* cmLocalGenerator::AddCustomCommandToTarget(
+ const std::string& target, const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmCustomCommandType type,
+ const char* comment, const char* workingDir, bool escapeOldStyle,
+ bool uses_terminal, const std::string& depfile, const std::string& job_pool,
+ bool command_expand_lists, cmObjectLibraryCommands objLibCommands)
+{
+ cmTarget* t = this->Makefile->GetCustomCommandTarget(
+ target, objLibCommands, this->DirectoryBacktrace);
+ if (!t) {
+ return nullptr;
+ }
+
+ detail::AddCustomCommandToTarget(
+ *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, t, byproducts,
+ depends, commandLines, type, comment, workingDir, escapeOldStyle,
+ uses_terminal, depfile, job_pool, command_expand_lists);
+
+ return t;
+}
+
+cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
+ const std::string& output, const std::vector<std::string>& depends,
+ const std::string& main_dependency, const cmCustomCommandLines& commandLines,
+ const char* comment, const char* workingDir, bool replace,
+ bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
+ const std::string& depfile, const std::string& job_pool)
+{
+ std::vector<std::string> no_byproducts;
+ cmImplicitDependsList no_implicit_depends;
+ return this->AddCustomCommandToOutput(
+ { output }, no_byproducts, depends, main_dependency, no_implicit_depends,
+ commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
+ command_expand_lists, depfile, job_pool);
+}
+
+cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends, const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool)
+{
+ // Make sure there is at least one output.
+ if (outputs.empty()) {
+ cmSystemTools::Error("Attempt to add a custom rule with no output!");
+ return nullptr;
+ }
+
+ return detail::AddCustomCommandToOutput(
+ *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, outputs,
+ byproducts, depends, main_dependency, implicit_depends, commandLines,
+ comment, workingDir, replace, escapeOldStyle, uses_terminal,
+ command_expand_lists, depfile, job_pool);
+}
+
+cmTarget* cmLocalGenerator::AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll, const char* workingDir,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, bool escapeOldStyle,
+ const char* comment, bool uses_terminal, bool command_expand_lists,
+ const std::string& job_pool)
+{
+ cmTarget* target =
+ this->Makefile->AddNewUtilityTarget(utilityName, excludeFromAll);
+ target->SetIsGeneratorProvided(true);
+
+ if (commandLines.empty() && depends.empty()) {
+ return target;
+ }
+
+ detail::AddUtilityCommand(
+ *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, target,
+ this->Makefile->GetUtilityOutput(target), workingDir, byproducts, depends,
+ commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists,
+ job_pool);
+
+ return target;
+}
+
std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
cmGeneratorTarget const* target, std::string const& lang,
std::string const& config, bool stripImplicitDirs,
@@ -2402,16 +2488,14 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
pchReuseFrom, ".pdb"));
if (this->GetGlobalGenerator()->IsMultiConfig()) {
- this->Makefile->AddCustomCommandToTarget(
+ this->AddCustomCommandToTarget(
target->GetName(), outputs, no_deps, commandLines,
cmCustomCommandType::PRE_BUILD, no_message, no_current_dir);
} else {
cmImplicitDependsList no_implicit_depends;
- cmSourceFile* copy_rule =
- this->Makefile->AddCustomCommandToOutput(
- outputs, no_byproducts, no_deps, no_main_dependency,
- no_implicit_depends, commandLines, no_message,
- no_current_dir);
+ cmSourceFile* copy_rule = this->AddCustomCommandToOutput(
+ outputs, no_byproducts, no_deps, no_main_dependency,
+ no_implicit_depends, commandLines, no_message, no_current_dir);
if (copy_rule) {
target->AddSource(copy_rule->ResolveFullPath());
@@ -3423,3 +3507,245 @@ void cmLocalGenerator::GenerateFrameworkInfoPList(
cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION");
mf->ConfigureFile(inFile, fname, false, false, false);
}
+
+namespace {
+void CreateGeneratedSource(cmLocalGenerator& lg, const std::string& output,
+ cmCommandOrigin origin,
+ const cmListFileBacktrace& lfbt)
+{
+ if (cmGeneratorExpression::Find(output) == std::string::npos) {
+ // Outputs without generator expressions from the project are already
+ // created and marked as generated. Do not mark them again, because
+ // other commands might have overwritten the property.
+ if (origin == cmCommandOrigin::Generator) {
+ lg.GetMakefile()->GetOrCreateGeneratedSource(output);
+ }
+ } else {
+ lg.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Generator expressions in custom command outputs are not implemented!",
+ lfbt);
+ }
+}
+
+void CreateGeneratedSources(cmLocalGenerator& lg,
+ const std::vector<std::string>& outputs,
+ cmCommandOrigin origin,
+ const cmListFileBacktrace& lfbt)
+{
+ for (std::string const& o : outputs) {
+ CreateGeneratedSource(lg, o, origin, lfbt);
+ }
+}
+
+cmSourceFile* AddCustomCommand(
+ cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends, const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool)
+{
+ cmMakefile* mf = lg.GetMakefile();
+
+ // Choose a source file on which to store the custom command.
+ cmSourceFile* file = nullptr;
+ if (!commandLines.empty() && !main_dependency.empty()) {
+ // The main dependency was specified. Use it unless a different
+ // custom command already used it.
+ file = mf->GetSource(main_dependency);
+ if (file && file->GetCustomCommand() && !replace) {
+ // The main dependency already has a custom command.
+ if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
+ // The existing custom command is identical. Silently ignore
+ // the duplicate.
+ return file;
+ }
+ // The existing custom command is different. We need to
+ // generate a rule file for this new command.
+ file = nullptr;
+ } else if (!file) {
+ file = mf->CreateSource(main_dependency);
+ }
+ }
+
+ // Generate a rule file if the main dependency is not available.
+ if (!file) {
+ cmGlobalGenerator* gg = lg.GetGlobalGenerator();
+
+ // Construct a rule file associated with the first output produced.
+ std::string outName = gg->GenerateRuleFile(outputs[0]);
+
+ // Check if the rule file already exists.
+ file = mf->GetSource(outName, cmSourceFileLocationKind::Known);
+ if (file && file->GetCustomCommand() && !replace) {
+ // The rule file already exists.
+ if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
+ lg.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Attempt to add a custom rule to output\n ", outName,
+ "\nwhich already has a custom rule."),
+ lfbt);
+ }
+ return file;
+ }
+
+ // Create a cmSourceFile for the rule file.
+ if (!file) {
+ file = mf->CreateSource(outName, true, cmSourceFileLocationKind::Known);
+ }
+ file->SetProperty("__CMAKE_RULE", "1");
+ }
+
+ // Attach the custom command to the file.
+ if (file) {
+ // Construct a complete list of dependencies.
+ std::vector<std::string> depends2(depends);
+ if (!main_dependency.empty()) {
+ depends2.push_back(main_dependency);
+ }
+
+ std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>(
+ outputs, byproducts, depends2, commandLines, lfbt, comment, workingDir);
+ cc->SetEscapeOldStyle(escapeOldStyle);
+ cc->SetEscapeAllowMakeVars(true);
+ cc->SetImplicitDepends(implicit_depends);
+ cc->SetUsesTerminal(uses_terminal);
+ cc->SetCommandExpandLists(command_expand_lists);
+ cc->SetDepfile(depfile);
+ cc->SetJobPool(job_pool);
+ file->SetCustomCommand(std::move(cc));
+
+ mf->AddSourceOutputs(file, outputs, byproducts);
+ }
+ return file;
+}
+}
+
+namespace detail {
+void AddCustomCommandToTarget(cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, cmTarget* target,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ cmCustomCommandType type, const char* comment,
+ const char* workingDir, bool escapeOldStyle,
+ bool uses_terminal, const std::string& depfile,
+ const std::string& job_pool,
+ bool command_expand_lists)
+{
+ cmMakefile* mf = lg.GetMakefile();
+
+ // Always create the byproduct sources and mark them generated.
+ CreateGeneratedSources(lg, byproducts, origin, lfbt);
+
+ // Add the command to the appropriate build step for the target.
+ std::vector<std::string> no_output;
+ cmCustomCommand cc(no_output, byproducts, depends, commandLines, lfbt,
+ comment, workingDir);
+ cc.SetEscapeOldStyle(escapeOldStyle);
+ cc.SetEscapeAllowMakeVars(true);
+ cc.SetUsesTerminal(uses_terminal);
+ cc.SetCommandExpandLists(command_expand_lists);
+ cc.SetDepfile(depfile);
+ cc.SetJobPool(job_pool);
+ switch (type) {
+ case cmCustomCommandType::PRE_BUILD:
+ target->AddPreBuildCommand(std::move(cc));
+ break;
+ case cmCustomCommandType::PRE_LINK:
+ target->AddPreLinkCommand(std::move(cc));
+ break;
+ case cmCustomCommandType::POST_BUILD:
+ target->AddPostBuildCommand(std::move(cc));
+ break;
+ }
+
+ mf->AddTargetByproducts(target, byproducts);
+}
+
+cmSourceFile* AddCustomCommandToOutput(
+ cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends, const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool)
+{
+ // Always create the output sources and mark them generated.
+ CreateGeneratedSources(lg, outputs, origin, lfbt);
+ CreateGeneratedSources(lg, byproducts, origin, lfbt);
+
+ return AddCustomCommand(
+ lg, lfbt, outputs, byproducts, depends, main_dependency, implicit_depends,
+ commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
+ command_expand_lists, depfile, job_pool);
+}
+
+void AppendCustomCommandToOutput(cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt,
+ const std::string& output,
+ const std::vector<std::string>& depends,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines)
+{
+ // Lookup an existing command.
+ if (cmSourceFile* sf = lg.GetMakefile()->GetSourceFileWithOutput(output)) {
+ if (cmCustomCommand* cc = sf->GetCustomCommand()) {
+ cc->AppendCommands(commandLines);
+ cc->AppendDepends(depends);
+ cc->AppendImplicitDepends(implicit_depends);
+ return;
+ }
+ }
+
+ // No existing command found.
+ lg.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Attempt to append to output\n ", output,
+ "\nwhich is not already a custom command output."),
+ lfbt);
+}
+
+void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, cmTarget* target,
+ const cmUtilityOutput& force, const char* workingDir,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ bool escapeOldStyle, const char* comment,
+ bool uses_terminal, bool command_expand_lists,
+ const std::string& job_pool)
+{
+ // Always create the byproduct sources and mark them generated.
+ CreateGeneratedSource(lg, force.Name, origin, lfbt);
+ CreateGeneratedSources(lg, byproducts, origin, lfbt);
+
+ // Use an empty comment to avoid generation of default comment.
+ if (!comment) {
+ comment = "";
+ }
+
+ std::string no_main_dependency;
+ cmImplicitDependsList no_implicit_depends;
+ cmSourceFile* rule = AddCustomCommand(
+ lg, lfbt, { force.Name }, byproducts, depends, no_main_dependency,
+ no_implicit_depends, commandLines, comment, workingDir, /*replace=*/false,
+ escapeOldStyle, uses_terminal, command_expand_lists, /*depfile=*/"",
+ job_pool);
+ if (rule) {
+ lg.GetMakefile()->AddTargetByproducts(target, byproducts);
+ }
+
+ if (!force.NameCMP0049.empty()) {
+ target->AddSource(force.NameCMP0049);
+ }
+}
+}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index e5c89f9b86..8788c2f8a4 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -15,6 +15,7 @@
#include "cm_kwiml.h"
+#include "cmCustomCommandTypes.h"
#include "cmListFileCache.h"
#include "cmMessageType.h"
#include "cmOutputConverter.h"
@@ -23,13 +24,16 @@
class cmComputeLinkInformation;
class cmCustomCommandGenerator;
+class cmCustomCommandLines;
class cmGeneratorTarget;
class cmGlobalGenerator;
+class cmImplicitDependsList;
class cmLinkLineComputer;
class cmMakefile;
class cmRulePlaceholderExpander;
class cmSourceFile;
class cmState;
+class cmTarget;
class cmake;
/** \class cmLocalGenerator
@@ -295,6 +299,51 @@ public:
cmGeneratorTarget* target, const std::string& lang,
const std::string& config);
+ /**
+ * Add a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a target.
+ */
+ cmTarget* AddCustomCommandToTarget(
+ const std::string& target, const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmCustomCommandType type,
+ const char* comment, const char* workingDir, bool escapeOldStyle = true,
+ bool uses_terminal = false, const std::string& depfile = "",
+ const std::string& job_pool = "", bool command_expand_lists = false,
+ cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject);
+
+ /**
+ * Add a custom command to a source file.
+ */
+ cmSourceFile* AddCustomCommandToOutput(
+ const std::string& output, const std::vector<std::string>& depends,
+ const std::string& main_dependency,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, bool replace = false, bool escapeOldStyle = true,
+ bool uses_terminal = false, bool command_expand_lists = false,
+ const std::string& depfile = "", const std::string& job_pool = "");
+ cmSourceFile* AddCustomCommandToOutput(
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, bool replace = false, bool escapeOldStyle = true,
+ bool uses_terminal = false, bool command_expand_lists = false,
+ const std::string& depfile = "", const std::string& job_pool = "");
+
+ /**
+ * Add a utility to the build. A utility target is a command that is run
+ * every time the target is built.
+ */
+ cmTarget* AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll,
+ const char* workingDir, const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
+ const char* comment = nullptr, bool uses_terminal = false,
+ bool command_expand_lists = false, const std::string& job_pool = "");
+
std::string GetProjectName() const;
/** Compute the language used to compile the given source file. */
@@ -497,4 +546,46 @@ bool cmLocalGeneratorCheckObjectName(std::string& objName,
std::string::size_type max_total_len);
#endif
+namespace detail {
+void AddCustomCommandToTarget(cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, cmTarget* target,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ cmCustomCommandType type, const char* comment,
+ const char* workingDir, bool escapeOldStyle,
+ bool uses_terminal, const std::string& depfile,
+ const std::string& job_pool,
+ bool command_expand_lists);
+
+cmSourceFile* AddCustomCommandToOutput(
+ cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends, const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool);
+
+void AppendCustomCommandToOutput(cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt,
+ const std::string& output,
+ const std::vector<std::string>& depends,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines);
+
+void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, cmTarget* target,
+ const cmUtilityOutput& force, const char* workingDir,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ bool escapeOldStyle, const char* comment,
+ bool uses_terminal, bool command_expand_lists,
+ const std::string& job_pool);
+}
+
#endif
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 5354f140b7..0758fd48a0 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -102,9 +102,9 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets()
this->Makefile->GetOrCreateGeneratedSource(force)) {
sf->SetProperty("SYMBOLIC", "1");
}
- if (cmSourceFile* file = this->Makefile->AddCustomCommandToOutput(
- force.c_str(), no_depends, no_main_dependency, force_commands, " ",
- 0, true)) {
+ if (cmSourceFile* file = this->AddCustomCommandToOutput(
+ force, no_depends, no_main_dependency, force_commands, " ",
+ nullptr, true)) {
l->AddSource(file->ResolveFullPath());
}
}
@@ -259,9 +259,9 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
const char* no_working_directory = nullptr;
std::string fullpathStampName =
cmSystemTools::CollapseFullPath(stampName.c_str());
- this->Makefile->AddCustomCommandToOutput(
- fullpathStampName, listFiles, makefileIn, commandLines, comment.c_str(),
- no_working_directory, true, false);
+ this->AddCustomCommandToOutput(fullpathStampName, listFiles, makefileIn,
+ commandLines, comment.c_str(),
+ no_working_directory, true, false);
if (cmSourceFile* file = this->Makefile->GetSource(makefileIn.c_str())) {
// Finalize the source file path now since we're adding this after
// the generator validated all project-named sources.
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index c6c8109b71..dc0b50f413 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -14,7 +14,7 @@
#include <utility>
#include <cm/iterator>
-#include <cm/memory>
+#include <cm/optional>
#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
@@ -798,6 +798,8 @@ 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
@@ -828,6 +830,39 @@ void cmMakefile::Generate(cmLocalGenerator& lg)
}
}
+namespace {
+// There are still too many implicit backtraces through cmMakefile. As a
+// workaround we reset the backtrace temporarily.
+struct BacktraceGuard
+{
+ BacktraceGuard(cmListFileBacktrace& lfbt, cmListFileBacktrace current)
+ : Backtrace(lfbt)
+ , Previous(lfbt)
+ {
+ this->Backtrace = std::move(current);
+ }
+
+ ~BacktraceGuard() { this->Backtrace = std::move(Previous); }
+
+private:
+ cmListFileBacktrace& Backtrace;
+ cmListFileBacktrace Previous;
+};
+
+cm::optional<std::string> MakeOptionalString(const char* str)
+{
+ if (str) {
+ return str;
+ }
+ return cm::nullopt;
+}
+
+const char* GetCStrOrNull(const cm::optional<std::string>& str)
+{
+ return str ? str->c_str() : nullptr;
+}
+}
+
bool cmMakefile::ValidateCustomCommand(
const cmCustomCommandLines& commandLines) const
{
@@ -916,10 +951,10 @@ cmTarget* cmMakefile::AddCustomCommandToTarget(
const cmCustomCommandLines& commandLines, cmCustomCommandType type,
const char* comment, const char* workingDir, bool escapeOldStyle,
bool uses_terminal, const std::string& depfile, const std::string& job_pool,
- bool command_expand_lists, cmObjectLibraryCommands objLibCommands)
+ bool command_expand_lists)
{
- cmTarget* t =
- this->GetCustomCommandTarget(target, objLibCommands, this->Backtrace);
+ cmTarget* t = this->GetCustomCommandTarget(
+ target, cmObjectLibraryCommands::Reject, this->Backtrace);
// Validate custom commands.
if (!t || !this->ValidateCustomCommand(commandLines)) {
@@ -927,176 +962,83 @@ cmTarget* cmMakefile::AddCustomCommandToTarget(
}
// Always create the byproduct sources and mark them generated.
- this->CreateGeneratedSources(byproducts);
-
- this->CommitCustomCommandToTarget(
- t, byproducts, depends, commandLines, type, comment, workingDir,
- escapeOldStyle, uses_terminal, depfile, job_pool, command_expand_lists);
+ this->CreateGeneratedByproducts(byproducts);
+
+ // Strings could be moved into the callback function with C++14.
+ cm::optional<std::string> commentStr = MakeOptionalString(comment);
+ cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
+
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction([=](cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ detail::AddCustomCommandToTarget(
+ lg, lfbt, cmCommandOrigin::Project, t, byproducts, depends, commandLines,
+ type, GetCStrOrNull(commentStr), GetCStrOrNull(workingStr),
+ escapeOldStyle, uses_terminal, depfile, job_pool, command_expand_lists);
+ });
return t;
}
-void cmMakefile::CommitCustomCommandToTarget(
- cmTarget* target, const std::vector<std::string>& byproducts,
- const std::vector<std::string>& depends,
- const cmCustomCommandLines& commandLines, cmCustomCommandType type,
- const char* comment, const char* workingDir, bool escapeOldStyle,
- bool uses_terminal, const std::string& depfile, const std::string& job_pool,
- bool command_expand_lists)
-{
- // Add the command to the appropriate build step for the target.
- std::vector<std::string> no_output;
- cmCustomCommand cc(no_output, byproducts, depends, commandLines,
- this->Backtrace, comment, workingDir);
- cc.SetEscapeOldStyle(escapeOldStyle);
- cc.SetEscapeAllowMakeVars(true);
- cc.SetUsesTerminal(uses_terminal);
- cc.SetCommandExpandLists(command_expand_lists);
- cc.SetDepfile(depfile);
- cc.SetJobPool(job_pool);
- switch (type) {
- case cmCustomCommandType::PRE_BUILD:
- target->AddPreBuildCommand(std::move(cc));
- break;
- case cmCustomCommandType::PRE_LINK:
- target->AddPreLinkCommand(std::move(cc));
- break;
- case cmCustomCommandType::POST_BUILD:
- target->AddPostBuildCommand(std::move(cc));
- break;
- }
-
- this->AddTargetByproducts(target, byproducts);
-}
-
-cmSourceFile* cmMakefile::AddCustomCommandToOutput(
+void cmMakefile::AddCustomCommandToOutput(
const std::string& output, const std::vector<std::string>& depends,
const std::string& main_dependency, const cmCustomCommandLines& commandLines,
- const char* comment, const char* workingDir, bool replace,
- bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
- const std::string& depfile, const std::string& job_pool)
+ const char* comment, const char* workingDir,
+ const CommandSourceCallback& callback, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool)
{
- std::vector<std::string> outputs;
- outputs.push_back(output);
std::vector<std::string> no_byproducts;
cmImplicitDependsList no_implicit_depends;
- return this->AddCustomCommandToOutput(
- outputs, no_byproducts, depends, main_dependency, no_implicit_depends,
- commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
- command_expand_lists, depfile, job_pool);
+ this->AddCustomCommandToOutput(
+ { output }, no_byproducts, depends, main_dependency, no_implicit_depends,
+ commandLines, comment, workingDir, callback, replace, escapeOldStyle,
+ uses_terminal, command_expand_lists, depfile, job_pool);
}
-cmSourceFile* cmMakefile::AddCustomCommandToOutput(
+void cmMakefile::AddCustomCommandToOutput(
const std::vector<std::string>& outputs,
const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends, const std::string& main_dependency,
const cmImplicitDependsList& implicit_depends,
const cmCustomCommandLines& commandLines, const char* comment,
- const char* workingDir, bool replace, bool escapeOldStyle,
- bool uses_terminal, bool command_expand_lists, const std::string& depfile,
- const std::string& job_pool)
+ const char* workingDir, const CommandSourceCallback& callback, bool replace,
+ bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
+ const std::string& depfile, const std::string& job_pool)
{
// Make sure there is at least one output.
if (outputs.empty()) {
cmSystemTools::Error("Attempt to add a custom rule with no output!");
- return nullptr;
+ return;
}
// Validate custom commands.
if (!this->ValidateCustomCommand(commandLines)) {
- return nullptr;
+ return;
}
// Always create the output sources and mark them generated.
- this->CreateGeneratedSources(outputs);
- this->CreateGeneratedSources(byproducts);
-
- return this->CommitCustomCommandToOutput(
- outputs, byproducts, depends, main_dependency, implicit_depends,
- commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
- command_expand_lists, depfile, job_pool);
-}
-
-cmSourceFile* cmMakefile::CommitCustomCommandToOutput(
- const std::vector<std::string>& outputs,
- const std::vector<std::string>& byproducts,
- const std::vector<std::string>& depends, const std::string& main_dependency,
- const cmImplicitDependsList& implicit_depends,
- const cmCustomCommandLines& commandLines, const char* comment,
- const char* workingDir, bool replace, bool escapeOldStyle,
- bool uses_terminal, bool command_expand_lists, const std::string& depfile,
- const std::string& job_pool)
-{
- // Choose a source file on which to store the custom command.
- cmSourceFile* file = nullptr;
- if (!commandLines.empty() && !main_dependency.empty()) {
- // The main dependency was specified. Use it unless a different
- // custom command already used it.
- file = this->GetSource(main_dependency);
- if (file && file->GetCustomCommand() && !replace) {
- // The main dependency already has a custom command.
- if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
- // The existing custom command is identical. Silently ignore
- // the duplicate.
- return file;
- }
- // The existing custom command is different. We need to
- // generate a rule file for this new command.
- file = nullptr;
- } else if (!file) {
- file = this->CreateSource(main_dependency);
- }
- }
-
- // Generate a rule file if the main dependency is not available.
- if (!file) {
- cmGlobalGenerator* gg = this->GetGlobalGenerator();
-
- // Construct a rule file associated with the first output produced.
- std::string outName = gg->GenerateRuleFile(outputs[0]);
-
- // Check if the rule file already exists.
- file = this->GetSource(outName, cmSourceFileLocationKind::Known);
- if (file && file->GetCustomCommand() && !replace) {
- // The rule file already exists.
- if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
- cmSystemTools::Error("Attempt to add a custom rule to output \"" +
- outName + "\" which already has a custom rule.");
- }
- return file;
+ this->CreateGeneratedOutputs(outputs);
+ this->CreateGeneratedByproducts(byproducts);
+
+ // Strings could be moved into the callback function with C++14.
+ cm::optional<std::string> commentStr = MakeOptionalString(comment);
+ cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
+
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction([=](cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ cmSourceFile* sf = detail::AddCustomCommandToOutput(
+ lg, lfbt, cmCommandOrigin::Project, outputs, byproducts, depends,
+ main_dependency, implicit_depends, commandLines,
+ GetCStrOrNull(commentStr), GetCStrOrNull(workingStr), replace,
+ escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool);
+ if (callback && sf) {
+ callback(sf);
}
-
- // Create a cmSourceFile for the rule file.
- if (!file) {
- file =
- this->CreateSource(outName, true, cmSourceFileLocationKind::Known);
- }
- file->SetProperty("__CMAKE_RULE", "1");
- }
-
- // Attach the custom command to the file.
- if (file) {
- // Construct a complete list of dependencies.
- std::vector<std::string> depends2(depends);
- if (!main_dependency.empty()) {
- depends2.push_back(main_dependency);
- }
-
- std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>(
- outputs, byproducts, depends2, commandLines, this->Backtrace, comment,
- workingDir);
- cc->SetEscapeOldStyle(escapeOldStyle);
- cc->SetEscapeAllowMakeVars(true);
- cc->SetImplicitDepends(implicit_depends);
- cc->SetUsesTerminal(uses_terminal);
- cc->SetCommandExpandLists(command_expand_lists);
- cc->SetDepfile(depfile);
- cc->SetJobPool(job_pool);
- file->SetCustomCommand(std::move(cc));
-
- this->AddSourceOutputs(file, outputs, byproducts);
- }
- return file;
+ });
}
void cmMakefile::AddCustomCommandOldStyle(
@@ -1144,11 +1086,8 @@ void cmMakefile::AddCustomCommandOldStyle(
if (sourceFiles.find(source)) {
// The source looks like a real file. Use it as the main dependency.
for (std::string const& output : outputs) {
- cmSourceFile* sf = this->AddCustomCommandToOutput(
- output, depends, source, commandLines, comment, nullptr);
- if (sf) {
- addRuleFileToTarget(sf);
- }
+ this->AddCustomCommandToOutput(output, depends, source, commandLines,
+ comment, nullptr, addRuleFileToTarget);
}
} else {
std::string no_main_dependency;
@@ -1157,11 +1096,9 @@ void cmMakefile::AddCustomCommandOldStyle(
// The source may not be a real file. Do not use a main dependency.
for (std::string const& output : outputs) {
- cmSourceFile* sf = this->AddCustomCommandToOutput(
- output, depends2, no_main_dependency, commandLines, comment, nullptr);
- if (sf) {
- addRuleFileToTarget(sf);
- }
+ this->AddCustomCommandToOutput(output, depends2, no_main_dependency,
+ commandLines, comment, nullptr,
+ addRuleFileToTarget);
}
}
}
@@ -1178,29 +1115,18 @@ bool cmMakefile::AppendCustomCommandToOutput(
// Validate custom commands.
if (this->ValidateCustomCommand(commandLines)) {
- // Add command factory to allow generator expressions in output.
- this->CommitAppendCustomCommandToOutput(output, depends, implicit_depends,
- commandLines);
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction(
+ [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ detail::AppendCustomCommandToOutput(lg, lfbt, output, depends,
+ implicit_depends, commandLines);
+ });
}
return true;
}
-void cmMakefile::CommitAppendCustomCommandToOutput(
- const std::string& output, const std::vector<std::string>& depends,
- const cmImplicitDependsList& implicit_depends,
- const cmCustomCommandLines& commandLines)
-{
- // Lookup an existing command.
- if (cmSourceFile* sf = this->GetSourceFileWithOutput(output)) {
- if (cmCustomCommand* cc = sf->GetCustomCommand()) {
- cc->AppendCommands(commandLines);
- cc->AppendDepends(depends);
- cc->AppendImplicitDepends(implicit_depends);
- }
- }
-}
-
cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target)
{
std::string force = cmStrCat(this->GetCurrentBinaryDirectory(),
@@ -1223,15 +1149,14 @@ cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target)
}
cmTarget* cmMakefile::AddUtilityCommand(
- const std::string& utilityName, cmCommandOrigin origin, bool excludeFromAll,
- const char* workingDirectory, const std::vector<std::string>& byproducts,
+ const std::string& utilityName, bool excludeFromAll, const char* workingDir,
+ const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle,
const char* comment, bool uses_terminal, bool command_expand_lists,
const std::string& job_pool)
{
- cmTarget* target =
- this->AddNewUtilityTarget(utilityName, origin, excludeFromAll);
+ cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll);
// Validate custom commands.
if ((commandLines.empty() && depends.empty()) ||
@@ -1244,45 +1169,26 @@ cmTarget* cmMakefile::AddUtilityCommand(
this->GetOrCreateGeneratedSource(force.Name);
// Always create the byproduct sources and mark them generated.
- this->CreateGeneratedSources(byproducts);
-
- if (!comment) {
- // Use an empty comment to avoid generation of default comment.
- comment = "";
- }
-
- this->CommitUtilityCommand(target, force, workingDirectory, byproducts,
- depends, commandLines, escapeOldStyle, comment,
- uses_terminal, command_expand_lists, job_pool);
+ this->CreateGeneratedByproducts(byproducts);
+
+ // Strings could be moved into the callback function with C++14.
+ cm::optional<std::string> commentStr = MakeOptionalString(comment);
+ cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
+
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction(
+ [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ detail::AddUtilityCommand(lg, lfbt, cmCommandOrigin::Project, target,
+ force, GetCStrOrNull(workingStr), byproducts,
+ depends, commandLines, escapeOldStyle,
+ GetCStrOrNull(commentStr), uses_terminal,
+ command_expand_lists, job_pool);
+ });
return target;
}
-void cmMakefile::CommitUtilityCommand(
- cmTarget* target, const cmUtilityOutput& force, const char* workingDirectory,
- const std::vector<std::string>& byproducts,
- const std::vector<std::string>& depends,
- const cmCustomCommandLines& commandLines, bool escapeOldStyle,
- const char* comment, bool uses_terminal, bool command_expand_lists,
- const std::string& job_pool)
-{
- std::vector<std::string> forced;
- forced.push_back(force.Name);
- std::string no_main_dependency;
- cmImplicitDependsList no_implicit_depends;
- bool no_replace = false;
- cmSourceFile* sf = this->AddCustomCommandToOutput(
- forced, byproducts, depends, no_main_dependency, no_implicit_depends,
- commandLines, comment, workingDirectory, no_replace, escapeOldStyle,
- uses_terminal, command_expand_lists, /*depfile=*/"", job_pool);
- if (!force.NameCMP0049.empty()) {
- target->AddSource(force.NameCMP0049);
- }
- if (sf) {
- this->AddTargetByproducts(target, byproducts);
- }
-}
-
static void s_AddDefineFlag(std::string const& flag, std::string& dflags)
{
// remove any \n\r
@@ -2095,11 +2001,9 @@ cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
}
cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName,
- cmCommandOrigin origin,
bool excludeFromAll)
{
cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName);
- target->SetIsGeneratorProvided(origin == cmCommandOrigin::Generator);
if (excludeFromAll) {
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
}
@@ -2217,8 +2121,8 @@ cmSourceFile* cmMakefile::GetSourceFileWithOutput(
(!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 or a PRE_BUILD, PRE_LINK, or POST_BUILD
- // command of a target.
+ // 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;
@@ -2226,12 +2130,20 @@ cmSourceFile* cmMakefile::GetSourceFileWithOutput(
bool cmMakefile::MightHaveCustomCommand(const std::string& name) const
{
- // This will have to be changed for delaying custom command creation, because
- // GetSourceFileWithOutput requires the command to be already created.
- if (cmSourceFile* sf = this->GetSourceFileWithOutput(name)) {
- if (sf->GetCustomCommand()) {
- return true;
- }
+ 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;
}
@@ -2284,6 +2196,7 @@ void cmMakefile::UpdateOutputToSourceMap(std::string const& output,
SourceEntry entry;
entry.Sources.Source = source;
entry.Sources.SourceIsByproduct = byproduct;
+ entry.SourceMightBeOutput = !byproduct;
auto pr = this->OutputToSource.emplace(output, entry);
if (!pr.second) {
@@ -2293,6 +2206,7 @@ void cmMakefile::UpdateOutputToSourceMap(std::string const& output,
(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).
@@ -3559,11 +3473,41 @@ cmSourceFile* cmMakefile::GetOrCreateGeneratedSource(
return sf;
}
-void cmMakefile::CreateGeneratedSources(
+void cmMakefile::CreateGeneratedOutputs(
const std::vector<std::string>& outputs)
{
- for (std::string const& output : outputs) {
- this->GetOrCreateGeneratedSource(output);
+ 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;
}
}
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index de9578aba3..d0dceb95e1 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -173,30 +173,43 @@ public:
cmObjectLibraryCommands objLibCommands,
const cmListFileBacktrace& lfbt) const;
- /** Add a custom command to the build. */
+ /**
+ * Dispatch adding a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a
+ * target.
+ */
cmTarget* AddCustomCommandToTarget(
const std::string& target, const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, cmCustomCommandType type,
const char* comment, const char* workingDir, bool escapeOldStyle = true,
bool uses_terminal = false, const std::string& depfile = "",
- const std::string& job_pool = "", bool command_expand_lists = false,
- cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject);
- cmSourceFile* AddCustomCommandToOutput(
+ const std::string& job_pool = "", bool command_expand_lists = false);
+
+ /**
+ * Called for each file with custom command.
+ */
+ using CommandSourceCallback = std::function<void(cmSourceFile*)>;
+
+ /**
+ * Dispatch adding a custom command to a source file.
+ */
+ void AddCustomCommandToOutput(
const std::string& output, const std::vector<std::string>& depends,
const std::string& main_dependency,
const cmCustomCommandLines& commandLines, const char* comment,
- const char* workingDir, bool replace = false, bool escapeOldStyle = true,
+ const char* workingDir, const CommandSourceCallback& callback = nullptr,
+ bool replace = false, bool escapeOldStyle = true,
bool uses_terminal = false, bool command_expand_lists = false,
const std::string& depfile = "", const std::string& job_pool = "");
- cmSourceFile* AddCustomCommandToOutput(
+ void AddCustomCommandToOutput(
const std::vector<std::string>& outputs,
const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const std::string& main_dependency,
const cmImplicitDependsList& implicit_depends,
const cmCustomCommandLines& commandLines, const char* comment,
- const char* workingDir, bool replace = false, bool escapeOldStyle = true,
+ const char* workingDir, const CommandSourceCallback& callback = nullptr,
+ bool replace = false, bool escapeOldStyle = true,
bool uses_terminal = false, bool command_expand_lists = false,
const std::string& depfile = "", const std::string& job_pool = "");
void AddCustomCommandOldStyle(const std::string& target,
@@ -242,7 +255,7 @@ public:
/** Create a target instance for the utility. */
cmTarget* AddNewUtilityTarget(const std::string& utilityName,
- cmCommandOrigin origin, bool excludeFromAll);
+ bool excludeFromAll);
/**
* Add an executable to the build.
@@ -257,13 +270,12 @@ public:
cmUtilityOutput GetUtilityOutput(cmTarget* target);
/**
- * Add a utility to the build. A utility target is a command that
- * is run every time the target is built.
+ * Dispatch adding a utility to the build. A utility target is a command
+ * that is run every time the target is built.
*/
cmTarget* AddUtilityCommand(
- const std::string& utilityName, cmCommandOrigin origin,
- bool excludeFromAll, const char* workingDirectory,
- const std::vector<std::string>& byproducts,
+ const std::string& utilityName, bool excludeFromAll,
+ const char* workingDir, const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
const char* comment = nullptr, bool uses_terminal = false,
@@ -1079,41 +1091,15 @@ private:
bool ValidateCustomCommand(const cmCustomCommandLines& commandLines) const;
- void CreateGeneratedSources(const std::vector<std::string>& outputs);
-
- void CommitCustomCommandToTarget(
- cmTarget* target, const std::vector<std::string>& byproducts,
- const std::vector<std::string>& depends,
- const cmCustomCommandLines& commandLines, cmCustomCommandType type,
- const char* comment, const char* workingDir, bool escapeOldStyle,
- bool uses_terminal, const std::string& depfile,
- const std::string& job_pool, bool command_expand_lists);
- cmSourceFile* CommitCustomCommandToOutput(
- const std::vector<std::string>& outputs,
- const std::vector<std::string>& byproducts,
- const std::vector<std::string>& depends,
- const std::string& main_dependency,
- const cmImplicitDependsList& implicit_depends,
- const cmCustomCommandLines& commandLines, const char* comment,
- const char* workingDir, bool replace, bool escapeOldStyle,
- bool uses_terminal, bool command_expand_lists, const std::string& depfile,
- const std::string& job_pool);
- void CommitAppendCustomCommandToOutput(
- const std::string& output, const std::vector<std::string>& depends,
- const cmImplicitDependsList& implicit_depends,
- const cmCustomCommandLines& commandLines);
-
- void CommitUtilityCommand(cmTarget* target, const cmUtilityOutput& force,
- const char* workingDirectory,
- const std::vector<std::string>& byproducts,
- const std::vector<std::string>& depends,
- const cmCustomCommandLines& commandLines,
- bool escapeOldStyle, const char* comment,
- bool uses_terminal, bool command_expand_lists,
- const std::string& job_pool);
+ 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
@@ -1133,6 +1119,7 @@ private:
struct SourceEntry
{
cmSourcesWithOutput Sources;
+ bool SourceMightBeOutput = false;
};
// A map for fast output to input look up.
diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index 4792860a59..ef70fcea65 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -7,7 +7,6 @@
#include <cm/memory>
#include "cmCustomCommandLines.h"
-#include "cmCustomCommandTypes.h"
#include "cmDuration.h"
#include "cmGeneratorTarget.h"
#include "cmLocalGenerator.h"
@@ -154,12 +153,12 @@ void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget(
cmMakefile* makefile = localGen->GetMakefile();
// Create utility target
- cmTarget* target = makefile->AddUtilityCommand(
- name, cmCommandOrigin::Generator, true,
- makefile->GetHomeOutputDirectory().c_str() /*work dir*/,
- std::vector<std::string>() /*output*/,
- std::vector<std::string>() /*depends*/, cmCustomCommandLines(), false,
- comment.c_str());
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+ cmCustomCommandLines no_commands;
+ cmTarget* target = localGen->AddUtilityCommand(
+ name, true, makefile->GetHomeOutputDirectory().c_str(), no_byproducts,
+ no_depends, no_commands, false, comment.c_str());
localGen->AddGeneratorTarget(
cm::make_unique<cmGeneratorTarget>(target, localGen));
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 80a0fcf71a..42979af009 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -25,7 +25,6 @@
#include "cmAlgorithms.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
-#include "cmCustomCommandTypes.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
@@ -1118,9 +1117,9 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
}
// Create autogen target
- cmTarget* autogenTarget = this->Makefile->AddUtilityCommand(
- this->AutogenTarget.Name, cmCommandOrigin::Generator, true,
- this->Dir.Work.c_str(), /*byproducts=*/autogenProvides,
+ cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand(
+ this->AutogenTarget.Name, true, this->Dir.Work.c_str(),
+ /*byproducts=*/autogenProvides,
std::vector<std::string>(this->AutogenTarget.DependFiles.begin(),
this->AutogenTarget.DependFiles.end()),
commandLines, false, autogenComment.c_str());
@@ -1200,9 +1199,9 @@ bool cmQtAutoGenInitializer::InitRccTargets()
ccName += cmStrCat('_', qrc.QrcPathChecksum);
}
- cmTarget* autoRccTarget = this->Makefile->AddUtilityCommand(
- ccName, cmCommandOrigin::Generator, true, this->Dir.Work.c_str(),
- ccOutput, ccDepends, commandLines, false, ccComment.c_str());
+ cmTarget* autoRccTarget = this->LocalGen->AddUtilityCommand(
+ ccName, true, this->Dir.Work.c_str(), ccOutput, ccDepends,
+ commandLines, false, ccComment.c_str());
// Create autogen generator target
this->LocalGen->AddGeneratorTarget(
@@ -1239,7 +1238,7 @@ bool cmQtAutoGenInitializer::InitRccTargets()
}
std::string no_main_dependency;
cmImplicitDependsList no_implicit_depends;
- this->Makefile->AddCustomCommandToOutput(
+ this->LocalGen->AddCustomCommandToOutput(
ccOutput, ccByproducts, ccDepends, no_main_dependency,
no_implicit_depends, commandLines, ccComment.c_str(),
this->Dir.Work.c_str());