From bf76a6b801597da424f1fe0f10adc0e8d559adc3 Mon Sep 17 00:00:00 2001 From: Daniel Eiband Date: Thu, 17 Oct 2019 15:40:09 +0200 Subject: cmMakefile: Delay CheckTargetProperties and FinalPass to generate time --- Source/cmExportLibraryDependenciesCommand.cxx | 9 ++++--- Source/cmFLTKWrapUICommand.cxx | 16 +++++++++--- Source/cmGlobalGenerator.cxx | 35 +++++++++++++-------------- Source/cmInstallFilesCommand.cxx | 10 +++++--- Source/cmInstallProgramsCommand.cxx | 10 +++++--- Source/cmLoadCommandCommand.cxx | 9 +++++-- Source/cmMakefile.cxx | 17 +++++++------ Source/cmMakefile.h | 25 ++++++++++--------- Source/cmVariableWatchCommand.cxx | 6 +++-- 9 files changed, 83 insertions(+), 54 deletions(-) diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx index 89093e9..dfc8de5 100644 --- a/Source/cmExportLibraryDependenciesCommand.cxx +++ b/Source/cmExportLibraryDependenciesCommand.cxx @@ -12,6 +12,7 @@ #include "cmExecutionStatus.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -20,6 +21,8 @@ #include "cmTargetLinkLibraryType.h" #include "cmake.h" +class cmListFileBacktrace; + static void FinalAction(cmMakefile& makefile, std::string const& filename, bool append) { @@ -150,9 +153,9 @@ bool cmExportLibraryDependenciesCommand(std::vector const& args, std::string const& filename = args[0]; bool const append = args.size() > 1 && args[1] == "APPEND"; - status.GetMakefile().AddFinalAction( - [filename, append](cmMakefile& makefile) { - FinalAction(makefile, filename, append); + status.GetMakefile().AddGeneratorAction( + [filename, append](cmLocalGenerator& lg, const cmListFileBacktrace&) { + FinalAction(*lg.GetMakefile(), filename, append); }); return true; diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx index 11844e4..d88617a 100644 --- a/Source/cmFLTKWrapUICommand.cxx +++ b/Source/cmFLTKWrapUICommand.cxx @@ -6,15 +6,20 @@ #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" +#include "cmListFileCache.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmRange.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmake.h" class cmTarget; -static void FinalAction(cmMakefile& makefile, std::string const& name) +static void FinalAction(cmMakefile& makefile, std::string const& name, + const cmListFileBacktrace& lfbt) { // people should add the srcs to the target themselves, but the old command // didn't support that, so check and see if they added the files in and if @@ -26,7 +31,8 @@ static void FinalAction(cmMakefile& makefile, std::string const& name) ". The problem was found while processing the source directory: ", makefile.GetCurrentSourceDirectory(), ". This FLTK_WRAP_UI call will be ignored."); - cmSystemTools::Message(msg, "Warning"); + makefile.GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_ERROR, msg, + lfbt); } } @@ -116,7 +122,9 @@ bool cmFLTKWrapUICommand(std::vector const& args, std::string const varName = target + "_FLTK_UI_SRCS"; mf.AddDefinition(varName, sourceListValue); - mf.AddFinalAction( - [target](cmMakefile& makefile) { FinalAction(makefile, target); }); + mf.AddGeneratorAction( + [target](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) { + FinalAction(*lg.GetMakefile(), target, lfbt); + }); return true; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index e38066f..965ee6d 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -34,6 +34,7 @@ #include "cmGeneratorTarget.h" #include "cmInstallGenerator.h" #include "cmLinkLineComputer.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMSVC60LinkLineComputer.h" #include "cmMakefile.h" @@ -1262,10 +1263,6 @@ void cmGlobalGenerator::Configure() "number of local generators", cmStateEnums::INTERNAL); - // check for link libraries and include directories containing "NOTFOUND" - // and for infinite loops - this->CheckTargetProperties(); - if (this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE) { std::ostringstream msg; if (cmSystemTools::GetErrorOccuredFlag()) { @@ -1288,6 +1285,10 @@ void cmGlobalGenerator::Configure() void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes) { this->CreateLocalGenerators(); + // Commit side effects only if we are actually generating + if (this->GetConfigureDoneCMP0026()) { + this->CheckTargetProperties(); + } this->CreateGeneratorTargets(targetTypes); this->ComputeBuildFileGenerators(); } @@ -1464,6 +1465,8 @@ void cmGlobalGenerator::Generate() this->ProcessEvaluationFiles(); + this->CMakeInstance->UpdateProgress("Generating", 0.1f); + // Generate project files for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile()); @@ -1475,8 +1478,9 @@ void cmGlobalGenerator::Generate() this->LocalGenerators[i]->GenerateTestFiles(); this->CMakeInstance->UpdateProgress( "Generating", - (static_cast(i) + 1.0f) / - static_cast(this->LocalGenerators.size())); + 0.1f + + 0.9f * (static_cast(i) + 1.0f) / + static_cast(this->LocalGenerators.size())); } this->SetCurrentMakefile(nullptr); @@ -1714,12 +1718,12 @@ void cmGlobalGenerator::ComputeTargetObjectDirectory( void cmGlobalGenerator::CheckTargetProperties() { + // check for link libraries and include directories containing "NOTFOUND" + // and for infinite loops std::map notFoundMap; - // std::set notFoundMap; - // after it is all done do a ConfigureFinalPass cmState* state = this->GetCMakeInstance()->GetState(); for (unsigned int i = 0; i < this->Makefiles.size(); ++i) { - this->Makefiles[i]->ConfigureFinalPass(); + this->Makefiles[i]->Generate(*this->LocalGenerators[i]); for (auto const& target : this->Makefiles[i]->GetTargets()) { if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; @@ -1763,11 +1767,6 @@ void cmGlobalGenerator::CheckTargetProperties() } } } - this->CMakeInstance->UpdateProgress( - "Configuring", - 0.9f + - 0.1f * (static_cast(i) + 1.0f) / - static_cast(this->Makefiles.size())); } if (!notFoundMap.empty()) { @@ -2017,10 +2016,10 @@ void cmGlobalGenerator::AddMakefile(cmMakefile* mf) } int numGen = atoi(numGenC->c_str()); - float prog = 0.9f * static_cast(this->Makefiles.size()) / - static_cast(numGen); - if (prog > 0.9f) { - prog = 0.9f; + float prog = + static_cast(this->Makefiles.size()) / static_cast(numGen); + if (prog > 1.0f) { + prog = 1.0f; } this->CMakeInstance->UpdateProgress("Configuring", prog); } diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx index d623943..efbcb98 100644 --- a/Source/cmInstallFilesCommand.cxx +++ b/Source/cmInstallFilesCommand.cxx @@ -7,11 +7,14 @@ #include "cmGlobalGenerator.h" #include "cmInstallFilesGenerator.h" #include "cmInstallGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmRange.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +class cmListFileBacktrace; + static std::string FindInstallSource(cmMakefile& makefile, const char* name); static void CreateInstallGenerator(cmMakefile& makefile, std::string const& dest, @@ -43,9 +46,10 @@ bool cmInstallFilesCommand(std::vector const& args, CreateInstallGenerator(mf, dest, files); } else { std::vector finalArgs(args.begin() + 1, args.end()); - mf.AddFinalAction([dest, finalArgs](cmMakefile& makefile) { - FinalAction(makefile, dest, finalArgs); - }); + mf.AddGeneratorAction( + [dest, finalArgs](cmLocalGenerator& lg, const cmListFileBacktrace&) { + FinalAction(*lg.GetMakefile(), dest, finalArgs); + }); } mf.GetGlobalGenerator()->AddInstallComponent( diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx index 6bb4409..2088eae 100644 --- a/Source/cmInstallProgramsCommand.cxx +++ b/Source/cmInstallProgramsCommand.cxx @@ -7,10 +7,13 @@ #include "cmGlobalGenerator.h" #include "cmInstallFilesGenerator.h" #include "cmInstallGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +class cmListFileBacktrace; + static void FinalAction(cmMakefile& makefile, std::string const& dest, std::vector const& args); static std::string FindInstallSource(cmMakefile& makefile, const char* name); @@ -33,9 +36,10 @@ bool cmInstallProgramsCommand(std::vector const& args, std::string const& dest = args[0]; std::vector const finalArgs(args.begin() + 1, args.end()); - mf.AddFinalAction([dest, finalArgs](cmMakefile& makefile) { - FinalAction(makefile, dest, finalArgs); - }); + mf.AddGeneratorAction( + [dest, finalArgs](cmLocalGenerator& lg, const cmListFileBacktrace&) { + FinalAction(*lg.GetMakefile(), dest, finalArgs); + }); return true; } diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx index 23ace64..92258e2 100644 --- a/Source/cmLoadCommandCommand.cxx +++ b/Source/cmLoadCommandCommand.cxx @@ -14,6 +14,7 @@ #include "cmCommand.h" #include "cmDynamicLoader.h" #include "cmExecutionStatus.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -25,6 +26,8 @@ # include /* for malloc/free on QNX */ #endif +class cmListFileBacktrace; + namespace { const char* LastName = nullptr; @@ -158,8 +161,10 @@ bool cmLoadedCommand::InitialPass(std::vector const& args, if (result) { if (this->Impl->FinalPass) { auto impl = this->Impl; - this->Makefile->AddFinalAction( - [impl](cmMakefile& makefile) { impl->DoFinalPass(&makefile); }); + this->Makefile->AddGeneratorAction( + [impl](cmLocalGenerator& lg, const cmListFileBacktrace&) { + impl->DoFinalPass(lg.GetMakefile()); + }); } return true; } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index bf488b1..41dabbd 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -36,6 +36,7 @@ #include "cmInstallGenerator.h" // IWYU pragma: keep #include "cmInstallSubdirectoryGenerator.h" #include "cmListFileCache.h" +#include "cmLocalGenerator.h" #include "cmMessageType.h" #include "cmRange.h" #include "cmSourceFile.h" @@ -780,21 +781,23 @@ struct file_not_persistent }; } -void cmMakefile::AddFinalAction(FinalAction action) +void cmMakefile::AddGeneratorAction(GeneratorAction action) { - this->FinalActions.push_back(std::move(action)); + assert(!this->GeneratorActionsInvoked); + this->GeneratorActions.emplace_back(std::move(action), this->Backtrace); } -void cmMakefile::FinalPass() +void cmMakefile::DoGenerate(cmLocalGenerator& lg) { // do all the variable expansions here this->ExpandVariablesCMP0019(); // give all the commands a chance to do something // after the file has been parsed before generation - for (FinalAction& action : this->FinalActions) { - action(*this); + for (const BT& action : this->GeneratorActions) { + action.Value(lg, action.Backtrace); } + this->GeneratorActionsInvoked = true; // 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 @@ -809,9 +812,9 @@ void cmMakefile::FinalPass() } // Generate the output file -void cmMakefile::ConfigureFinalPass() +void cmMakefile::Generate(cmLocalGenerator& lg) { - this->FinalPass(); + this->DoGenerate(lg); const char* oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY"); if (oldValue && cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 6e59494..83a99f6 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -49,6 +49,7 @@ class cmGeneratorExpressionEvaluationFile; class cmGlobalGenerator; class cmImplicitDependsList; class cmInstallGenerator; +class cmLocalGenerator; class cmMessenger; class cmSourceFile; class cmState; @@ -151,23 +152,19 @@ public: bool EnforceUniqueName(std::string const& name, std::string& msg, bool isCustom = false) const; - using FinalAction = std::function; + using GeneratorAction = + std::function; /** - * Register an action that is executed during FinalPass + * Register an action that is executed during Generate */ - void AddFinalAction(FinalAction action); + void AddGeneratorAction(GeneratorAction action); /** - * Perform FinalPass, Library dependency analysis etc before output of the - * makefile. + * Perform generate actions, Library dependency analysis etc before output of + * the makefile. */ - void ConfigureFinalPass(); - - /** - * run all FinalActions. - */ - void FinalPass(); + void Generate(cmLocalGenerator& lg); /** * Get the target for PRE_BUILD, PRE_LINK, or POST_BUILD commands. @@ -1001,7 +998,6 @@ protected: size_t ObjectLibrariesSourceGroupIndex; #endif - std::vector FinalActions; cmGlobalGenerator* GlobalGenerator; bool IsFunctionBlocked(const cmListFileFunction& lff, cmExecutionStatus& status); @@ -1011,6 +1007,8 @@ private: cmListFileBacktrace Backtrace; int RecursionDepth; + void DoGenerate(cmLocalGenerator& lg); + void ReadListFile(cmListFile const& listFile, const std::string& filenametoread); @@ -1113,6 +1111,9 @@ private: bool uses_terminal, bool command_expand_lists, const std::string& job_pool); + std::vector> GeneratorActions; + bool GeneratorActionsInvoked = false; + /** * See LinearGetSourceFileWithOutput for background information */ diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index 039f1ba..35b9a1d 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -15,6 +15,8 @@ #include "cmVariableWatch.h" #include "cmake.h" +class cmLocalGenerator; + namespace { struct cmVariableWatchCallbackData { @@ -91,7 +93,7 @@ public: { } - void operator()(cmMakefile&) const {} + void operator()(cmLocalGenerator&, const cmListFileBacktrace&) const {} private: struct Impl @@ -145,7 +147,7 @@ bool cmVariableWatchCommand(std::vector const& args, return false; } - status.GetMakefile().AddFinalAction( + status.GetMakefile().AddGeneratorAction( FinalAction{ &status.GetMakefile(), variable }); return true; } -- cgit v0.12 From e8360afbf7588cb73c3fed1cfe01595dc221645c Mon Sep 17 00:00:00 2001 From: Daniel Eiband Date: Thu, 17 Oct 2019 15:52:57 +0200 Subject: cmPluginAPI: Correct typo in documentation of FinalPass --- Source/cmCPluginAPI.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/cmCPluginAPI.h b/Source/cmCPluginAPI.h index 6a95148..19626f0 100644 --- a/Source/cmCPluginAPI.h +++ b/Source/cmCPluginAPI.h @@ -36,7 +36,7 @@ typedef struct of functions are utility functions that are specific to the plugin API =========================================================================*/ /* set/Get the ClientData in the cmLoadedCommandInfo structure, this is how - information is passed from the InitialPass to FInalPass for commands + information is passed from the InitialPass to FinalPass for commands that need a FinalPass and need information from the InitialPass */ void*(CCONV* GetClientData)(void* info); /* return the summed size in characters of all the arguments */ @@ -44,7 +44,7 @@ typedef struct /* free all the memory associated with an argc, argv pair */ void(CCONV* FreeArguments)(int argc, char** argv); /* set/Get the ClientData in the cmLoadedCommandInfo structure, this is how - information is passed from the InitialPass to FInalPass for commands + information is passed from the InitialPass to FinalPass for commands that need a FinalPass and need information from the InitialPass */ void(CCONV* SetClientData)(void* info, void* cd); /* when an error occurs, call this function to set the error string */ -- cgit v0.12 From 3dc084ebc1fb261aea69dbd254d50ffd1604dc80 Mon Sep 17 00:00:00 2001 From: Daniel Eiband Date: Thu, 17 Oct 2019 15:50:34 +0200 Subject: cmMakefile: Explicitly pass backtrace to GetCustomCommandTarget Allow GetCustomCommandTarget to be called at generate time with correct backtraces. --- Source/cmMakefile.cxx | 38 +++++++++++++++++++------------------- Source/cmMakefile.h | 5 +++-- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 41dabbd..c4d757e 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -147,7 +147,7 @@ void cmMakefile::IssueMessage(MessageType t, std::string const& text) const this->ExecutionStatusStack.back()->SetNestedError(); } } - this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace()); + this->GetCMakeInstance()->IssueMessage(t, text, this->Backtrace); } bool cmMakefile::CheckCMP0037(std::string const& targetName, @@ -845,7 +845,8 @@ bool cmMakefile::ValidateCustomCommand( } cmTarget* cmMakefile::GetCustomCommandTarget( - const std::string& target, cmObjectLibraryCommands objLibCommands) const + const std::string& target, cmObjectLibraryCommands objLibCommands, + const cmListFileBacktrace& lfbt) const { // Find the target to which to add the custom command. auto ti = this->Targets.find(target); @@ -879,7 +880,7 @@ cmTarget* cmMakefile::GetCustomCommandTarget( e << "No TARGET '" << target << "' has been created in this directory."; } - this->IssueMessage(messageType, e.str()); + this->GetCMakeInstance()->IssueMessage(messageType, e.str(), lfbt); } return nullptr; @@ -892,7 +893,8 @@ cmTarget* cmMakefile::GetCustomCommandTarget( e << "Target \"" << target << "\" is an OBJECT library " "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands."; - this->IssueMessage(MessageType::FATAL_ERROR, e.str()); + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(), + lfbt); return nullptr; } if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) { @@ -900,7 +902,8 @@ cmTarget* cmMakefile::GetCustomCommandTarget( e << "Target \"" << target << "\" is an INTERFACE library " "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands."; - this->IssueMessage(MessageType::FATAL_ERROR, e.str()); + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(), + lfbt); return nullptr; } @@ -915,7 +918,8 @@ cmTarget* cmMakefile::AddCustomCommandToTarget( bool uses_terminal, const std::string& depfile, const std::string& job_pool, bool command_expand_lists, cmObjectLibraryCommands objLibCommands) { - cmTarget* t = this->GetCustomCommandTarget(target, objLibCommands); + cmTarget* t = + this->GetCustomCommandTarget(target, objLibCommands, this->Backtrace); // Validate custom commands. if (!t || !this->ValidateCustomCommand(commandLines)) { @@ -1360,13 +1364,12 @@ void cmMakefile::AddLinkOption(std::string const& option) void cmMakefile::AddLinkDirectory(std::string const& directory, bool before) { - cmListFileBacktrace lfbt = this->GetBacktrace(); if (before) { - this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(directory, - lfbt); + this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry( + directory, this->Backtrace); } else { - this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(directory, - lfbt); + this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry( + directory, this->Backtrace); } } @@ -1823,20 +1826,19 @@ void cmMakefile::AddIncludeDirectories(const std::vector& incs, return; } - cmListFileBacktrace lfbt = this->GetBacktrace(); std::string entryString = cmJoin(incs, ";"); if (before) { this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry( - entryString, lfbt); + entryString, this->Backtrace); } else { this->StateSnapshot.GetDirectory().AppendIncludeDirectoriesEntry( - entryString, lfbt); + entryString, this->Backtrace); } // Property on each target: for (auto& target : this->Targets) { cmTarget& t = target.second; - t.InsertInclude(entryString, lfbt, before); + t.InsertInclude(entryString, this->Backtrace, before); } } @@ -4032,16 +4034,14 @@ int cmMakefile::ConfigureFile(const std::string& infile, void cmMakefile::SetProperty(const std::string& prop, const char* value) { - cmListFileBacktrace lfbt = this->GetBacktrace(); - this->StateSnapshot.GetDirectory().SetProperty(prop, value, lfbt); + this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace); } void cmMakefile::AppendProperty(const std::string& prop, const char* value, bool asString) { - cmListFileBacktrace lfbt = this->GetBacktrace(); this->StateSnapshot.GetDirectory().AppendProperty(prop, value, asString, - lfbt); + this->Backtrace); } const char* cmMakefile::GetProperty(const std::string& prop) const diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 83a99f6..de9578a 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -169,8 +169,9 @@ public: /** * Get the target for PRE_BUILD, PRE_LINK, or POST_BUILD commands. */ - cmTarget* GetCustomCommandTarget( - const std::string& target, cmObjectLibraryCommands objLibCommands) const; + cmTarget* GetCustomCommandTarget(const std::string& target, + cmObjectLibraryCommands objLibCommands, + const cmListFileBacktrace& lfbt) const; /** Add a custom command to the build. */ cmTarget* AddCustomCommandToTarget( -- cgit v0.12 From 96e5042e468c5551b9b6ca01f8671295b2fda1a6 Mon Sep 17 00:00:00 2001 From: Daniel Eiband Date: Thu, 17 Oct 2019 16:15:44 +0200 Subject: cmCustomCommand: Explicitly pass backtrace on construction --- Source/cmCustomCommand.cxx | 10 +++------- Source/cmCustomCommand.h | 8 +++----- Source/cmGlobalGenerator.cxx | 4 ++-- Source/cmGlobalVisualStudioGenerator.cxx | 7 ++++--- Source/cmGlobalXCodeGenerator.cxx | 10 +++++----- Source/cmLocalVisualStudioGenerator.cxx | 4 ++-- Source/cmMakefile.cxx | 7 ++++--- Source/cmQtAutoGenInitializer.cxx | 4 ++-- 8 files changed, 25 insertions(+), 29 deletions(-) diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index 09d269b..7cc3c04 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -5,26 +5,22 @@ #include #include "cmAlgorithms.h" -#include "cmMakefile.h" -cmCustomCommand::cmCustomCommand(cmMakefile const* mf, - std::vector outputs, +cmCustomCommand::cmCustomCommand(std::vector outputs, std::vector byproducts, std::vector depends, cmCustomCommandLines commandLines, - const char* comment, + cmListFileBacktrace lfbt, const char* comment, const char* workingDirectory) : Outputs(std::move(outputs)) , Byproducts(std::move(byproducts)) , Depends(std::move(depends)) , CommandLines(std::move(commandLines)) + , Backtrace(std::move(lfbt)) , Comment(comment ? comment : "") , WorkingDirectory(workingDirectory ? workingDirectory : "") , HaveComment(comment != nullptr) { - if (mf) { - this->Backtrace = mf->GetBacktrace(); - } } const std::vector& cmCustomCommand::GetOutputs() const diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index 4689ace..d300fa5 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -12,8 +12,6 @@ #include "cmCustomCommandLines.h" #include "cmListFileCache.h" -class cmMakefile; - class cmImplicitDependsList : public std::vector> { @@ -28,11 +26,11 @@ class cmCustomCommand { public: /** Main constructor specifies all information for the command. */ - cmCustomCommand(cmMakefile const* mf, std::vector outputs, + cmCustomCommand(std::vector outputs, std::vector byproducts, std::vector depends, - cmCustomCommandLines commandLines, const char* comment, - const char* workingDirectory); + cmCustomCommandLines commandLines, cmListFileBacktrace lfbt, + const char* comment, const char* workingDirectory); /** Get the output file produced by the command. */ const std::vector& GetOutputs() const; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 965ee6d..8dfc0ce 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2651,8 +2651,8 @@ cmTarget cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti, std::vector no_byproducts; std::vector no_depends; // Store the custom command in the target. - cmCustomCommand cc(nullptr, no_outputs, no_byproducts, no_depends, - gti.CommandLines, nullptr, gti.WorkingDir.c_str()); + cmCustomCommand cc(no_outputs, no_byproducts, no_depends, gti.CommandLines, + cmListFileBacktrace(), nullptr, gti.WorkingDir.c_str()); cc.SetUsesTerminal(gti.UsesTerminal); target.AddPostBuildCommand(std::move(cc)); if (!gti.Message.empty()) { diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 2181994..b687e56 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -930,9 +930,10 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( cmCustomCommandLines commandLines = cmMakeSingleCommandLine( { cmakeCommand, "-E", "__create_def", mdi->DefFile, objs_file }); - cmCustomCommand command(gt->Target->GetMakefile(), outputs, empty, empty, - commandLines, "Auto build dll exports", "."); - commands.push_back(command); + cmCustomCommand command(outputs, empty, empty, commandLines, + gt->Target->GetMakefile()->GetBacktrace(), + "Auto build dll exports", "."); + commands.push_back(std::move(command)); } static bool OpenSolution(std::string sln) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 9e6741d..280ac26 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1462,12 +1462,12 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library", str_file, str_so_file, str_link_file }); - cmCustomCommand command(this->CurrentMakefile, std::vector(), - std::vector(), - std::vector(), cmd, - "Creating symlinks", ""); + cmCustomCommand command( + std::vector(), std::vector(), + std::vector(), cmd, this->CurrentMakefile->GetBacktrace(), + "Creating symlinks", ""); - postbuild.push_back(command); + postbuild.push_back(std::move(command)); } std::vector classes; diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index 336e3a5..8d50898 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -104,8 +104,8 @@ cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmGeneratorTarget* target, std::vector no_depends; cmCustomCommandLines commands = cmMakeSingleCommandLine( { cmSystemTools::GetCMakeCommand(), "-E", "make_directory", impDir }); - pcc.reset(new cmCustomCommand(0, no_output, no_byproducts, no_depends, - commands, 0, 0)); + pcc.reset(new cmCustomCommand(no_output, no_byproducts, no_depends, commands, + cmListFileBacktrace(), nullptr, nullptr)); pcc->SetEscapeOldStyle(false); pcc->SetEscapeAllowMakeVars(true); return pcc; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index c4d757e..c6c8109 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -946,8 +946,8 @@ void cmMakefile::CommitCustomCommandToTarget( { // Add the command to the appropriate build step for the target. std::vector no_output; - cmCustomCommand cc(this, no_output, byproducts, depends, commandLines, - comment, workingDir); + cmCustomCommand cc(no_output, byproducts, depends, commandLines, + this->Backtrace, comment, workingDir); cc.SetEscapeOldStyle(escapeOldStyle); cc.SetEscapeAllowMakeVars(true); cc.SetUsesTerminal(uses_terminal); @@ -1083,7 +1083,8 @@ cmSourceFile* cmMakefile::CommitCustomCommandToOutput( } std::unique_ptr cc = cm::make_unique( - this, outputs, byproducts, depends2, commandLines, comment, workingDir); + outputs, byproducts, depends2, commandLines, this->Backtrace, comment, + workingDir); cc->SetEscapeOldStyle(escapeOldStyle); cc->SetEscapeAllowMakeVars(true); cc->SetImplicitDepends(implicit_depends); diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 68b7122..80a0fcf 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -1082,8 +1082,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // PRE_BUILD does not support file dependencies! const std::vector no_output; const std::vector no_deps; - cmCustomCommand cc(this->Makefile, no_output, autogenProvides, no_deps, - commandLines, autogenComment.c_str(), + cmCustomCommand cc(no_output, autogenProvides, no_deps, commandLines, + this->Makefile->GetBacktrace(), autogenComment.c_str(), this->Dir.Work.c_str()); cc.SetEscapeOldStyle(false); cc.SetEscapeAllowMakeVars(true); -- cgit v0.12 From 4e37508c8570bd6b846aa67478e97ec370ab4feb Mon Sep 17 00:00:00 2001 From: Daniel Eiband Date: Thu, 17 Oct 2019 16:20:52 +0200 Subject: cmLocalGenerator: Refactor to use cmMakeSingleCommandLine --- Source/cmLocalGenerator.cxx | 10 +++------- bootstrap | 1 + 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index c43876c..bdc0358 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2387,13 +2387,9 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) file << "endif()\n"; } - cmCustomCommandLines commandLines; - cmCustomCommandLine currentLine; - currentLine.push_back(cmSystemTools::GetCMakeCommand()); - currentLine.push_back(cmStrCat("-DPDB_PREFIX=", pdb_prefix)); - currentLine.push_back("-P"); - currentLine.push_back(copy_script); - commandLines.push_back(std::move(currentLine)); + cmCustomCommandLines commandLines = cmMakeSingleCommandLine( + { cmSystemTools::GetCMakeCommand(), + cmStrCat("-DPDB_PREFIX=", pdb_prefix), "-P", copy_script }); const std::string no_main_dependency; const std::vector no_deps; diff --git a/bootstrap b/bootstrap index 4432d49..8606dda 100755 --- a/bootstrap +++ b/bootstrap @@ -294,6 +294,7 @@ CMAKE_CXX_SOURCES="\ cmCreateTestSourceList \ cmCustomCommand \ cmCustomCommandGenerator \ + cmCustomCommandLines \ cmDefinePropertyCommand \ cmDefinitions \ cmDepends \ -- cgit v0.12 From 777ceaea94cec5c4388e3b11495904ad8e408535 Mon Sep 17 00:00:00 2001 From: Daniel Eiband Date: Thu, 17 Oct 2019 17:02:20 +0200 Subject: 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 --- Source/cmAddCustomCommandCommand.cxx | 2 +- Source/cmAddCustomTargetCommand.cxx | 7 +- Source/cmCPluginAPI.cxx | 6 +- Source/cmGlobalVisualStudio8Generator.cxx | 11 +- Source/cmGlobalVisualStudioGenerator.cxx | 6 +- Source/cmGlobalXCodeGenerator.cxx | 19 +- Source/cmLocalGenerator.cxx | 338 ++++++++++++++++++++++++- Source/cmLocalGenerator.h | 91 +++++++ Source/cmLocalVisualStudio7Generator.cxx | 12 +- Source/cmMakefile.cxx | 396 +++++++++++++----------------- Source/cmMakefile.h | 77 +++--- Source/cmQtAutoGenGlobalInitializer.cxx | 13 +- Source/cmQtAutoGenInitializer.cxx | 15 +- 13 files changed, 667 insertions(+), 326 deletions(-) diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 6e04ce5..52fc5d5 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -343,7 +343,7 @@ bool cmAddCustomCommandCommand(std::vector 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 e27b126..aa98d89 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 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 177bca8..b5c7e96 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 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 d39d42a..ea603b0 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -101,15 +101,14 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() std::vector const& generators = this->LocalGenerators; cmLocalVisualStudio7Generator* lg = static_cast(generators[0]); - cmMakefile* mf = lg->GetMakefile(); const char* no_working_directory = nullptr; std::vector no_byproducts; std::vector 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(tgt, lg); auto gt = ptr.get(); @@ -156,7 +155,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() std::vector 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 b687e56..be5cfd4 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(allBuild, gen[0])); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 280ac26..d75c489 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -500,16 +500,13 @@ std::string cmGlobalXCodeGenerator::PostBuildMakeTarget( void cmGlobalXCodeGenerator::AddExtraTargets( cmLocalGenerator* root, std::vector& gens) { - cmMakefile* mf = root->GetMakefile(); - const char* no_working_directory = nullptr; std::vector no_byproducts; std::vector 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(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(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 bdc0358..c88805f 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -14,6 +14,7 @@ #include #include +#include #include #include "cmsys/RegularExpression.hxx" @@ -988,6 +989,91 @@ void cmLocalGenerator::AddCompileOptions(std::vector>& flags, } } +cmTarget* cmLocalGenerator::AddCustomCommandToTarget( + const std::string& target, const std::vector& byproducts, + const std::vector& 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& 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 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& outputs, + const std::vector& byproducts, + const std::vector& 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& byproducts, + const std::vector& 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> 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& 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& outputs, + const std::vector& byproducts, + const std::vector& 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 depends2(depends); + if (!main_dependency.empty()) { + depends2.push_back(main_dependency); + } + + std::unique_ptr cc = cm::make_unique( + 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& byproducts, + const std::vector& 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 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& outputs, + const std::vector& byproducts, + const std::vector& 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& 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& byproducts, + const std::vector& 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 e5c89f9..8788c2f 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& byproducts, + const std::vector& 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& 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& outputs, + const std::vector& byproducts, + const std::vector& 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& byproducts, + const std::vector& 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& byproducts, + const std::vector& 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& outputs, + const std::vector& byproducts, + const std::vector& 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& 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& byproducts, + const std::vector& 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 5354f14..0758fd4 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 c6c8109..dc0b50f 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -14,7 +14,7 @@ #include #include -#include +#include #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 MakeOptionalString(const char* str) +{ + if (str) { + return str; + } + return cm::nullopt; +} + +const char* GetCStrOrNull(const cm::optional& 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 commentStr = MakeOptionalString(comment); + cm::optional 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& byproducts, - const std::vector& 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 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& 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 outputs; - outputs.push_back(output); std::vector 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& outputs, const std::vector& byproducts, const std::vector& 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& outputs, - const std::vector& byproducts, - const std::vector& 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 commentStr = MakeOptionalString(comment); + cm::optional 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 depends2(depends); - if (!main_dependency.empty()) { - depends2.push_back(main_dependency); - } - - std::unique_ptr cc = cm::make_unique( - 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& 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& byproducts, + const std::string& utilityName, bool excludeFromAll, const char* workingDir, + const std::vector& byproducts, const std::vector& 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 commentStr = MakeOptionalString(comment); + cm::optional 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& byproducts, - const std::vector& depends, - const cmCustomCommandLines& commandLines, bool escapeOldStyle, - const char* comment, bool uses_terminal, bool command_expand_lists, - const std::string& job_pool) -{ - std::vector 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& 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& 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 de9578a..d0dceb9 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& byproducts, const std::vector& 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; + + /** + * Dispatch adding a custom command to a source file. + */ + void AddCustomCommandToOutput( const std::string& output, const std::vector& 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& outputs, const std::vector& byproducts, const std::vector& 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& byproducts, + const std::string& utilityName, bool excludeFromAll, + const char* workingDir, const std::vector& byproducts, const std::vector& 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& outputs); - - void CommitCustomCommandToTarget( - cmTarget* target, const std::vector& byproducts, - const std::vector& 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& outputs, - const std::vector& byproducts, - const std::vector& 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& depends, - const cmImplicitDependsList& implicit_depends, - const cmCustomCommandLines& commandLines); - - void CommitUtilityCommand(cmTarget* target, const cmUtilityOutput& force, - const char* workingDirectory, - const std::vector& byproducts, - const std::vector& 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& outputs); + void CreateGeneratedByproducts(const std::vector& byproducts); std::vector> GeneratorActions; bool GeneratorActionsInvoked = false; + bool DelayedOutputFilesHaveGenex = false; + std::vector 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 4792860..ef70fce 100644 --- a/Source/cmQtAutoGenGlobalInitializer.cxx +++ b/Source/cmQtAutoGenGlobalInitializer.cxx @@ -7,7 +7,6 @@ #include #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() /*output*/, - std::vector() /*depends*/, cmCustomCommandLines(), false, - comment.c_str()); + std::vector no_byproducts; + std::vector 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(target, localGen)); diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 80a0fcf..42979af 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(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()); -- cgit v0.12