diff options
author | Daniel Eiband <daniel.eiband@brainlab.com> | 2019-10-17 15:02:20 (GMT) |
---|---|---|
committer | Daniel Eiband <daniel.eiband@brainlab.com> | 2019-11-24 19:32:43 (GMT) |
commit | 777ceaea94cec5c4388e3b11495904ad8e408535 (patch) | |
tree | 200a986e08bb827255315101fb1e52d843e220ab /Source/cmLocalGenerator.cxx | |
parent | 4e37508c8570bd6b846aa67478e97ec370ab4feb (diff) | |
download | CMake-777ceaea94cec5c4388e3b11495904ad8e408535.zip CMake-777ceaea94cec5c4388e3b11495904ad8e408535.tar.gz CMake-777ceaea94cec5c4388e3b11495904ad8e408535.tar.bz2 |
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/cmLocalGenerator.cxx')
-rw-r--r-- | Source/cmLocalGenerator.cxx | 338 |
1 files changed, 332 insertions, 6 deletions
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 <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); + } +} +} |