diff options
-rw-r--r-- | Source/cmGlobalNinjaGenerator.cxx | 508 | ||||
-rw-r--r-- | Source/cmGlobalNinjaGenerator.h | 42 | ||||
-rw-r--r-- | Source/cmLocalNinjaGenerator.cxx | 32 | ||||
-rw-r--r-- | Source/cmNinjaNormalTargetGenerator.cxx | 243 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 274 | ||||
-rw-r--r-- | Source/cmNinjaTypes.h | 20 | ||||
-rw-r--r-- | Source/cmNinjaUtilityTargetGenerator.cxx | 134 |
7 files changed, 610 insertions, 643 deletions
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 3fce29e..2d52356 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -127,113 +127,107 @@ std::string cmGlobalNinjaGenerator::EncodePath(const std::string& path) return result; } -void cmGlobalNinjaGenerator::WriteBuild( - std::ostream& os, const std::string& comment, const std::string& rule, - const cmNinjaDeps& outputs, const cmNinjaDeps& implicitOuts, - const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps, - const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables, - const std::string& rspfile, int cmdLineLimit, bool* usedResponseFile) +void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, + cmNinjaBuild const& build, + int cmdLineLimit, + bool* usedResponseFile) { // Make sure there is a rule. - if (rule.empty()) { + if (build.Rule.empty()) { cmSystemTools::Error("No rule for WriteBuild! called with comment: " + - comment); + build.Comment); return; } // Make sure there is at least one output file. - if (outputs.empty()) { + if (build.Outputs.empty()) { cmSystemTools::Error( - "No output files for WriteBuild! called with comment: " + comment); + "No output files for WriteBuild! called with comment: " + build.Comment); return; } - cmGlobalNinjaGenerator::WriteComment(os, comment); - - std::string arguments; - - // TODO: Better formatting for when there are multiple input/output files. + cmGlobalNinjaGenerator::WriteComment(os, build.Comment); - // Write explicit dependencies. - for (std::string const& explicitDep : explicitDeps) { - arguments += " " + EncodePath(explicitDep); - } - - // Write implicit dependencies. - if (!implicitDeps.empty()) { - arguments += " |"; - for (std::string const& implicitDep : implicitDeps) { - arguments += " " + EncodePath(implicitDep); + // Write output files. + std::string buildStr("build"); + { + // Write explicit outputs + for (std::string const& output : build.Outputs) { + buildStr += " " + EncodePath(output); + if (this->ComputingUnknownDependencies) { + this->CombinedBuildOutputs.insert(output); + } } - } - - // Write order-only dependencies. - if (!orderOnlyDeps.empty()) { - arguments += " ||"; - for (std::string const& orderOnlyDep : orderOnlyDeps) { - arguments += " " + EncodePath(orderOnlyDep); + // Write implicit outputs + if (!build.ImplicitOuts.empty()) { + buildStr += " |"; + for (std::string const& implicitOut : build.ImplicitOuts) { + buildStr += " " + EncodePath(implicitOut); + } } + buildStr += ":"; + + // Write the rule. + buildStr += " "; + buildStr += build.Rule; } - arguments += "\n"; + std::string arguments; + { + // TODO: Better formatting for when there are multiple input/output files. - std::string build; + // Write explicit dependencies. + for (std::string const& explicitDep : build.ExplicitDeps) { + arguments += " " + EncodePath(explicitDep); + } - // Write outputs files. - build += "build"; - for (std::string const& output : outputs) { - build += " " + EncodePath(output); - if (this->ComputingUnknownDependencies) { - this->CombinedBuildOutputs.insert(output); + // Write implicit dependencies. + if (!build.ImplicitDeps.empty()) { + arguments += " |"; + for (std::string const& implicitDep : build.ImplicitDeps) { + arguments += " " + EncodePath(implicitDep); + } } - } - if (!implicitOuts.empty()) { - build += " |"; - for (std::string const& implicitOut : implicitOuts) { - build += " " + EncodePath(implicitOut); + + // Write order-only dependencies. + if (!build.OrderOnlyDeps.empty()) { + arguments += " ||"; + for (std::string const& orderOnlyDep : build.OrderOnlyDeps) { + arguments += " " + EncodePath(orderOnlyDep); + } } - } - build += ":"; - // Write the rule. - build += " " + rule; + arguments += "\n"; + } // Write the variables bound to this build statement. - std::ostringstream variable_assignments; - for (auto const& variable : variables) { - cmGlobalNinjaGenerator::WriteVariable(variable_assignments, variable.first, - variable.second, "", 1); - } + std::string assignments; + { + std::ostringstream variable_assignments; + for (auto const& variable : build.Variables) { + cmGlobalNinjaGenerator::WriteVariable( + variable_assignments, variable.first, variable.second, "", 1); + } - // check if a response file rule should be used - std::string buildstr = build; - std::string assignments = variable_assignments.str(); - bool useResponseFile = false; - if (cmdLineLimit < 0 || - (cmdLineLimit > 0 && - (arguments.size() + buildstr.size() + assignments.size() + 1000) > - static_cast<size_t>(cmdLineLimit))) { - variable_assignments.str(std::string()); - cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE", - rspfile, "", 1); - assignments += variable_assignments.str(); - useResponseFile = true; - } - if (usedResponseFile) { - *usedResponseFile = useResponseFile; + // check if a response file rule should be used + assignments = variable_assignments.str(); + bool useResponseFile = false; + if (cmdLineLimit < 0 || + (cmdLineLimit > 0 && + (arguments.size() + buildStr.size() + assignments.size() + 1000) > + static_cast<size_t>(cmdLineLimit))) { + variable_assignments.str(std::string()); + cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE", + build.RspFile, "", 1); + assignments += variable_assignments.str(); + useResponseFile = true; + } + if (usedResponseFile) { + *usedResponseFile = useResponseFile; + } } - os << buildstr << arguments << assignments; -} - -void cmGlobalNinjaGenerator::WritePhonyBuild( - std::ostream& os, const std::string& comment, const cmNinjaDeps& outputs, - const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps, - const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables) -{ - this->WriteBuild(os, comment, "phony", outputs, - /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, - orderOnlyDeps, variables); + os << buildStr << arguments << assignments << "\n"; } void cmGlobalNinjaGenerator::AddCustomCommandRule() @@ -249,40 +243,47 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( const std::string& command, const std::string& description, const std::string& comment, const std::string& depfile, const std::string& job_pool, bool uses_terminal, bool restat, - const cmNinjaDeps& outputs, const cmNinjaDeps& deps, - const cmNinjaDeps& orderOnly) + const cmNinjaDeps& outputs, const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& orderOnlyDeps) { - std::string cmd = command; // NOLINT(*) -#ifdef _WIN32 - if (cmd.empty()) - // TODO Shouldn't an empty command be handled by ninja? - cmd = "cmd.exe /c"; -#endif - this->AddCustomCommandRule(); - cmNinjaVars vars; - vars["COMMAND"] = cmd; - vars["DESC"] = EncodeLiteral(description); - if (restat) { - vars["restat"] = "1"; - } - if (uses_terminal && SupportsConsolePool()) { - vars["pool"] = "console"; - } else if (!job_pool.empty()) { - vars["pool"] = job_pool; - } - if (!depfile.empty()) { - vars["depfile"] = depfile; + { + cmNinjaBuild build("CUSTOM_COMMAND"); + build.Comment = comment; + build.Outputs = outputs; + build.ExplicitDeps = explicitDeps; + build.OrderOnlyDeps = orderOnlyDeps; + + cmNinjaVars& vars = build.Variables; + { + std::string cmd = command; // NOLINT(*) +#ifdef _WIN32 + if (cmd.empty()) + // TODO Shouldn't an empty command be handled by ninja? + cmd = "cmd.exe /c"; +#endif + vars["COMMAND"] = std::move(cmd); + } + vars["DESC"] = EncodeLiteral(description); + if (restat) { + vars["restat"] = "1"; + } + if (uses_terminal && SupportsConsolePool()) { + vars["pool"] = "console"; + } else if (!job_pool.empty()) { + vars["pool"] = job_pool; + } + if (!depfile.empty()) { + vars["depfile"] = depfile; + } + this->WriteBuild(*this->BuildFileStream, build); } - this->WriteBuild(*this->BuildFileStream, comment, "CUSTOM_COMMAND", outputs, - /*implicitOuts=*/cmNinjaDeps(), deps, cmNinjaDeps(), - orderOnly, vars); if (this->ComputingUnknownDependencies) { // we need to track every dependency that comes in, since we are trying // to find dependencies that are side effects of build commands - for (std::string const& dep : deps) { + for (std::string const& dep : explicitDeps) { this->CombinedCustomCommandExplicitDependencies.insert(dep); } } @@ -297,20 +298,16 @@ void cmGlobalNinjaGenerator::AddMacOSXContentRule() this->AddRule(rule); } -void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input, - const std::string& output) +void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(std::string input, + std::string output) { this->AddMacOSXContentRule(); - - cmNinjaDeps outputs; - outputs.push_back(output); - cmNinjaDeps deps; - deps.push_back(input); - cmNinjaVars vars; - - this->WriteBuild(*this->BuildFileStream, "", "COPY_OSX_CONTENT", outputs, - /*implicitOuts=*/cmNinjaDeps(), deps, cmNinjaDeps(), - cmNinjaDeps(), cmNinjaVars()); + { + cmNinjaBuild build("COPY_OSX_CONTENT"); + build.Outputs.push_back(std::move(output)); + build.ExplicitDeps.push_back(std::move(input)); + this->WriteBuild(*this->BuildFileStream, build); + } } void cmGlobalNinjaGenerator::WriteRule(std::ostream& os, @@ -1083,6 +1080,8 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) cmGlobalNinjaGenerator::WriteDivider(os); os << "# Target aliases.\n\n"; + cmNinjaBuild build("phony"); + build.Outputs.emplace_back(""); for (auto const& ta : TargetAliases) { // Don't write ambiguous aliases. if (!ta.second) { @@ -1095,10 +1094,13 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) continue; } - cmNinjaDeps deps; - this->AppendTargetOutputs(ta.second, deps); - - this->WritePhonyBuild(os, "", cmNinjaDeps(1, ta.first), deps); + // Outputs + build.Outputs[0] = ta.first; + // Explicit depdendencies + build.ExplicitDeps.clear(); + this->AppendTargetOutputs(ta.second, build.ExplicitDeps); + // Write + this->WriteBuild(os, build); } } @@ -1107,13 +1109,22 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) cmGlobalNinjaGenerator::WriteDivider(os); os << "# Folder targets.\n\n"; + std::string const& rootBinaryDir = + this->LocalGenerators[0]->GetBinaryDirectory(); + std::map<std::string, cmNinjaDeps> targetsPerFolder; for (cmLocalGenerator const* lg : this->LocalGenerators) { - const std::string currentBinaryFolder( + std::string const& currentBinaryFolder( lg->GetStateSnapshot().GetDirectory().GetCurrentBinary()); + + // Do not generate a rule for the root binary dir. + if (currentBinaryFolder == rootBinaryDir) { + continue; + } + // The directory-level rule should depend on the target-level rules // for all targets in the directory. - targetsPerFolder[currentBinaryFolder] = cmNinjaDeps(); + cmNinjaDeps& folderTargets = targetsPerFolder[currentBinaryFolder]; for (auto gt : lg->GetGeneratorTargets()) { cmStateEnums::TargetType const type = gt->GetType(); if ((type == cmStateEnums::EXECUTABLE || @@ -1123,37 +1134,34 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) type == cmStateEnums::OBJECT_LIBRARY || type == cmStateEnums::UTILITY) && !gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) { - targetsPerFolder[currentBinaryFolder].push_back(gt->GetName()); + folderTargets.push_back(gt->GetName()); } } // The directory-level rule should depend on the directory-level // rules of the subdirectories. for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) { - std::string const currentBinaryDir = + std::string const& currentBinaryDir = state.GetDirectory().GetCurrentBinary(); - - targetsPerFolder[currentBinaryFolder].push_back( + folderTargets.push_back( this->ConvertToNinjaPath(currentBinaryDir + "/all")); } } - std::string const rootBinaryDir = - this->LocalGenerators[0]->GetBinaryDirectory(); - for (auto const& it : targetsPerFolder) { - cmGlobalNinjaGenerator::WriteDivider(os); - std::string const& currentBinaryDir = it.first; + if (!targetsPerFolder.empty()) { + cmNinjaBuild build("phony"); + build.Outputs.emplace_back(""); + for (auto& it : targetsPerFolder) { + cmGlobalNinjaGenerator::WriteDivider(os); + std::string const& currentBinaryDir = it.first; - // Do not generate a rule for the root binary dir. - if (rootBinaryDir.length() >= currentBinaryDir.length()) { - continue; + // Setup target + build.Comment = "Folder: " + currentBinaryDir; + build.Outputs[0] = this->ConvertToNinjaPath(currentBinaryDir + "/all"); + build.ExplicitDeps = std::move(it.second); + // Write target + this->WriteBuild(os, build); } - - std::string const comment = "Folder: " + currentBinaryDir; - cmNinjaDeps output(1); - output.push_back(this->ConvertToNinjaPath(currentBinaryDir + "/all")); - - this->WritePhonyBuild(os, comment, output, it.second); } } @@ -1234,23 +1242,26 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os) knownDependencies.begin(), knownDependencies.end(), std::back_inserter(unknownExplicitDepends)); - std::string const rootBuildDirectory = - this->GetCMakeInstance()->GetHomeOutputDirectory(); - bool const inSourceBuild = - (rootBuildDirectory == this->GetCMakeInstance()->GetHomeDirectory()); std::vector<std::string> warnExplicitDepends; - for (std::string const& i : unknownExplicitDepends) { - // verify the file is in the build directory - std::string const absDepPath = - cmSystemTools::CollapseFullPath(i, rootBuildDirectory); - bool const inBuildDir = - cmSystemTools::IsSubDirectory(absDepPath, rootBuildDirectory); - if (inBuildDir) { - cmNinjaDeps deps(1, i); - this->WritePhonyBuild(os, "", deps, cmNinjaDeps()); - if (this->PolicyCMP0058 == cmPolicies::WARN && !inSourceBuild && - warnExplicitDepends.size() < 10) { - warnExplicitDepends.push_back(i); + if (!unknownExplicitDepends.empty()) { + cmake* cmk = this->GetCMakeInstance(); + std::string const& buildRoot = cmk->GetHomeOutputDirectory(); + bool const inSource = (buildRoot == cmk->GetHomeDirectory()); + bool const warn = (!inSource && (this->PolicyCMP0058 == cmPolicies::WARN)); + cmNinjaBuild build("phony"); + build.Outputs.emplace_back(""); + for (std::string const& ued : unknownExplicitDepends) { + // verify the file is in the build directory + std::string const absDepPath = + cmSystemTools::CollapseFullPath(ued, buildRoot); + if (cmSystemTools::IsSubDirectory(absDepPath, buildRoot)) { + // Generate phony build statement + build.Outputs[0] = ued; + this->WriteBuild(os, build); + // Add to warning on demand + if (warn && warnExplicitDepends.size() < 10) { + warnExplicitDepends.push_back(ued); + } } } } @@ -1291,14 +1302,14 @@ void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os) void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os) { - cmNinjaDeps outputs; - outputs.push_back(this->TargetAll); - - this->WritePhonyBuild(os, "The main all target.", outputs, - this->AllDependencies); + cmNinjaBuild build("phony"); + build.Comment = "The main all target."; + build.Outputs.push_back(this->TargetAll); + build.ExplicitDeps = this->AllDependencies; + this->WriteBuild(os, build); if (!this->HasOutputPathPrefix()) { - cmGlobalNinjaGenerator::WriteDefault(os, outputs, + cmGlobalNinjaGenerator::WriteDefault(os, build.Outputs, "Make the all target the default."); } } @@ -1325,20 +1336,21 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) WriteRule(*this->RulesFileStream, rule); } - cmNinjaDeps implicitDeps; - cmNinjaDeps explicitDeps; + cmNinjaBuild reBuild("RERUN_CMAKE"); + reBuild.Comment = "Re-run CMake if any of its inputs changed."; + reBuild.Outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE)); + for (cmLocalGenerator* localGen : this->LocalGenerators) { for (std::string const& fi : localGen->GetMakefile()->GetListFiles()) { - implicitDeps.push_back(this->ConvertToNinjaPath(fi)); + reBuild.ImplicitDeps.push_back(this->ConvertToNinjaPath(fi)); } } - implicitDeps.push_back(this->CMakeCacheFile); + reBuild.ImplicitDeps.push_back(this->CMakeCacheFile); - cmNinjaVars variables; // Use 'console' pool to get non buffered output of the CMake re-run call // Available since Ninja 1.5 if (SupportsConsolePool()) { - variables["pool"] = "console"; + reBuild.Variables["pool"] = "console"; } cmake* cm = this->GetCMakeInstance(); @@ -1355,29 +1367,28 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) this->WriteRule(*this->RulesFileStream, rule); } - std::string verifyForce = cm->GetGlobVerifyScript() + "_force"; - cmNinjaDeps verifyForceDeps(1, this->NinjaOutputPath(verifyForce)); - - this->WritePhonyBuild(os, "Phony target to force glob verification run.", - verifyForceDeps, cmNinjaDeps()); + cmNinjaBuild phonyBuild("phony"); + phonyBuild.Comment = "Phony target to force glob verification run."; + phonyBuild.Outputs.push_back(cm->GetGlobVerifyScript() + "_force"); + this->WriteBuild(os, phonyBuild); - variables["restat"] = "1"; + reBuild.Variables["restat"] = "1"; std::string const verifyScriptFile = this->NinjaOutputPath(cm->GetGlobVerifyScript()); std::string const verifyStampFile = this->NinjaOutputPath(cm->GetGlobVerifyStamp()); - this->WriteBuild(os, - "Re-run CMake to check if globbed directories changed.", - "VERIFY_GLOBS", - /*outputs=*/cmNinjaDeps(1, verifyStampFile), - /*implicitOuts=*/cmNinjaDeps(), - /*explicitDeps=*/cmNinjaDeps(), - /*implicitDeps=*/verifyForceDeps, - /*orderOnlyDeps=*/cmNinjaDeps(), variables); - - variables.erase("restat"); - implicitDeps.push_back(verifyScriptFile); - explicitDeps.push_back(verifyStampFile); + { + cmNinjaBuild vgBuild("VERIFY_GLOBS"); + vgBuild.Comment = + "Re-run CMake to check if globbed directories changed."; + vgBuild.Outputs.push_back(verifyStampFile); + vgBuild.ImplicitDeps = phonyBuild.Outputs; + vgBuild.Variables = reBuild.Variables; + this->WriteBuild(os, vgBuild); + } + reBuild.Variables.erase("restat"); + reBuild.ImplicitDeps.push_back(verifyScriptFile); + reBuild.ExplicitDeps.push_back(verifyStampFile); } else if (!this->SupportsManifestRestat() && cm->DoWriteGlobVerifyTarget()) { std::ostringstream msg; @@ -1395,25 +1406,23 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) msg.str()); } - std::sort(implicitDeps.begin(), implicitDeps.end()); - implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()), - implicitDeps.end()); - - std::string const ninjaBuildFile = this->NinjaOutputPath(NINJA_BUILD_FILE); - this->WriteBuild(os, "Re-run CMake if any of its inputs changed.", - "RERUN_CMAKE", - /*outputs=*/cmNinjaDeps(1, ninjaBuildFile), - /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, - /*orderOnlyDeps=*/cmNinjaDeps(), variables); + std::sort(reBuild.ImplicitDeps.begin(), reBuild.ImplicitDeps.end()); + reBuild.ImplicitDeps.erase( + std::unique(reBuild.ImplicitDeps.begin(), reBuild.ImplicitDeps.end()), + reBuild.ImplicitDeps.end()); - cmNinjaDeps missingInputs; - std::set_difference(std::make_move_iterator(implicitDeps.begin()), - std::make_move_iterator(implicitDeps.end()), - CustomCommandOutputs.begin(), CustomCommandOutputs.end(), - std::back_inserter(missingInputs)); + this->WriteBuild(os, reBuild); - this->WritePhonyBuild(os, "A missing CMake input file is not an error.", - missingInputs, cmNinjaDeps()); + { + cmNinjaBuild build("phony"); + build.Comment = "A missing CMake input file is not an error."; + std::set_difference(std::make_move_iterator(reBuild.ImplicitDeps.begin()), + std::make_move_iterator(reBuild.ImplicitDeps.end()), + CustomCommandOutputs.begin(), + CustomCommandOutputs.end(), + std::back_inserter(build.Outputs)); + this->WriteBuild(os, build); + } } std::string cmGlobalNinjaGenerator::CMakeCmd() const @@ -1500,16 +1509,11 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) // Write build { - cmNinjaDeps outputs; - outputs.emplace_back( + cmNinjaBuild build("CLEAN_ADDITIONAL"); + build.Comment = "Clean additional files."; + build.Outputs.push_back( this->NinjaOutputPath(this->GetAdditionalCleanTargetName())); - WriteBuild(os, "Clean additional files.", "CLEAN_ADDITIONAL", - /*outputs=*/outputs, - /*implicitOuts=*/cmNinjaDeps(), - /*explicitDeps=*/cmNinjaDeps(), - /*implicitDeps=*/cmNinjaDeps(), - /*orderOnlyDeps=*/cmNinjaDeps(), - /*variables=*/cmNinjaVars()); + WriteBuild(os, build); } // Return success return true; @@ -1532,20 +1536,14 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) // Write build { - cmNinjaDeps explicitDeps; + cmNinjaBuild build("CLEAN"); + build.Comment = "Clean all the built files."; + build.Outputs.push_back(this->NinjaOutputPath(this->GetCleanTargetName())); if (additionalFiles) { - explicitDeps.emplace_back( + build.ExplicitDeps.push_back( this->NinjaOutputPath(this->GetAdditionalCleanTargetName())); } - cmNinjaDeps outputs; - outputs.emplace_back(this->NinjaOutputPath(this->GetCleanTargetName())); - WriteBuild(os, "Clean all the built files.", "CLEAN", - /*outputs=*/outputs, - /*implicitOuts=*/cmNinjaDeps(), - /*explicitDeps=*/explicitDeps, - /*implicitDeps=*/cmNinjaDeps(), - /*orderOnlyDeps=*/cmNinjaDeps(), - /*variables=*/cmNinjaVars()); + WriteBuild(os, build); } } @@ -1558,13 +1556,12 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os) rule.Comment = "Rule for printing all primary targets available."; WriteRule(*this->RulesFileStream, rule); } - WriteBuild(os, "Print all primary targets available.", "HELP", - /*outputs=*/cmNinjaDeps(1, this->NinjaOutputPath("help")), - /*implicitOuts=*/cmNinjaDeps(), - /*explicitDeps=*/cmNinjaDeps(), - /*implicitDeps=*/cmNinjaDeps(), - /*orderOnlyDeps=*/cmNinjaDeps(), - /*variables=*/cmNinjaVars()); + { + cmNinjaBuild build("HELP"); + build.Comment = "Print all primary targets available."; + build.Outputs.push_back(this->NinjaOutputPath("help")); + WriteBuild(os, build); + } } void cmGlobalNinjaGenerator::InitOutputPathPrefix() @@ -1937,32 +1934,29 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( cmGeneratedFileStream ddf(arg_dd); ddf << "ninja_dyndep_version = 1.0\n"; - for (cmDyndepObjectInfo const& object : objects) { - std::string const ddComment; - std::string const ddRule = "dyndep"; - cmNinjaDeps ddOutputs; - cmNinjaDeps ddImplicitOuts; - cmNinjaDeps ddExplicitDeps; - cmNinjaDeps ddImplicitDeps; - cmNinjaDeps ddOrderOnlyDeps; - cmNinjaVars ddVars; - - ddOutputs.push_back(object.Object); - for (std::string const& p : object.Provides) { - ddImplicitOuts.push_back(this->ConvertToNinjaPath(mod_files[p])); - } - for (std::string const& r : object.Requires) { - std::map<std::string, std::string>::iterator m = mod_files.find(r); - if (m != mod_files.end()) { - ddImplicitDeps.push_back(this->ConvertToNinjaPath(m->second)); + { + cmNinjaBuild build("dyndep"); + build.Outputs.emplace_back(""); + for (cmDyndepObjectInfo const& object : objects) { + build.Outputs[0] = object.Object; + build.ImplicitOuts.clear(); + for (std::string const& p : object.Provides) { + build.ImplicitOuts.push_back(this->ConvertToNinjaPath(mod_files[p])); + } + build.ImplicitDeps.clear(); + for (std::string const& r : object.Requires) { + auto mit = mod_files.find(r); + if (mit != mod_files.end()) { + build.ImplicitDeps.push_back(this->ConvertToNinjaPath(mit->second)); + } + } + build.Variables.clear(); + if (!object.Provides.empty()) { + build.Variables.emplace("restat", "1"); } - } - if (!object.Provides.empty()) { - ddVars["restat"] = "1"; - } - this->WriteBuild(ddf, ddComment, ddRule, ddOutputs, ddImplicitOuts, - ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars); + this->WriteBuild(ddf, build); + } } // Store the map of modules provided by this target in a file for diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index dcc358b..15dd404 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -101,41 +101,21 @@ public: bool IsIPOSupported() const override { return true; } /** - * Write a build statement to @a os with the @a comment using - * the @a rule the list of @a outputs files and inputs. - * It also writes the variables bound to this build statement. + * Write a build statement @a build to @a os. * @warning no escaping of any kind is done here. */ - void WriteBuild(std::ostream& os, const std::string& comment, - const std::string& rule, const cmNinjaDeps& outputs, - const cmNinjaDeps& implicitOuts, - const cmNinjaDeps& explicitDeps, - const cmNinjaDeps& implicitDeps, - const cmNinjaDeps& orderOnlyDeps, - const cmNinjaVars& variables, - const std::string& rspfile = std::string(), + void WriteBuild(std::ostream& os, cmNinjaBuild const& build, int cmdLineLimit = 0, bool* usedResponseFile = nullptr); - /** - * Helper to write a build statement with the special 'phony' rule. - */ - void WritePhonyBuild(std::ostream& os, const std::string& comment, - const cmNinjaDeps& outputs, - const cmNinjaDeps& explicitDeps, - const cmNinjaDeps& implicitDeps = cmNinjaDeps(), - const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(), - const cmNinjaVars& variables = cmNinjaVars()); - - void WriteCustomCommandBuild(const std::string& command, - const std::string& description, - const std::string& comment, - const std::string& depfile, - const std::string& pool, bool uses_terminal, - bool restat, const cmNinjaDeps& outputs, - const cmNinjaDeps& deps = cmNinjaDeps(), - const cmNinjaDeps& orderOnly = cmNinjaDeps()); - void WriteMacOSXContentBuild(const std::string& input, - const std::string& output); + void WriteCustomCommandBuild( + const std::string& command, const std::string& description, + const std::string& comment, const std::string& depfile, + const std::string& pool, bool uses_terminal, bool restat, + const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps = cmNinjaDeps(), + const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps()); + + void WriteMacOSXContentBuild(std::string input, std::string output); /** * Write a rule statement to @a os. diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 9b651a4..81cafa3 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -454,7 +454,8 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines( void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps) { - if (this->GetGlobalNinjaGenerator()->SeenCustomCommand(cc)) { + cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator(); + if (gg->SeenCustomCommand(cc)) { return; } @@ -462,13 +463,12 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( const std::vector<std::string>& outputs = ccg.GetOutputs(); const std::vector<std::string>& byproducts = ccg.GetByproducts(); - cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size()), ninjaDeps; bool symbolic = false; for (std::string const& output : outputs) { if (cmSourceFile* sf = this->Makefile->GetSource(output)) { - symbolic = sf->GetPropertyAsBool("SYMBOLIC"); - if (symbolic) { + if (sf->GetPropertyAsBool("SYMBOLIC")) { + symbolic = true; break; } } @@ -479,25 +479,29 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( file of each imported target that has an add_dependencies pointing \ at us. How to know which ExternalProject step actually provides it? #endif + cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size()); std::transform(outputs.begin(), outputs.end(), ninjaOutputs.begin(), - this->GetGlobalNinjaGenerator()->MapToNinjaPath()); + gg->MapToNinjaPath()); std::transform(byproducts.begin(), byproducts.end(), - ninjaOutputs.begin() + outputs.size(), - this->GetGlobalNinjaGenerator()->MapToNinjaPath()); - this->AppendCustomCommandDeps(ccg, ninjaDeps); + ninjaOutputs.begin() + outputs.size(), gg->MapToNinjaPath()); for (std::string const& ninjaOutput : ninjaOutputs) { - this->GetGlobalNinjaGenerator()->SeenCustomCommandOutput(ninjaOutput); + gg->SeenCustomCommandOutput(ninjaOutput); } + cmNinjaDeps ninjaDeps; + this->AppendCustomCommandDeps(ccg, ninjaDeps); + std::vector<std::string> cmdLines; this->AppendCustomCommandLines(ccg, cmdLines); if (cmdLines.empty()) { - this->GetGlobalNinjaGenerator()->WritePhonyBuild( - this->GetBuildFileStream(), - "Phony custom command for " + ninjaOutputs[0], ninjaOutputs, ninjaDeps, - cmNinjaDeps(), orderOnlyDeps, cmNinjaVars()); + cmNinjaBuild build("phony"); + build.Comment = "Phony custom command for " + ninjaOutputs[0]; + build.Outputs = std::move(ninjaOutputs); + build.ExplicitDeps = std::move(ninjaDeps); + build.OrderOnlyDeps = orderOnlyDeps; + gg->WriteBuild(this->GetBuildFileStream(), build); } else { std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]); // Hash full path to make unique. @@ -505,7 +509,7 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( cmCryptoHash hash(cmCryptoHash::AlgoSHA256); customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7); - this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild( + gg->WriteCustomCommandBuild( this->BuildCommandLine(cmdLines, customStep), this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0], cc->GetDepfile(), cc->GetJobPool(), cc->GetUsesTerminal(), diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 6e9e112..1399ee2 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -554,11 +554,12 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd() void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() { - if (!this->GetGlobalGenerator()->GetLanguageEnabled("CUDA")) { + cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator(); + if (!globalGen->GetLanguageEnabled("CUDA")) { return; } - cmGeneratorTarget& genTarget = *this->GetGeneratorTarget(); + cmGeneratorTarget* genTarget = this->GetGeneratorTarget(); bool requiresDeviceLinking = requireDeviceLinking( *this->GeneratorTarget, *this->GetLocalGenerator(), this->ConfigName); @@ -576,39 +577,39 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() std::string const cfgName = this->GetConfigName(); std::string const targetOutputReal = ConvertToNinjaPath( - genTarget.ObjectDirectory + "cmake_device_link" + objExt); + genTarget->ObjectDirectory + "cmake_device_link" + objExt); std::string const targetOutputImplib = ConvertToNinjaPath( - genTarget.GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact)); + genTarget->GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact)); this->DeviceLinkObject = targetOutputReal; // Write comments. cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); - const cmStateEnums::TargetType targetType = genTarget.GetType(); + const cmStateEnums::TargetType targetType = genTarget->GetType(); this->GetBuildFileStream() << "# Device Link build statements for " << cmState::GetTargetTypeName(targetType) << " target " << this->GetTargetName() << "\n\n"; // Compute the comment. - std::ostringstream comment; - comment << "Link the " << this->GetVisibleTypeName() << " " - << targetOutputReal; + cmNinjaBuild build(this->LanguageLinkerDeviceRule()); + build.Comment = "Link the "; + build.Comment += this->GetVisibleTypeName(); + build.Comment += " "; + build.Comment += targetOutputReal; - cmNinjaDeps emptyDeps; - cmNinjaVars vars; + cmNinjaVars& vars = build.Variables; // Compute outputs. - cmNinjaDeps outputs; - outputs.push_back(targetOutputReal); + build.Outputs.push_back(targetOutputReal); // Compute specific libraries to link with. - cmNinjaDeps explicitDeps = this->GetObjects(); - cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage); + build.ExplicitDeps = this->GetObjects(); + build.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage); std::string frameworkPath; std::string linkPath; - std::string createRule = genTarget.GetCreateRuleVariable( + std::string createRule = genTarget->GetCreateRuleVariable( this->TargetLinkLanguage, this->GetConfigName()); const bool useWatcomQuote = this->GetMakefile()->IsOn(createRule + "_USE_WATCOM_QUOTE"); @@ -621,14 +622,14 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() new cmNinjaLinkLineDeviceComputer( this->GetLocalGenerator(), this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(), - this->GetGlobalGenerator())); + globalGen)); linkLineComputer->SetUseWatcomQuote(useWatcomQuote); localGen.GetTargetFlags( linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"], - vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, &genTarget); + vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, genTarget); - this->addPoolNinjaVariable("JOB_POOL_LINK", &genTarget, vars); + this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars); vars["LINK_FLAGS"] = cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]); @@ -642,18 +643,18 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() // code between the Makefile executable and library generators. if (targetType == cmStateEnums::EXECUTABLE) { std::string t = vars["FLAGS"]; - localGen.AddArchitectureFlags(t, &genTarget, cudaLinkLanguage, cfgName); + localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, cfgName); vars["FLAGS"] = t; } else { std::string t = vars["ARCH_FLAGS"]; - localGen.AddArchitectureFlags(t, &genTarget, cudaLinkLanguage, cfgName); + localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, cfgName); vars["ARCH_FLAGS"] = t; t.clear(); - localGen.AddLanguageFlagsForLinking(t, &genTarget, cudaLinkLanguage, + localGen.AddLanguageFlagsForLinking(t, genTarget, cudaLinkLanguage, cfgName); vars["LANGUAGE_COMPILE_FLAGS"] = t; } - if (this->GetGeneratorTarget()->HasSOName(cfgName)) { + if (genTarget->HasSOName(cfgName)) { vars["SONAME_FLAG"] = this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage); vars["SONAME"] = this->TargetNames.SharedObject; @@ -681,7 +682,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() this->SetMsvcTargetPdbVariable(vars); - if (this->GetGlobalGenerator()->IsGCCOnWindows()) { + if (globalGen->IsGCCOnWindows()) { // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) std::string& linkLibraries = vars["LINK_LIBRARIES"]; std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/'); @@ -689,46 +690,43 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() std::replace(link_path.begin(), link_path.end(), '\\', '/'); } - cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator(); - // Device linking currently doesn't support response files so // do not check if the user has explicitly forced a response file. int const commandLineLengthLimit = static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) - - globalGen.GetRuleCmdLength(this->LanguageLinkerDeviceRule()); + globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule()); - const std::string rspfile = this->ConvertToNinjaPath( - std::string("CMakeFiles/") + genTarget.GetName() + ".rsp"); + build.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") + + genTarget->GetName() + ".rsp"); // Gather order-only dependencies. - cmNinjaDeps orderOnlyDeps; this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(), - orderOnlyDeps); + build.OrderOnlyDeps); // Write the build statement for this target. bool usedResponseFile = false; - globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(), - this->LanguageLinkerDeviceRule(), outputs, - /*implicitOuts=*/cmNinjaDeps(), explicitDeps, - implicitDeps, orderOnlyDeps, vars, rspfile, - commandLineLengthLimit, &usedResponseFile); + globalGen->WriteBuild(this->GetBuildFileStream(), build, + commandLineLengthLimit, &usedResponseFile); this->WriteDeviceLinkRule(false); } void cmNinjaNormalTargetGenerator::WriteLinkStatement() { - cmGeneratorTarget& gt = *this->GetGeneratorTarget(); + cmMakefile* mf = this->GetMakefile(); + cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator(); + cmGeneratorTarget* gt = this->GetGeneratorTarget(); + const std::string cfgName = this->GetConfigName(); - std::string targetOutput = ConvertToNinjaPath(gt.GetFullPath(cfgName)); + std::string targetOutput = ConvertToNinjaPath(gt->GetFullPath(cfgName)); std::string targetOutputReal = ConvertToNinjaPath( - gt.GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact, - /*realname=*/true)); + gt->GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact, + /*realname=*/true)); std::string targetOutputImplib = ConvertToNinjaPath( - gt.GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact)); + gt->GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact)); - if (gt.IsAppBundleOnApple()) { + if (gt->IsAppBundleOnApple()) { // Create the app bundle - std::string outpath = gt.GetDirectory(cfgName); + std::string outpath = gt->GetDirectory(cfgName); this->OSXBundleGenerator->CreateAppBundle(this->TargetNames.Output, outpath); @@ -741,34 +739,34 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() targetOutputReal += "/"; targetOutputReal += this->TargetNames.Real; targetOutputReal = this->ConvertToNinjaPath(targetOutputReal); - } else if (gt.IsFrameworkOnApple()) { + } else if (gt->IsFrameworkOnApple()) { // Create the library framework. this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output, - gt.GetDirectory(cfgName)); - } else if (gt.IsCFBundleOnApple()) { + gt->GetDirectory(cfgName)); + } else if (gt->IsCFBundleOnApple()) { // Create the core foundation bundle. this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output, - gt.GetDirectory(cfgName)); + gt->GetDirectory(cfgName)); } // Write comments. cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); - const cmStateEnums::TargetType targetType = gt.GetType(); + const cmStateEnums::TargetType targetType = gt->GetType(); this->GetBuildFileStream() << "# Link build statements for " << cmState::GetTargetTypeName(targetType) << " target " << this->GetTargetName() << "\n\n"; - cmNinjaDeps emptyDeps; - cmNinjaVars vars; + cmNinjaBuild linkBuild(this->LanguageLinkerRule()); + cmNinjaVars& vars = linkBuild.Variables; // Compute the comment. - std::ostringstream comment; - comment << "Link the " << this->GetVisibleTypeName() << " " - << targetOutputReal; + linkBuild.Comment = "Link the "; + linkBuild.Comment += this->GetVisibleTypeName(); + linkBuild.Comment += " "; + linkBuild.Comment += targetOutputReal; // Compute outputs. - cmNinjaDeps outputs; - outputs.push_back(targetOutputReal); + linkBuild.Outputs.push_back(targetOutputReal); if (this->TargetLinkLanguage == "Swift") { vars["SWIFT_LIBRARY_NAME"] = [this]() -> std::string { @@ -777,12 +775,11 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() return targetNames.Base; }(); - vars["SWIFT_MODULE_NAME"] = [this]() -> std::string { - if (const char* name = - this->GetGeneratorTarget()->GetProperty("Swift_MODULE_NAME")) { + vars["SWIFT_MODULE_NAME"] = [gt]() -> std::string { + if (const char* name = gt->GetProperty("Swift_MODULE_NAME")) { return name; } - return this->GetGeneratorTarget()->GetName(); + return gt->GetName(); }(); vars["SWIFT_MODULE"] = [this](const std::string& module) -> std::string { @@ -806,7 +803,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() vars["SWIFT_OUTPUT_FILE_MAP"] = this->GetLocalGenerator()->ConvertToOutputFormat( - this->ConvertToNinjaPath(gt.GetSupportDirectory() + + this->ConvertToNinjaPath(gt->GetSupportDirectory() + "/output-file-map.json"), cmOutputConverter::SHELL); @@ -835,35 +832,31 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() } // Compute specific libraries to link with. - cmNinjaDeps explicitDeps; if (this->TargetLinkLanguage == "Swift") { std::vector<cmSourceFile const*> sources; - this->GetGeneratorTarget()->GetObjectSources(sources, - this->GetConfigName()); + gt->GetObjectSources(sources, this->GetConfigName()); for (const auto& source : sources) { - outputs.push_back( + linkBuild.Outputs.push_back( this->ConvertToNinjaPath(this->GetObjectFilePath(source))); - explicitDeps.push_back( + linkBuild.ExplicitDeps.push_back( this->ConvertToNinjaPath(this->GetSourceFilePath(source))); } - outputs.push_back(vars["SWIFT_MODULE"]); + linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]); } else { - explicitDeps = this->GetObjects(); + linkBuild.ExplicitDeps = this->GetObjects(); } - cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage); + linkBuild.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage); if (!this->DeviceLinkObject.empty()) { - explicitDeps.push_back(this->DeviceLinkObject); + linkBuild.ExplicitDeps.push_back(this->DeviceLinkObject); } - cmMakefile* mf = this->GetMakefile(); - std::string frameworkPath; std::string linkPath; std::string createRule = - gt.GetCreateRuleVariable(this->TargetLinkLanguage, this->GetConfigName()); + gt->GetCreateRuleVariable(this->TargetLinkLanguage, this->GetConfigName()); bool useWatcomQuote = mf->IsOn(createRule + "_USE_WATCOM_QUOTE"); cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator(); @@ -871,14 +864,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL); std::unique_ptr<cmLinkLineComputer> linkLineComputer( - this->GetGlobalGenerator()->CreateLinkLineComputer( + globalGen->CreateLinkLineComputer( this->GetLocalGenerator(), this->GetLocalGenerator()->GetStateSnapshot().GetDirectory())); linkLineComputer->SetUseWatcomQuote(useWatcomQuote); localGen.GetTargetFlags(linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"], vars["FLAGS"], - vars["LINK_FLAGS"], frameworkPath, linkPath, >); + vars["LINK_FLAGS"], frameworkPath, linkPath, gt); // Add OS X version flags, if any. if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY || @@ -889,7 +882,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() "CURRENT", false); } - this->addPoolNinjaVariable("JOB_POOL_LINK", >, vars); + this->addPoolNinjaVariable("JOB_POOL_LINK", gt, vars); this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"]); vars["LINK_FLAGS"] = @@ -899,7 +892,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() vars["LINK_PATH"] = frameworkPath + linkPath; std::string lwyuFlags; - if (gt.GetPropertyAsBool("LINK_WHAT_YOU_USE")) { + if (gt->GetPropertyAsBool("LINK_WHAT_YOU_USE")) { lwyuFlags = " -Wl,--no-as-needed"; } @@ -908,24 +901,23 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // code between the Makefile executable and library generators. if (targetType == cmStateEnums::EXECUTABLE) { std::string t = vars["FLAGS"]; - localGen.AddArchitectureFlags(t, >, TargetLinkLanguage, cfgName); + localGen.AddArchitectureFlags(t, gt, TargetLinkLanguage, cfgName); t += lwyuFlags; vars["FLAGS"] = t; } else { std::string t = vars["ARCH_FLAGS"]; - localGen.AddArchitectureFlags(t, >, TargetLinkLanguage, cfgName); + localGen.AddArchitectureFlags(t, gt, TargetLinkLanguage, cfgName); vars["ARCH_FLAGS"] = t; t.clear(); t += lwyuFlags; - localGen.AddLanguageFlagsForLinking(t, >, TargetLinkLanguage, cfgName); + localGen.AddLanguageFlagsForLinking(t, gt, TargetLinkLanguage, cfgName); vars["LANGUAGE_COMPILE_FLAGS"] = t; } - if (this->GetGeneratorTarget()->HasSOName(cfgName)) { + if (gt->HasSOName(cfgName)) { vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage); vars["SONAME"] = this->TargetNames.SharedObject; if (targetType == cmStateEnums::SHARED_LIBRARY) { - std::string install_dir = - this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName); + std::string install_dir = gt->GetInstallNameDirForBuildTree(cfgName); if (!install_dir.empty()) { vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat( install_dir, cmOutputConverter::SHELL); @@ -940,7 +932,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() targetOutputImplib, cmOutputConverter::SHELL); vars["TARGET_IMPLIB"] = impLibPath; EnsureParentDirectoryExists(impLibPath); - if (gt.HasImportLibrary(cfgName)) { + if (gt->HasImportLibrary(cfgName)) { byproducts.push_back(targetOutputImplib); } } @@ -951,7 +943,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string prefix; std::string base; std::string suffix; - this->GetGeneratorTarget()->GetFullNameComponents(prefix, base, suffix); + gt->GetFullNameComponents(prefix, base, suffix); std::string dbg_suffix = ".dbg"; // TODO: Where to document? if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) { @@ -960,12 +952,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() vars["TARGET_PDB"] = base + suffix + dbg_suffix; } - const std::string objPath = GetGeneratorTarget()->GetSupportDirectory(); + const std::string objPath = gt->GetSupportDirectory(); vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat( this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL); EnsureDirectoryExists(objPath); - if (this->GetGlobalGenerator()->IsGCCOnWindows()) { + if (globalGen->IsGCCOnWindows()) { // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) std::string& linkLibraries = vars["LINK_LIBRARIES"]; std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/'); @@ -974,8 +966,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() } const std::vector<cmCustomCommand>* cmdLists[3] = { - >.GetPreBuildCommands(), >.GetPreLinkCommands(), - >.GetPostBuildCommands() + >->GetPreBuildCommands(), >->GetPreLinkCommands(), + >->GetPostBuildCommands() }; std::vector<std::string> preLinkCmdLines, postBuildCmdLines; @@ -995,7 +987,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // maybe create .def file from list of objects cmGeneratorTarget::ModuleDefinitionInfo const* mdi = - gt.GetModuleDefinitionInfo(this->GetConfigName()); + gt->GetModuleDefinitionInfo(this->GetConfigName()); if (mdi && mdi->DefFileGenerated) { std::string cmakeCommand = this->GetLocalGenerator()->ConvertToOutputFormat( @@ -1027,8 +1019,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() } } // If we have any PRE_LINK commands, we need to go back to CMAKE_BINARY_DIR - // for - // the link commands. + // for the link commands. if (!preLinkCmdLines.empty()) { const std::string homeOutDir = localGen.ConvertToOutputFormat( localGen.GetBinaryDirectory(), cmOutputConverter::SHELL); @@ -1042,14 +1033,13 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() cmNinjaVars symlinkVars; bool const symlinkNeeded = - (targetOutput != targetOutputReal && !gt.IsFrameworkOnApple()); + (targetOutput != targetOutputReal && !gt->IsFrameworkOnApple()); if (!symlinkNeeded) { vars["POST_BUILD"] = postBuildCmdLine; } else { vars["POST_BUILD"] = cmGlobalNinjaGenerator::SHELL_NOOP; symlinkVars["POST_BUILD"] = postBuildCmdLine; } - cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator(); bool const lang_supports_response = !(this->TargetLinkLanguage == "RC" || this->TargetLinkLanguage == "CUDA"); @@ -1057,44 +1047,41 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() if (!lang_supports_response || !this->ForceResponseFile()) { commandLineLengthLimit = static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) - - globalGen.GetRuleCmdLength(this->LanguageLinkerRule()); + globalGen->GetRuleCmdLength(linkBuild.Rule); } - const std::string rspfile = this->ConvertToNinjaPath( - std::string("CMakeFiles/") + gt.GetName() + ".rsp"); + linkBuild.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") + + gt->GetName() + ".rsp"); // Gather order-only dependencies. - cmNinjaDeps orderOnlyDeps; - this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(), - orderOnlyDeps); + this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps); // Ninja should restat after linking if and only if there are byproducts. vars["RESTAT"] = byproducts.empty() ? "" : "1"; for (std::string const& o : byproducts) { - this->GetGlobalGenerator()->SeenCustomCommandOutput(o); - outputs.push_back(o); + globalGen->SeenCustomCommandOutput(o); + linkBuild.Outputs.push_back(o); } // Write the build statement for this target. bool usedResponseFile = false; - globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(), - this->LanguageLinkerRule(), outputs, - /*implicitOuts=*/cmNinjaDeps(), explicitDeps, - implicitDeps, orderOnlyDeps, vars, rspfile, - commandLineLengthLimit, &usedResponseFile); + globalGen->WriteBuild(this->GetBuildFileStream(), linkBuild, + commandLineLengthLimit, &usedResponseFile); this->WriteLinkRule(usedResponseFile); if (symlinkNeeded) { if (targetType == cmStateEnums::EXECUTABLE) { - globalGen.WriteBuild( - this->GetBuildFileStream(), - "Create executable symlink " + targetOutput, - "CMAKE_SYMLINK_EXECUTABLE", cmNinjaDeps(1, targetOutput), - /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal), - emptyDeps, emptyDeps, symlinkVars); + cmNinjaBuild build("CMAKE_SYMLINK_EXECUTABLE"); + build.Comment = "Create executable symlink " + targetOutput; + build.Outputs.push_back(targetOutput); + build.ExplicitDeps.push_back(targetOutputReal); + build.Variables = std::move(symlinkVars); + globalGen->WriteBuild(this->GetBuildFileStream(), build); } else { - cmNinjaDeps symlinks; + cmNinjaBuild build("CMAKE_SYMLINK_LIBRARY"); + build.Comment = "Create library symlink " + targetOutput; + std::string const soName = this->ConvertToNinjaPath( this->GetTargetFilePath(this->TargetNames.SharedObject)); // If one link has to be created. @@ -1104,32 +1091,32 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() soName, cmOutputConverter::SHELL); } else { symlinkVars["SONAME"].clear(); - symlinks.push_back(soName); + build.Outputs.push_back(soName); } - symlinks.push_back(targetOutput); - globalGen.WriteBuild( - this->GetBuildFileStream(), "Create library symlink " + targetOutput, - "CMAKE_SYMLINK_LIBRARY", symlinks, - /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal), - emptyDeps, emptyDeps, symlinkVars); + build.Outputs.push_back(targetOutput); + build.ExplicitDeps.push_back(targetOutputReal); + build.Variables = std::move(symlinkVars); + + globalGen->WriteBuild(this->GetBuildFileStream(), build); } } // Add aliases for the file name and the target name. - globalGen.AddTargetAlias(this->TargetNames.Output, >); - globalGen.AddTargetAlias(this->GetTargetName(), >); + globalGen->AddTargetAlias(this->TargetNames.Output, gt); + globalGen->AddTargetAlias(this->GetTargetName(), gt); } void cmNinjaNormalTargetGenerator::WriteObjectLibStatement() { // Write a phony output that depends on all object files. - cmNinjaDeps outputs; - this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(), - outputs); - cmNinjaDeps depends = this->GetObjects(); - this->GetGlobalGenerator()->WritePhonyBuild( - this->GetBuildFileStream(), "Object library " + this->GetTargetName(), - outputs, depends); + { + cmNinjaBuild build("phony"); + build.Comment = "Object library " + this->GetTargetName(); + this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(), + build.Outputs); + build.ExplicitDeps = this->GetObjects(); + this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build); + } // Add aliases for the target name. this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 5b8ed90..4c93cf1 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -796,97 +796,102 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements() const std::string& config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); - std::vector<cmSourceFile const*> customCommands; - this->GeneratorTarget->GetCustomCommands(customCommands, config); - for (cmSourceFile const* sf : customCommands) { - cmCustomCommand const* cc = sf->GetCustomCommand(); - this->GetLocalGenerator()->AddCustomCommandTarget( - cc, this->GetGeneratorTarget()); - // Record the custom commands for this target. The container is used - // in WriteObjectBuildStatement when called in a loop below. - this->CustomCommands.push_back(cc); + { + std::vector<cmSourceFile const*> customCommands; + this->GeneratorTarget->GetCustomCommands(customCommands, config); + for (cmSourceFile const* sf : customCommands) { + cmCustomCommand const* cc = sf->GetCustomCommand(); + this->GetLocalGenerator()->AddCustomCommandTarget( + cc, this->GetGeneratorTarget()); + // Record the custom commands for this target. The container is used + // in WriteObjectBuildStatement when called in a loop below. + this->CustomCommands.push_back(cc); + } } - std::vector<cmSourceFile const*> headerSources; - this->GeneratorTarget->GetHeaderSources(headerSources, config); - this->OSXBundleGenerator->GenerateMacOSXContentStatements( - headerSources, this->MacOSXContentGenerator.get()); - std::vector<cmSourceFile const*> extraSources; - this->GeneratorTarget->GetExtraSources(extraSources, config); - this->OSXBundleGenerator->GenerateMacOSXContentStatements( - extraSources, this->MacOSXContentGenerator.get()); - std::vector<cmSourceFile const*> externalObjects; - this->GeneratorTarget->GetExternalObjects(externalObjects, config); - for (cmSourceFile const* sf : externalObjects) { - this->Objects.push_back(this->GetSourceFilePath(sf)); + { + std::vector<cmSourceFile const*> headerSources; + this->GeneratorTarget->GetHeaderSources(headerSources, config); + this->OSXBundleGenerator->GenerateMacOSXContentStatements( + headerSources, this->MacOSXContentGenerator.get()); } - - cmNinjaDeps orderOnlyDeps; - this->GetLocalGenerator()->AppendTargetDepends( - this->GeneratorTarget, orderOnlyDeps, DependOnTargetOrdering); - - // Add order-only dependencies on other files associated with the target. - cmAppend(orderOnlyDeps, this->ExtraFiles); - - // Add order-only dependencies on custom command outputs. - for (cmCustomCommand const* cc : this->CustomCommands) { - cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), - this->GetLocalGenerator()); - 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(orderOnlyDeps), MapToNinjaPath()); - std::transform(ccbyproducts.begin(), ccbyproducts.end(), - std::back_inserter(orderOnlyDeps), MapToNinjaPath()); + { + std::vector<cmSourceFile const*> extraSources; + this->GeneratorTarget->GetExtraSources(extraSources, config); + this->OSXBundleGenerator->GenerateMacOSXContentStatements( + extraSources, this->MacOSXContentGenerator.get()); } - - std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end()); - orderOnlyDeps.erase(std::unique(orderOnlyDeps.begin(), orderOnlyDeps.end()), - orderOnlyDeps.end()); - - // The phony target must depend on at least one input or ninja will explain - // that "output ... of phony edge with no inputs doesn't exist" and consider - // the phony output "dirty". - if (orderOnlyDeps.empty()) { - // Any path that always exists will work here. It would be nice to - // use just "." but that is not supported by Ninja < 1.7. - std::string tgtDir; - tgtDir += this->LocalGenerator->GetCurrentBinaryDirectory(); - tgtDir += "/"; - tgtDir += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir)); + { + std::vector<cmSourceFile const*> externalObjects; + this->GeneratorTarget->GetExternalObjects(externalObjects, config); + for (cmSourceFile const* sf : externalObjects) { + this->Objects.push_back(this->GetSourceFilePath(sf)); + } } { - cmNinjaDeps orderOnlyTarget; - orderOnlyTarget.push_back(this->OrderDependsTargetForTarget()); - this->GetGlobalGenerator()->WritePhonyBuild( - this->GetBuildFileStream(), - "Order-only phony target for " + this->GetTargetName(), orderOnlyTarget, - cmNinjaDeps(), cmNinjaDeps(), orderOnlyDeps); + cmNinjaBuild build("phony"); + build.Comment = "Order-only phony target for " + this->GetTargetName(); + build.Outputs.push_back(this->OrderDependsTargetForTarget()); + + cmNinjaDeps& orderOnlyDeps = build.OrderOnlyDeps; + this->GetLocalGenerator()->AppendTargetDepends( + this->GeneratorTarget, orderOnlyDeps, DependOnTargetOrdering); + + // Add order-only dependencies on other files associated with the target. + cmAppend(orderOnlyDeps, this->ExtraFiles); + + // Add order-only dependencies on custom command outputs. + for (cmCustomCommand const* cc : this->CustomCommands) { + cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), + this->GetLocalGenerator()); + 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(orderOnlyDeps), MapToNinjaPath()); + std::transform(ccbyproducts.begin(), ccbyproducts.end(), + std::back_inserter(orderOnlyDeps), MapToNinjaPath()); + } + + std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end()); + orderOnlyDeps.erase( + std::unique(orderOnlyDeps.begin(), orderOnlyDeps.end()), + orderOnlyDeps.end()); + + // The phony target must depend on at least one input or ninja will explain + // that "output ... of phony edge with no inputs doesn't exist" and + // consider the phony output "dirty". + if (orderOnlyDeps.empty()) { + // Any path that always exists will work here. It would be nice to + // use just "." but that is not supported by Ninja < 1.7. + std::string tgtDir; + tgtDir += this->LocalGenerator->GetCurrentBinaryDirectory(); + tgtDir += "/"; + tgtDir += + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); + orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir)); + } + + this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build); } - std::vector<cmSourceFile const*> objectSources; - this->GeneratorTarget->GetObjectSources(objectSources, config); - for (cmSourceFile const* sf : objectSources) { - this->WriteObjectBuildStatement(sf); + + { + std::vector<cmSourceFile const*> objectSources; + this->GeneratorTarget->GetObjectSources(objectSources, config); + for (cmSourceFile const* sf : objectSources) { + this->WriteObjectBuildStatement(sf); + } } for (auto const& langDDIFiles : this->DDIFiles) { std::string const& language = langDDIFiles.first; cmNinjaDeps const& ddiFiles = langDDIFiles.second; - std::string const ddComment; - std::string const ddRule = this->LanguageDyndepRule(language); - cmNinjaDeps ddOutputs; - cmNinjaDeps ddImplicitOuts; - cmNinjaDeps const& ddExplicitDeps = ddiFiles; - cmNinjaDeps ddImplicitDeps; - cmNinjaDeps ddOrderOnlyDeps; - cmNinjaVars ddVars; + cmNinjaBuild build(this->LanguageDyndepRule(language)); + build.Outputs.push_back(this->GetDyndepFilePath(language)); + build.ExplicitDeps = ddiFiles; this->WriteTargetDependInfo(language); - ddOutputs.push_back(this->GetDyndepFilePath(language)); - // Make sure dyndep files for all our dependencies have already // been generated so that the '<LANG>Modules.json' files they // produced as side-effects are available for us to read. @@ -896,11 +901,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements() // refactoring the Ninja generator to generate targets in // dependency order so that we can collect the needed information. this->GetLocalGenerator()->AppendTargetDepends( - this->GeneratorTarget, ddOrderOnlyDeps, DependOnTargetArtifact); + this->GeneratorTarget, build.OrderOnlyDeps, DependOnTargetArtifact); - this->GetGlobalGenerator()->WriteBuild( - this->GetBuildFileStream(), ddComment, ddRule, ddOutputs, ddImplicitOuts, - ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars); + this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build); } this->GetBuildFileStream() << "\n"; @@ -946,7 +949,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( int const commandLineLengthLimit = ((lang_supports_response && this->ForceResponseFile())) ? -1 : 0; - cmNinjaVars vars; + cmNinjaBuild objBuild(this->LanguageCompilerRule(language)); + cmNinjaVars& vars = objBuild.Variables; vars["FLAGS"] = this->ComputeFlagsForObject(source, language); vars["DEFINES"] = this->ComputeDefines(source, language); vars["INCLUDES"] = this->ComputeIncludes(source, language); @@ -977,32 +981,26 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( language, sourceFileName, objectDir, objectFileName, objectFileDir, vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"]); - std::string comment; - std::string rule = this->LanguageCompilerRule(language); - - cmNinjaDeps outputs; - outputs.push_back(objectFileName); + objBuild.Outputs.push_back(objectFileName); // Add this object to the list of object files. this->Objects.push_back(objectFileName); - cmNinjaDeps explicitDeps; - explicitDeps.push_back(sourceFileName); + objBuild.ExplicitDeps.push_back(sourceFileName); - cmNinjaDeps implicitDeps; if (const char* objectDeps = source->GetProperty("OBJECT_DEPENDS")) { - std::vector<std::string> depList; - cmSystemTools::ExpandListArgument(objectDeps, depList); + std::vector<std::string> depList = + cmSystemTools::ExpandedListArgument(objectDeps); for (std::string& odi : depList) { if (cmSystemTools::FileIsFullPath(odi)) { odi = cmSystemTools::CollapseFullPath(odi); } } std::transform(depList.begin(), depList.end(), - std::back_inserter(implicitDeps), MapToNinjaPath()); + std::back_inserter(objBuild.ImplicitDeps), + MapToNinjaPath()); } - cmNinjaDeps orderOnlyDeps; - orderOnlyDeps.push_back(this->OrderDependsTargetForTarget()); + objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget()); // If the source file is GENERATED and does not have a custom command // (either attached to this source file or another one), assume that one of @@ -1012,8 +1010,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( !source->GetPropertyAsBool("__CMAKE_GENERATED_BY_CMAKE") && !source->GetCustomCommand() && !this->GetGlobalGenerator()->HasCustomCommandOutput(sourceFileName)) { - this->GetGlobalGenerator()->AddAssumedSourceDependencies(sourceFileName, - orderOnlyDeps); + this->GetGlobalGenerator()->AddAssumedSourceDependencies( + sourceFileName, objBuild.OrderOnlyDeps); } // For some cases we need to generate a ninja dyndep file. @@ -1022,39 +1020,34 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // For some cases we do an explicit preprocessor invocation. bool const explicitPP = this->NeedExplicitPreprocessing(language); if (explicitPP) { - bool const compilePP = this->UsePreprocessedSource(language); - std::string const ppComment; - std::string const ppRule = this->LanguagePreprocessRule(language); - cmNinjaDeps ppOutputs; - cmNinjaDeps ppImplicitOuts; - cmNinjaDeps ppExplicitDeps; - cmNinjaDeps ppImplicitDeps; - cmNinjaDeps ppOrderOnlyDeps; - cmNinjaVars ppVars; + cmNinjaBuild ppBuild(this->LanguagePreprocessRule(language)); std::string const ppFileName = this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source)); - ppOutputs.push_back(ppFileName); + ppBuild.Outputs.push_back(ppFileName); + + ppBuild.RspFile = ppFileName + ".rsp"; + bool const compilePP = this->UsePreprocessedSource(language); if (compilePP) { // Move compilation dependencies to the preprocessing build statement. - std::swap(ppExplicitDeps, explicitDeps); - std::swap(ppImplicitDeps, implicitDeps); - std::swap(ppOrderOnlyDeps, orderOnlyDeps); - std::swap(ppVars["IN_ABS"], vars["IN_ABS"]); + std::swap(ppBuild.ExplicitDeps, objBuild.ExplicitDeps); + std::swap(ppBuild.ImplicitDeps, objBuild.ImplicitDeps); + std::swap(ppBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps); + std::swap(ppBuild.Variables["IN_ABS"], vars["IN_ABS"]); // The actual compilation will now use the preprocessed source. - explicitDeps.push_back(ppFileName); + objBuild.ExplicitDeps.push_back(ppFileName); } else { // Copy compilation dependencies to the preprocessing build statement. - ppExplicitDeps = explicitDeps; - ppImplicitDeps = implicitDeps; - ppOrderOnlyDeps = orderOnlyDeps; - ppVars["IN_ABS"] = vars["IN_ABS"]; + ppBuild.ExplicitDeps = objBuild.ExplicitDeps; + ppBuild.ImplicitDeps = objBuild.ImplicitDeps; + ppBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps; + ppBuild.Variables["IN_ABS"] = vars["IN_ABS"]; } // Preprocessing and compilation generally use the same flags. - ppVars["FLAGS"] = vars["FLAGS"]; + ppBuild.Variables["FLAGS"] = vars["FLAGS"]; if (compilePP) { // In case compilation requires flags that are incompatible with @@ -1066,16 +1059,16 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( if (compilePP) { // Move preprocessor definitions to the preprocessor build statement. - std::swap(ppVars["DEFINES"], vars["DEFINES"]); + std::swap(ppBuild.Variables["DEFINES"], vars["DEFINES"]); } else { // Copy preprocessor definitions to the preprocessor build statement. - ppVars["DEFINES"] = vars["DEFINES"]; + ppBuild.Variables["DEFINES"] = vars["DEFINES"]; } // Copy include directories to the preprocessor build statement. The // Fortran compilation build statement still needs them for the INCLUDE // directive. - ppVars["INCLUDES"] = vars["INCLUDES"]; + ppBuild.Variables["INCLUDES"] = vars["INCLUDES"]; if (compilePP) { // Prepend source file's original directory as an include directory @@ -1092,8 +1085,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( } // Explicit preprocessing always uses a depfile. - ppVars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( - objectFileName + ".pp.d", cmOutputConverter::SHELL); + ppBuild.Variables["DEP_FILE"] = + this->GetLocalGenerator()->ConvertToOutputFormat( + objectFileName + ".pp.d", cmOutputConverter::SHELL); if (compilePP) { // The actual compilation does not need a depfile because it // depends on the already-preprocessed source. @@ -1103,28 +1097,24 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( if (needDyndep) { // Tell dependency scanner the object file that will result from // compiling the source. - ppVars["OBJ_FILE"] = objectFileName; + ppBuild.Variables["OBJ_FILE"] = objectFileName; // Tell dependency scanner where to store dyndep intermediate results. std::string const ddiFile = objectFileName + ".ddi"; - ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; - ppImplicitOuts.push_back(ddiFile); + ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; + ppBuild.ImplicitOuts.push_back(ddiFile); this->DDIFiles[language].push_back(ddiFile); } this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(), - ppVars); - - std::string const ppRspFile = ppFileName + ".rsp"; + ppBuild.Variables); - this->GetGlobalGenerator()->WriteBuild( - this->GetBuildFileStream(), ppComment, ppRule, ppOutputs, ppImplicitOuts, - ppExplicitDeps, ppImplicitDeps, ppOrderOnlyDeps, ppVars, ppRspFile, - commandLineLengthLimit); + this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), ppBuild, + commandLineLengthLimit); } if (needDyndep) { std::string const dyndep = this->GetDyndepFilePath(language); - orderOnlyDeps.push_back(dyndep); + objBuild.OrderOnlyDeps.push_back(dyndep); vars["dyndep"] = dyndep; } @@ -1140,25 +1130,23 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( this->SetMsvcTargetPdbVariable(vars); - std::string const rspfile = objectFileName + ".rsp"; + objBuild.RspFile = objectFileName + ".rsp"; if (language == "Swift") { this->EmitSwiftDependencyInfo(source); } else { - this->GetGlobalGenerator()->WriteBuild( - this->GetBuildFileStream(), comment, rule, outputs, - /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, - orderOnlyDeps, vars, rspfile, commandLineLengthLimit); + this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), + objBuild, commandLineLengthLimit); } if (const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) { - std::vector<std::string> outputList; - cmSystemTools::ExpandListArgument(objectOutputs, outputList); - std::transform(outputList.begin(), outputList.end(), outputList.begin(), - MapToNinjaPath()); - this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(), - "Additional output files.", - outputList, outputs); + cmNinjaBuild build("phony"); + build.Comment = "Additional output files."; + build.Outputs = cmSystemTools::ExpandedListArgument(objectOutputs); + std::transform(build.Outputs.begin(), build.Outputs.end(), + build.Outputs.begin(), MapToNinjaPath()); + build.ExplicitDeps = objBuild.Outputs; + this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build); } } diff --git a/Source/cmNinjaTypes.h b/Source/cmNinjaTypes.h index 78f3917..52c05b6 100644 --- a/Source/cmNinjaTypes.h +++ b/Source/cmNinjaTypes.h @@ -41,4 +41,24 @@ public: bool Generator = false; }; +class cmNinjaBuild +{ +public: + cmNinjaBuild() = default; + cmNinjaBuild(std::string rule) + : Rule(std::move(rule)) + { + } + + std::string Comment; + std::string Rule; + cmNinjaDeps Outputs; + cmNinjaDeps ImplicitOuts; + cmNinjaDeps ExplicitDeps; + cmNinjaDeps ImplicitDeps; + cmNinjaDeps OrderOnlyDeps; + cmNinjaVars Variables; + std::string RspFile; +}; + #endif // ! cmNinjaTypes_h diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index ab777c8..1225cbd 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -16,8 +16,10 @@ #include "cmSystemTools.h" #include <algorithm> +#include <array> #include <iterator> #include <string> +#include <utility> #include <vector> cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator( @@ -30,74 +32,74 @@ cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default; void cmNinjaUtilityTargetGenerator::Generate() { - std::string utilCommandName = - this->GetLocalGenerator()->GetCurrentBinaryDirectory(); + cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator(); + cmLocalNinjaGenerator* lg = this->GetLocalGenerator(); + cmGeneratorTarget* genTarget = this->GetGeneratorTarget(); + + std::string utilCommandName = lg->GetCurrentBinaryDirectory(); utilCommandName += "/CMakeFiles"; utilCommandName += "/"; utilCommandName += this->GetTargetName() + ".util"; utilCommandName = this->ConvertToNinjaPath(utilCommandName); + cmNinjaBuild phonyBuild("phony"); std::vector<std::string> commands; - cmNinjaDeps deps, outputs, util_outputs(1, utilCommandName); - - const std::vector<cmCustomCommand>* cmdLists[2] = { - &this->GetGeneratorTarget()->GetPreBuildCommands(), - &this->GetGeneratorTarget()->GetPostBuildCommands() - }; + cmNinjaDeps deps, util_outputs(1, utilCommandName); bool uses_terminal = false; - - for (unsigned i = 0; i != 2; ++i) { - for (cmCustomCommand const& ci : *cmdLists[i]) { - cmCustomCommandGenerator ccg(ci, this->GetConfigName(), - this->GetLocalGenerator()); - this->GetLocalGenerator()->AppendCustomCommandDeps(ccg, deps); - this->GetLocalGenerator()->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::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::vector<cmSourceFile*> sources; - std::string config = - this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"); - this->GetGeneratorTarget()->GetSourceFiles(sources, config); - for (cmSourceFile const* source : sources) { - if (cmCustomCommand const* cc = source->GetCustomCommand()) { - cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), - this->GetLocalGenerator()); - this->GetLocalGenerator()->AddCustomCommandTarget( - cc, this->GetGeneratorTarget()); - - // 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()); + { + 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()); + } } } - this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(), - outputs); - this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(), - deps); + lg->AppendTargetOutputs(genTarget, phonyBuild.Outputs); + lg->AppendTargetDepends(genTarget, deps); if (commands.empty()) { - this->GetGlobalGenerator()->WritePhonyBuild( - this->GetBuildFileStream(), - "Utility command for " + this->GetTargetName(), outputs, deps); + phonyBuild.Comment = "Utility command for " + this->GetTargetName(); + phonyBuild.ExplicitDeps = std::move(deps); + gg->WriteBuild(this->GetBuildFileStream(), phonyBuild); } else { - std::string command = this->GetLocalGenerator()->BuildCommandLine( - commands, "utility", this->GeneratorTarget); - const char* echoStr = - this->GetGeneratorTarget()->GetProperty("EchoString"); + std::string command = + lg->BuildCommandLine(commands, "utility", this->GeneratorTarget); std::string desc; + const char* echoStr = genTarget->GetProperty("EchoString"); if (echoStr) { desc = echoStr; } else { @@ -108,18 +110,12 @@ void cmNinjaUtilityTargetGenerator::Generate() // makefile vars. cmSystemTools::ReplaceString( command, "$(CMAKE_SOURCE_DIR)", - this->GetLocalGenerator() - ->ConvertToOutputFormat( - this->GetLocalGenerator()->GetSourceDirectory(), - cmOutputConverter::SHELL) - .c_str()); + lg->ConvertToOutputFormat(lg->GetSourceDirectory(), + cmOutputConverter::SHELL)); cmSystemTools::ReplaceString( command, "$(CMAKE_BINARY_DIR)", - this->GetLocalGenerator() - ->ConvertToOutputFormat( - this->GetLocalGenerator()->GetBinaryDirectory(), - cmOutputConverter::SHELL) - .c_str()); + lg->ConvertToOutputFormat(lg->GetBinaryDirectory(), + cmOutputConverter::SHELL)); cmSystemTools::ReplaceString(command, "$(ARGS)", ""); if (command.find('$') != std::string::npos) { @@ -127,24 +123,22 @@ void cmNinjaUtilityTargetGenerator::Generate() } for (std::string const& util_output : util_outputs) { - this->GetGlobalGenerator()->SeenCustomCommandOutput(util_output); + gg->SeenCustomCommandOutput(util_output); } - this->GetGlobalGenerator()->WriteCustomCommandBuild( - command, desc, "Utility command for " + this->GetTargetName(), - /*depfile*/ "", /*job_pool*/ "", uses_terminal, - /*restat*/ true, util_outputs, deps); + gg->WriteCustomCommandBuild(command, desc, + "Utility command for " + this->GetTargetName(), + /*depfile*/ "", /*job_pool*/ "", uses_terminal, + /*restat*/ true, util_outputs, deps); - this->GetGlobalGenerator()->WritePhonyBuild( - this->GetBuildFileStream(), "", outputs, - cmNinjaDeps(1, utilCommandName)); + phonyBuild.ExplicitDeps.push_back(utilCommandName); + gg->WriteBuild(this->GetBuildFileStream(), phonyBuild); } // 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 (this->GetGeneratorTarget()->GetType() != cmStateEnums::GLOBAL_TARGET) { - this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), - this->GetGeneratorTarget()); + if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) { + gg->AddTargetAlias(this->GetTargetName(), genTarget); } } |