| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmNinjaUtilityTargetGenerator.h" |
| |
| #include <algorithm> |
| #include <array> |
| #include <iterator> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "cmCustomCommand.h" |
| #include "cmCustomCommandGenerator.h" |
| #include "cmGeneratedFileStream.h" |
| #include "cmGeneratorTarget.h" |
| #include "cmGlobalNinjaGenerator.h" |
| #include "cmLocalNinjaGenerator.h" |
| #include "cmMakefile.h" |
| #include "cmNinjaTypes.h" |
| #include "cmOutputConverter.h" |
| #include "cmSourceFile.h" |
| #include "cmStateTypes.h" |
| #include "cmStringAlgorithms.h" |
| #include "cmSystemTools.h" |
| |
| cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator( |
| cmGeneratorTarget* target) |
| : cmNinjaTargetGenerator(target) |
| { |
| } |
| |
| cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default; |
| |
| void cmNinjaUtilityTargetGenerator::Generate() |
| { |
| cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator(); |
| cmLocalNinjaGenerator* lg = this->GetLocalGenerator(); |
| cmGeneratorTarget* genTarget = this->GetGeneratorTarget(); |
| |
| std::string utilCommandName = |
| cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles/", |
| this->GetTargetName(), ".util"); |
| utilCommandName = this->ConvertToNinjaPath(utilCommandName); |
| |
| cmNinjaBuild phonyBuild("phony"); |
| std::vector<std::string> commands; |
| cmNinjaDeps deps; |
| cmNinjaDeps util_outputs(1, utilCommandName); |
| |
| bool uses_terminal = false; |
| { |
| std::array<std::vector<cmCustomCommand> const*, 2> const cmdLists = { |
| { &genTarget->GetPreBuildCommands(), &genTarget->GetPostBuildCommands() } |
| }; |
| |
| for (std::vector<cmCustomCommand> const* cmdList : cmdLists) { |
| for (cmCustomCommand const& ci : *cmdList) { |
| cmCustomCommandGenerator ccg(ci, this->GetConfigName(), lg); |
| lg->AppendCustomCommandDeps(ccg, deps); |
| lg->AppendCustomCommandLines(ccg, commands); |
| std::vector<std::string> const& ccByproducts = ccg.GetByproducts(); |
| std::transform(ccByproducts.begin(), ccByproducts.end(), |
| std::back_inserter(util_outputs), MapToNinjaPath()); |
| if (ci.GetUsesTerminal()) { |
| uses_terminal = true; |
| } |
| } |
| } |
| } |
| |
| { |
| std::string const& config = |
| this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"); |
| std::vector<cmSourceFile*> sources; |
| genTarget->GetSourceFiles(sources, config); |
| for (cmSourceFile const* source : sources) { |
| if (cmCustomCommand const* cc = source->GetCustomCommand()) { |
| cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), lg); |
| lg->AddCustomCommandTarget(cc, genTarget); |
| |
| // Depend on all custom command outputs. |
| const std::vector<std::string>& ccOutputs = ccg.GetOutputs(); |
| const std::vector<std::string>& ccByproducts = ccg.GetByproducts(); |
| std::transform(ccOutputs.begin(), ccOutputs.end(), |
| std::back_inserter(deps), MapToNinjaPath()); |
| std::transform(ccByproducts.begin(), ccByproducts.end(), |
| std::back_inserter(deps), MapToNinjaPath()); |
| } |
| } |
| } |
| |
| lg->AppendTargetOutputs(genTarget, phonyBuild.Outputs); |
| lg->AppendTargetDepends(genTarget, deps); |
| |
| if (commands.empty()) { |
| phonyBuild.Comment = "Utility command for " + this->GetTargetName(); |
| phonyBuild.ExplicitDeps = std::move(deps); |
| gg->WriteBuild(this->GetBuildFileStream(), phonyBuild); |
| } else { |
| std::string command = |
| lg->BuildCommandLine(commands, "utility", this->GeneratorTarget); |
| std::string desc; |
| const char* echoStr = genTarget->GetProperty("EchoString"); |
| if (echoStr) { |
| desc = echoStr; |
| } else { |
| desc = "Running utility command for " + this->GetTargetName(); |
| } |
| |
| // TODO: fix problematic global targets. For now, search and replace the |
| // makefile vars. |
| cmSystemTools::ReplaceString( |
| command, "$(CMAKE_SOURCE_DIR)", |
| lg->ConvertToOutputFormat(lg->GetSourceDirectory(), |
| cmOutputConverter::SHELL)); |
| cmSystemTools::ReplaceString( |
| command, "$(CMAKE_BINARY_DIR)", |
| lg->ConvertToOutputFormat(lg->GetBinaryDirectory(), |
| cmOutputConverter::SHELL)); |
| cmSystemTools::ReplaceString(command, "$(ARGS)", ""); |
| |
| if (command.find('$') != std::string::npos) { |
| return; |
| } |
| |
| for (std::string const& util_output : util_outputs) { |
| gg->SeenCustomCommandOutput(util_output); |
| } |
| |
| gg->WriteCustomCommandBuild(command, desc, |
| "Utility command for " + this->GetTargetName(), |
| /*depfile*/ "", /*job_pool*/ "", uses_terminal, |
| /*restat*/ true, util_outputs, deps); |
| |
| phonyBuild.ExplicitDeps.push_back(utilCommandName); |
| gg->WriteBuild(this->GetBuildFileStream(), phonyBuild); |
| } |
| |
| // Find ADDITIONAL_CLEAN_FILES |
| this->AdditionalCleanFiles(); |
| |
| // Add an alias for the logical target name regardless of what directory |
| // contains it. Skip this for GLOBAL_TARGET because they are meant to |
| // be per-directory and have one at the top-level anyway. |
| if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) { |
| gg->AddTargetAlias(this->GetTargetName(), genTarget); |
| } |
| } |