diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2019-11-15 18:01:36 (GMT) |
---|---|---|
committer | Kyle Edwards <kyle.edwards@kitware.com> | 2019-12-13 15:51:46 (GMT) |
commit | 5a8a9f72293ab1b3fd768ff40e5fb1f07cdb7dd2 (patch) | |
tree | 7e456292c9299223c3bd851261595f24371d2f3b /Source/cmGlobalNinjaGenerator.cxx | |
parent | 3bc63e99e44b3ef82c19d018f939ea839882a131 (diff) | |
download | CMake-5a8a9f72293ab1b3fd768ff40e5fb1f07cdb7dd2.zip CMake-5a8a9f72293ab1b3fd768ff40e5fb1f07cdb7dd2.tar.gz CMake-5a8a9f72293ab1b3fd768ff40e5fb1f07cdb7dd2.tar.bz2 |
Ninja: Add multi-config variant
Co-Authored-by: vector-of-bool <vectorofbool@gmail.com>
Diffstat (limited to 'Source/cmGlobalNinjaGenerator.cxx')
-rw-r--r-- | Source/cmGlobalNinjaGenerator.cxx | 601 |
1 files changed, 475 insertions, 126 deletions
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 87fd958..11dd705 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -115,6 +115,11 @@ std::string cmGlobalNinjaGenerator::EncodeLiteral(const std::string& lit) std::string result = lit; cmSystemTools::ReplaceString(result, "$", "$$"); cmSystemTools::ReplaceString(result, "\n", "$\n"); + if (this->IsMultiConfig()) { + cmSystemTools::ReplaceString(result, + cmStrCat('$', this->GetCMakeCFGIntDir()), + this->GetCMakeCFGIntDir()); + } return result; } @@ -249,8 +254,8 @@ 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& explicitDeps, - const cmNinjaDeps& orderOnlyDeps) + const cmNinjaDeps& outputs, const std::string& config, + const cmNinjaDeps& explicitDeps, const cmNinjaDeps& orderOnlyDeps) { this->AddCustomCommandRule(); @@ -283,7 +288,11 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( if (!depfile.empty()) { vars["depfile"] = depfile; } - this->WriteBuild(*this->BuildFileStream, build); + if (config.empty()) { + this->WriteBuild(*this->GetCommonFileStream(), build); + } else { + this->WriteBuild(*this->GetConfigFileStream(config), build); + } } if (this->ComputingUnknownDependencies) { @@ -305,14 +314,15 @@ void cmGlobalNinjaGenerator::AddMacOSXContentRule() } void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(std::string input, - std::string output) + std::string output, + const std::string& config) { this->AddMacOSXContentRule(); { cmNinjaBuild build("COPY_OSX_CONTENT"); build.Outputs.push_back(std::move(output)); build.ExplicitDeps.push_back(std::move(input)); - this->WriteBuild(*this->BuildFileStream, build); + this->WriteBuild(*this->GetConfigFileStream(config), build); } } @@ -473,14 +483,16 @@ void cmGlobalNinjaGenerator::Generate() msg.str()); return; } - if (!this->OpenBuildFileStream()) { + if (!this->OpenBuildFileStreams()) { return; } if (!this->OpenRulesFileStream()) { return; } - this->TargetDependsClosures.clear(); + for (auto& it : this->Configs) { + it.second.TargetDependsClosures.clear(); + } this->InitOutputPathPrefix(); this->TargetAll = this->NinjaOutputPath("all"); @@ -496,19 +508,26 @@ void cmGlobalNinjaGenerator::Generate() this->cmGlobalGenerator::Generate(); this->WriteAssumedSourceDependencies(); - this->WriteTargetAliases(*this->BuildFileStream); - this->WriteFolderTargets(*this->BuildFileStream); - this->WriteUnknownExplicitDependencies(*this->BuildFileStream); - this->WriteBuiltinTargets(*this->BuildFileStream); + this->WriteTargetAliases(*this->GetCommonFileStream()); + this->WriteFolderTargets(*this->GetCommonFileStream()); + this->WriteUnknownExplicitDependencies(*this->GetCommonFileStream()); + this->WriteBuiltinTargets(*this->GetCommonFileStream()); if (cmSystemTools::GetErrorOccuredFlag()) { this->RulesFileStream->setstate(std::ios::failbit); - this->BuildFileStream->setstate(std::ios::failbit); + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + this->GetConfigFileStream(config)->setstate(std::ios::failbit); + } + this->GetCommonFileStream()->setstate(std::ios::failbit); } this->CloseCompileCommandsStream(); this->CloseRulesFileStream(); - this->CloseBuildFileStream(); + this->CloseBuildFileStreams(); + + if (!this->WriteDefaultBuildFile()) { + return; + } } bool cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf) @@ -612,6 +631,17 @@ bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const void cmGlobalNinjaGenerator::EnableLanguage( std::vector<std::string> const& langs, cmMakefile* mf, bool optional) { + if (this->IsMultiConfig()) { + if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) { + mf->AddCacheDefinition( + "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo", + "Semicolon separated list of supported configuration types, only " + "supports Debug, Release, MinSizeRel, and RelWithDebInfo, anything " + "else will be ignored", + cmStateEnums::STRING); + } + } + this->cmGlobalGenerator::EnableLanguage(langs, mf, optional); for (std::string const& l : langs) { if (l == "NONE") { @@ -653,7 +683,7 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand> cmGlobalNinjaGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& /*projectName*/, const std::string& /*projectDir*/, - std::vector<std::string> const& targetNames, const std::string& /*config*/, + std::vector<std::string> const& targetNames, const std::string& config, bool /*fast*/, int jobs, bool verbose, std::vector<std::string> const& makeOptions) { @@ -669,6 +699,9 @@ cmGlobalNinjaGenerator::GenerateBuildCommand( makeCommand.Add("-j", std::to_string(jobs)); } + this->AppendNinjaFileArgument(makeCommand, + config.empty() ? "Debug" : config); + makeCommand.Add(makeOptions.begin(), makeOptions.end()); for (const auto& tname : targetNames) { if (!tname.empty()) { @@ -710,44 +743,53 @@ void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory( cmGeneratorTarget* gt) const { // Compute full path to object file directory for this target. - std::string dir = - cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), '/', - gt->LocalGenerator->GetTargetDirectory(gt), '/'); + std::string dir = cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), + '/', gt->LocalGenerator->GetTargetDirectory(gt), + '/', this->GetCMakeCFGIntDir(), '/'); gt->ObjectDirectory = dir; } // Private methods -bool cmGlobalNinjaGenerator::OpenBuildFileStream() +bool cmGlobalNinjaGenerator::OpenBuildFileStreams() { - // Compute Ninja's build file path. - std::string buildFilePath = - cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), '/', - cmGlobalNinjaGenerator::NINJA_BUILD_FILE); + if (!this->OpenFileStream(this->BuildFileStream, + cmGlobalNinjaGenerator::NINJA_BUILD_FILE)) { + return false; + } + + // Write a comment about this file. + *this->BuildFileStream + << "# This file contains all the build statements describing the\n" + << "# compilation DAG.\n\n"; + + return true; +} +bool cmGlobalNinjaGenerator::OpenFileStream( + std::unique_ptr<cmGeneratedFileStream>& stream, const std::string& name) +{ // Get a stream where to generate things. - if (!this->BuildFileStream) { - this->BuildFileStream = cm::make_unique<cmGeneratedFileStream>( - buildFilePath, false, this->GetMakefileEncoding()); - if (!(*this->BuildFileStream)) { + if (!stream) { + // Compute Ninja's build file path. + std::string path = + cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), '/', name); + stream = cm::make_unique<cmGeneratedFileStream>( + path, false, this->GetMakefileEncoding()); + if (!(*stream)) { // An error message is generated by the constructor if it cannot // open the file. return false; } - } - - // Write the do not edit header. - this->WriteDisclaimer(*this->BuildFileStream); - // Write a comment about this file. - *this->BuildFileStream - << "# This file contains all the build statements describing the\n" - << "# compilation DAG.\n\n"; + // Write the do not edit header. + this->WriteDisclaimer(*stream); + } return true; } -void cmGlobalNinjaGenerator::CloseBuildFileStream() +void cmGlobalNinjaGenerator::CloseBuildFileStreams() { if (this->BuildFileStream) { this->BuildFileStream.reset(); @@ -758,25 +800,11 @@ void cmGlobalNinjaGenerator::CloseBuildFileStream() bool cmGlobalNinjaGenerator::OpenRulesFileStream() { - // Compute Ninja's build file path. - std::string rulesFilePath = - cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), '/', - cmGlobalNinjaGenerator::NINJA_RULES_FILE); - - // Get a stream where to generate things. - if (!this->RulesFileStream) { - this->RulesFileStream = cm::make_unique<cmGeneratedFileStream>( - rulesFilePath, false, this->GetMakefileEncoding()); - if (!(*this->RulesFileStream)) { - // An error message is generated by the constructor if it cannot - // open the file. - return false; - } + if (!this->OpenFileStream(this->RulesFileStream, + cmGlobalNinjaGenerator::NINJA_RULES_FILE)) { + return false; } - // Write the do not edit header. - this->WriteDisclaimer(*this->RulesFileStream); - // Write comment about this file. /* clang-format off */ *this->RulesFileStream @@ -834,9 +862,10 @@ std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath( .first->second; } -void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName) +void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName, + const std::string& config) { - this->AdditionalCleanFiles.emplace(std::move(fileName)); + this->Configs[config].AdditionalCleanFiles.emplace(std::move(fileName)); } void cmGlobalNinjaGenerator::AddCXXCompileCommand( @@ -904,14 +933,16 @@ void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies() "Assume dependencies for generated source file.", /*depfile*/ "", /*job_pool*/ "", /*uses_terminal*/ false, - /*restat*/ true, cmNinjaDeps(1, asd.first), + /*restat*/ true, cmNinjaDeps(1, asd.first), "", cmNinjaDeps(), orderOnlyDeps); } } -std::string OrderDependsTargetForTarget(cmGeneratorTarget const* target) +std::string cmGlobalNinjaGenerator::OrderDependsTargetForTarget( + cmGeneratorTarget const* target, const std::string& config) { - return "cmake_object_order_depends_target_" + target->GetName(); + return "cmake_object_order_depends_target_" + target->GetName() + "_" + + config; } void cmGlobalNinjaGenerator::AppendTargetOutputs( @@ -929,7 +960,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( case cmStateEnums::STATIC_LIBRARY: case cmStateEnums::MODULE_LIBRARY: { if (depends == DependOnTargetOrdering) { - outputs.push_back(OrderDependsTargetForTarget(target)); + outputs.push_back(OrderDependsTargetForTarget(target, config)); break; } } @@ -941,7 +972,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( } case cmStateEnums::OBJECT_LIBRARY: { if (depends == DependOnTargetOrdering) { - outputs.push_back(OrderDependsTargetForTarget(target)); + outputs.push_back(OrderDependsTargetForTarget(target, config)); break; } } @@ -951,7 +982,11 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( std::string path = target->GetLocalGenerator()->GetCurrentBinaryDirectory() + std::string("/") + target->GetName(); - outputs.push_back(this->ConvertToNinjaPath(path)); + std::string output = this->ConvertToNinjaPath(path); + if (target->Target->IsPerConfig()) { + output = this->BuildAlias(output, config); + } + outputs.push_back(output); break; } @@ -962,7 +997,8 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( void cmGlobalNinjaGenerator::AppendTargetDepends( cmGeneratorTarget const* target, cmNinjaDeps& outputs, - const std::string& config, cmNinjaTargetDepends depends) + const std::string& config, const std::string& fileConfig, + cmNinjaTargetDepends depends) { if (target->GetType() == cmStateEnums::GLOBAL_TARGET) { // These depend only on other CMake-provided targets, e.g. "all". @@ -970,7 +1006,7 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( std::string d = target->GetLocalGenerator()->GetCurrentBinaryDirectory() + "/" + util.Value; - outputs.push_back(this->ConvertToNinjaPath(d)); + outputs.push_back(this->BuildAlias(this->ConvertToNinjaPath(d), config)); } } else { cmNinjaDeps outs; @@ -979,7 +1015,14 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( if (targetDep->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - this->AppendTargetOutputs(targetDep, outs, config, depends); + // For some reason, object libraries show up as "utility" dependencies + // even though they're used for linking. Treat them as link dependencies. + if (targetDep.IsUtil() && + targetDep->GetType() != cmStateEnums::OBJECT_LIBRARY) { + this->AppendTargetOutputs(targetDep, outs, fileConfig, depends); + } else { + this->AppendTargetOutputs(targetDep, outs, config, depends); + } } std::sort(outs.begin(), outs.end()); cmAppend(outputs, outs); @@ -1001,9 +1044,10 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure( { // try to locate the target in the cache - auto find = this->TargetDependsClosures.lower_bound(target); + auto find = this->Configs[config].TargetDependsClosures.lower_bound(target); - if (find == this->TargetDependsClosures.end() || find->first != target) { + if (find == this->Configs[config].TargetDependsClosures.end() || + find->first != target) { // We now calculate the closure outputs by inspecting the dependent // targets recursively. // For that we have to distinguish between a local result set that is only @@ -1020,8 +1064,8 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure( // Collect the dependent targets for _this_ target this->AppendTargetDependsClosure(dep_target, this_outs, config, false); } - find = this->TargetDependsClosures.emplace_hint(find, target, - std::move(this_outs)); + find = this->Configs[config].TargetDependsClosures.emplace_hint( + find, target, std::move(this_outs)); } // now fill the outputs of the final result from the newly generated cache @@ -1040,21 +1084,39 @@ void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias, cmGeneratorTarget* target, const std::string& config) { - std::string buildAlias = this->NinjaOutputPath(alias); + std::string outputPath = this->NinjaOutputPath(alias); + std::string buildAlias = this->BuildAlias(outputPath, config); cmNinjaDeps outputs; this->AppendTargetOutputs(target, outputs, config); - // Mark the target's outputs as ambiguous to ensure that no other target uses - // the output as an alias. + // Mark the target's outputs as ambiguous to ensure that no other target + // uses the output as an alias. for (std::string const& output : outputs) { - TargetAliases[output] = nullptr; + this->TargetAliases[output].GeneratorTarget = nullptr; + for (const std::string& config2 : + this->Makefiles.front()->GetGeneratorConfigs()) { + this->Configs[config2].TargetAliases[output].GeneratorTarget = nullptr; + } } // Insert the alias into the map. If the alias was already present in the // map and referred to another target, mark it as ambiguous. - std::pair<TargetAliasMap::iterator, bool> newAlias = - TargetAliases.insert(std::make_pair(buildAlias, target)); - if (newAlias.second && newAlias.first->second != target) { - newAlias.first->second = nullptr; + TargetAlias ta; + ta.GeneratorTarget = target; + ta.Config = config; + std::pair<TargetAliasMap::iterator, bool> newAliasGlobal = + this->TargetAliases.insert(std::make_pair(buildAlias, ta)); + if (newAliasGlobal.second && + newAliasGlobal.first->second.GeneratorTarget != target) { + newAliasGlobal.first->second.GeneratorTarget = nullptr; + } + if (config != "all") { + std::pair<TargetAliasMap::iterator, bool> newAliasConfig = + this->Configs[config].TargetAliases.insert( + std::make_pair(outputPath, ta)); + if (newAliasConfig.second && + newAliasConfig.first->second.GeneratorTarget != target) { + newAliasConfig.first->second.GeneratorTarget = nullptr; + } } } @@ -1064,10 +1126,10 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) os << "# Target aliases.\n\n"; cmNinjaBuild build("phony"); - build.Outputs.emplace_back(""); - for (auto const& ta : TargetAliases) { + build.Outputs.emplace_back(); + for (auto const& ta : this->TargetAliases) { // Don't write ambiguous aliases. - if (!ta.second) { + if (!ta.second.GeneratorTarget) { continue; } @@ -1077,20 +1139,41 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) continue; } - // Outputs - build.Outputs[0] = ta.first; - - std::vector<std::string> configs; - ta.second->Makefile->GetConfigurations(configs); - if (configs.empty()) { - configs.emplace_back(); + build.Outputs.front() = ta.first; + build.ExplicitDeps.clear(); + if (ta.second.Config == "all") { + for (auto const& config : + ta.second.GeneratorTarget->Makefile->GetGeneratorConfigs()) { + this->AppendTargetOutputs(ta.second.GeneratorTarget, + build.ExplicitDeps, config); + } + } else { + this->AppendTargetOutputs(ta.second.GeneratorTarget, build.ExplicitDeps, + ta.second.Config); } - for (auto const& config : configs) { - // Explicit dependencies - build.ExplicitDeps.clear(); - this->AppendTargetOutputs(ta.second, build.ExplicitDeps, config); - // Write - this->WriteBuild(os, build); + this->WriteBuild(os, build); + } + + if (this->IsMultiConfig()) { + for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs()) { + for (auto const& ta : this->Configs[config].TargetAliases) { + // Don't write ambiguous aliases. + if (!ta.second.GeneratorTarget) { + continue; + } + + // Don't write alias if there is a already a custom command with + // matching output + if (this->HasCustomCommandOutput(ta.first)) { + continue; + } + + build.Outputs.front() = ta.first; + build.ExplicitDeps.clear(); + this->AppendTargetOutputs(ta.second.GeneratorTarget, + build.ExplicitDeps, config); + this->WriteBuild(*this->GetConfigFileStream(config), build); + } } } } @@ -1108,31 +1191,58 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) cmGlobalNinjaGenerator::WriteDivider(os); std::string const& currentBinaryDir = it.first; DirectoryTarget const& dt = it.second; + std::vector<std::string> configs; + dt.LG->GetMakefile()->GetConfigurations(configs, true); + if (configs.empty()) { + configs.emplace_back(); + } // Setup target + cmNinjaDeps configDeps; build.Comment = "Folder: " + currentBinaryDir; - build.Outputs.emplace_back( - this->ConvertToNinjaPath(currentBinaryDir + "/all")); - for (DirectoryTarget::Target const& t : dt.Targets) { - if (!t.ExcludeFromAll) { - std::vector<std::string> configs; - dt.LG->GetMakefile()->GetConfigurations(configs, true); - if (configs.empty()) { - configs.emplace_back(); - } - for (auto const& config : configs) { + build.Outputs.emplace_back(); + for (auto const& config : configs) { + build.ExplicitDeps.clear(); + build.Outputs.front() = this->BuildAlias( + this->ConvertToNinjaPath(currentBinaryDir + "/all"), config); + configDeps.emplace_back(build.Outputs.front()); + for (DirectoryTarget::Target const& t : dt.Targets) { + if (!t.ExcludeFromAll) { this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config); } } + for (DirectoryTarget::Dir const& d : dt.Children) { + if (!d.ExcludeFromAll) { + build.ExplicitDeps.emplace_back(this->BuildAlias( + this->ConvertToNinjaPath(d.Path + "/all"), config)); + } + } + // Write target + this->WriteBuild(os, build); } - for (DirectoryTarget::Dir const& d : dt.Children) { - if (!d.ExcludeFromAll) { - build.ExplicitDeps.emplace_back( - this->ConvertToNinjaPath(d.Path + "/all")); + + // Add shortcut target + if (this->IsMultiConfig()) { + for (auto const& config : configs) { + build.ExplicitDeps = { this->BuildAlias( + this->ConvertToNinjaPath(currentBinaryDir + "/all"), config) }; + build.Outputs.front() = + this->ConvertToNinjaPath(currentBinaryDir + "/all"); + this->WriteBuild(*this->GetConfigFileStream(config), build); } } - // Write target - this->WriteBuild(os, build); + + // Add target for all configs + if (this->IsMultiConfig()) { + build.ExplicitDeps.clear(); + for (auto const& config : configs) { + build.ExplicitDeps.push_back(this->BuildAlias( + this->ConvertToNinjaPath(currentBinaryDir + "/all"), config)); + } + build.Outputs.front() = this->BuildAlias( + this->ConvertToNinjaPath(currentBinaryDir + "/all"), "all"); + this->WriteBuild(*this->GetCommonFileStream(), build); + } } } @@ -1265,10 +1375,13 @@ void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os) cmGlobalNinjaGenerator::WriteDivider(os); os << "# Built-in targets\n\n"; - this->WriteTargetDefault(os); this->WriteTargetRebuildManifest(os); this->WriteTargetClean(os); this->WriteTargetHelp(os); + + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + this->WriteTargetDefault(*this->GetConfigFileStream(config)); + } } void cmGlobalNinjaGenerator::WriteTargetDefault(std::ostream& os) @@ -1305,7 +1418,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) cmNinjaBuild reBuild("RERUN_CMAKE"); reBuild.Comment = "Re-run CMake if any of its inputs changed."; - reBuild.Outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE)); + this->AddRebuildManifestOutputs(reBuild.Outputs); for (const auto& localGen : this->LocalGenerators) { for (std::string const& fi : localGen->GetMakefile()->GetListFiles()) { @@ -1435,9 +1548,23 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) std::string cleanScriptRel = "CMakeFiles/clean_additional.cmake"; std::string cleanScriptAbs = cmStrCat(lgr->GetBinaryDirectory(), '/', cleanScriptRel); + std::vector<std::string> configs; + this->Makefiles[0]->GetConfigurations(configs, true); + if (configs.empty()) { + configs.emplace_back(); + } // Check if there are additional files to clean - if (this->AdditionalCleanFiles.empty()) { + bool empty = true; + for (auto const& config : configs) { + auto const it = this->Configs.find(config); + if (it != this->Configs.end() && + !it->second.AdditionalCleanFiles.empty()) { + empty = false; + break; + } + } + if (empty) { // Remove cmake clean script file if it exists cmSystemTools::RemoveFile(cleanScriptAbs); return false; @@ -1449,14 +1576,23 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) if (!fout) { return false; } - fout << "# Additional clean files\n\n"; - fout << "file(REMOVE_RECURSE\n"; - for (std::string const& acf : this->AdditionalCleanFiles) { - fout << " " - << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf)) - << '\n'; + fout << "# Additional clean files\ncmake_minimum_required(VERSION 3.16)\n"; + for (auto const& config : configs) { + auto const it = this->Configs.find(config); + if (it != this->Configs.end() && + !it->second.AdditionalCleanFiles.empty()) { + fout << "\nif(\"${CONFIG}\" STREQUAL \"\" OR \"${CONFIG}\" STREQUAL \"" + << config << "\")\n"; + fout << " file(REMOVE_RECURSE\n"; + for (std::string const& acf : it->second.AdditionalCleanFiles) { + fout << " " + << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf)) + << '\n'; + } + fout << " )\n"; + fout << "endif()\n"; + } } - fout << ")\n"; } // Register clean script file lgr->GetMakefile()->AddCMakeOutputFile(cleanScriptAbs); @@ -1465,7 +1601,7 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) { cmNinjaRule rule("CLEAN_ADDITIONAL"); rule.Command = cmStrCat( - CMakeCmd(), " -P ", + CMakeCmd(), " -DCONFIG=$CONFIG -P ", lgr->ConvertToOutputFormat(this->NinjaOutputPath(cleanScriptRel), cmOutputConverter::SHELL)); rule.Description = "Cleaning additional files..."; @@ -1477,9 +1613,19 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) { cmNinjaBuild build("CLEAN_ADDITIONAL"); build.Comment = "Clean additional files."; - build.Outputs.push_back( - this->NinjaOutputPath(this->GetAdditionalCleanTargetName())); - WriteBuild(os, build); + build.Outputs.emplace_back(); + for (auto const& config : configs) { + build.Outputs.front() = this->BuildAlias( + this->NinjaOutputPath(this->GetAdditionalCleanTargetName()), config); + build.Variables["CONFIG"] = config; + WriteBuild(os, build); + } + if (this->IsMultiConfig()) { + build.Outputs.front() = + this->NinjaOutputPath(this->GetAdditionalCleanTargetName()); + build.Variables["CONFIG"] = ""; + WriteBuild(os, build); + } } // Return success return true; @@ -1494,22 +1640,91 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) // Write rule { cmNinjaRule rule("CLEAN"); - rule.Command = NinjaCmd() + " -t clean"; + rule.Command = NinjaCmd() + " $FILE_ARG -t clean $TARGETS"; rule.Description = "Cleaning all built files..."; rule.Comment = "Rule for cleaning all built files."; WriteRule(*this->RulesFileStream, rule); } + auto const configs = this->Makefiles.front()->GetGeneratorConfigs(); + // Write build { cmNinjaBuild build("CLEAN"); build.Comment = "Clean all the built files."; - build.Outputs.push_back(this->NinjaOutputPath(this->GetCleanTargetName())); - if (additionalFiles) { - build.ExplicitDeps.push_back( - this->NinjaOutputPath(this->GetAdditionalCleanTargetName())); + build.Outputs.emplace_back(); + + for (auto const& config : configs) { + build.Outputs.front() = this->BuildAlias( + this->NinjaOutputPath(this->GetCleanTargetName()), config); + if (this->IsMultiConfig()) { + build.Variables["TARGETS"] = + cmStrCat(this->BuildAlias(GetByproductsForCleanTargetName(), config), + " ", GetByproductsForCleanTargetName()); + } + build.ExplicitDeps.clear(); + if (additionalFiles) { + build.ExplicitDeps.push_back(this->BuildAlias( + this->NinjaOutputPath(this->GetAdditionalCleanTargetName()), + config)); + } + for (auto const& fileConfig : configs) { + if (this->IsMultiConfig()) { + build.Variables["FILE_ARG"] = cmStrCat( + "-f ", cmGlobalNinjaMultiGenerator::GetNinjaFilename(fileConfig)); + } + this->WriteBuild(*this->GetConfigFileStream(fileConfig), build); + } + } + + if (this->IsMultiConfig()) { + build.Outputs.front() = this->BuildAlias( + this->NinjaOutputPath(this->GetCleanTargetName()), "all"); + build.ExplicitDeps.clear(); + + if (additionalFiles) { + build.ExplicitDeps.push_back( + this->NinjaOutputPath(this->GetAdditionalCleanTargetName())); + } + + build.Variables["TARGETS"] = ""; + + for (auto const& fileConfig : configs) { + build.Variables["FILE_ARG"] = cmStrCat( + "-f ", cmGlobalNinjaMultiGenerator::GetNinjaFilename(fileConfig)); + this->WriteBuild(*this->GetConfigFileStream(fileConfig), build); + } + } + } + + if (this->IsMultiConfig()) { + cmNinjaBuild build("phony"); + build.Outputs.emplace_back( + this->NinjaOutputPath(this->GetCleanTargetName())); + build.ExplicitDeps.emplace_back(); + + for (auto const& config : configs) { + build.ExplicitDeps.front() = this->BuildAlias( + this->NinjaOutputPath(this->GetCleanTargetName()), config); + this->WriteBuild(*this->GetConfigFileStream(config), build); } + } + + // Write byproducts + if (this->IsMultiConfig()) { + cmNinjaBuild build("phony"); + build.Comment = "Clean byproducts."; + build.Outputs.emplace_back( + this->ConvertToNinjaPath(GetByproductsForCleanTargetName())); + build.ExplicitDeps = this->ByproductsForCleanTarget; WriteBuild(os, build); + + for (auto const& config : configs) { + build.Outputs.front() = this->BuildAlias( + this->ConvertToNinjaPath(GetByproductsForCleanTargetName()), config); + build.ExplicitDeps = this->Configs[config].ByproductsForCleanTarget; + WriteBuild(os, build); + } } } @@ -2016,3 +2231,137 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, } return 0; } + +void cmGlobalNinjaGenerator::AppendDirectoryForConfig( + const std::string& prefix, const std::string& config, + const std::string& suffix, std::string& dir) +{ + if (!config.empty() && this->IsMultiConfig()) { + dir += prefix; + dir += config; + dir += suffix; + } +} + +const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE = "common.ninja"; +const char* cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION = ".ninja"; + +cmGlobalNinjaMultiGenerator::cmGlobalNinjaMultiGenerator(cmake* cm) + : cmGlobalNinjaGenerator(cm) +{ + cm->GetState()->SetIsGeneratorMultiConfig(true); + cm->GetState()->SetNinjaMulti(true); +} + +void cmGlobalNinjaMultiGenerator::GetDocumentation(cmDocumentationEntry& entry) +{ + entry.Name = cmGlobalNinjaMultiGenerator::GetActualName(); + entry.Brief = "Generates build-<Config>.ninja files."; +} + +std::string cmGlobalNinjaMultiGenerator::ExpandCFGIntDir( + const std::string& str, const std::string& config) const +{ + std::string result = str; + cmSystemTools::ReplaceString(result, this->GetCMakeCFGIntDir(), config); + return result; +} + +bool cmGlobalNinjaMultiGenerator::OpenBuildFileStreams() +{ + if (!this->OpenFileStream(this->CommonFileStream, + cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE)) { + return false; + } + + // Write a comment about this file. + *this->CommonFileStream + << "# This file contains build statements common to all " + "configurations.\n\n"; + + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + if (!this->OpenFileStream(this->ConfigFileStreams[config], + GetNinjaFilename(config))) { + return false; + } + + // Write a comment about this file. + *this->ConfigFileStreams[config] + << "# This file contains build statements specific to the \"" << config + << "\"\n# configuration.\n\n"; + } + + return true; +} + +void cmGlobalNinjaMultiGenerator::CloseBuildFileStreams() +{ + if (this->CommonFileStream) { + this->CommonFileStream.reset(); + } else { + cmSystemTools::Error("Common file stream was not open."); + } + + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + if (this->ConfigFileStreams[config]) { + this->ConfigFileStreams[config].reset(); + } else { + cmSystemTools::Error( + cmStrCat("Config file stream for \"", config, "\" was not open.")); + } + } +} + +void cmGlobalNinjaMultiGenerator::AppendNinjaFileArgument( + GeneratedMakeCommand& command, const std::string& config) const +{ + command.Add("-f"); + command.Add(GetNinjaFilename(config)); +} + +std::string cmGlobalNinjaMultiGenerator::GetNinjaFilename( + const std::string& config) +{ + return cmStrCat("build-", config, + cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION); +} + +void cmGlobalNinjaMultiGenerator::AddRebuildManifestOutputs( + cmNinjaDeps& outputs) const +{ + for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs()) { + outputs.push_back(this->NinjaOutputPath(GetNinjaFilename(config))); + } + if (this->Makefiles.front()->GetDefinition( + "CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE")) { + outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE)); + } +} + +void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs( + std::vector<std::string>& configs) const +{ + auto const oldSize = configs.size(); + this->Makefiles.front()->GetConfigurations(configs); + if (configs.size() == oldSize) { + configs.emplace_back(); + } +} + +bool cmGlobalNinjaMultiGenerator::WriteDefaultBuildFile() +{ + auto const* defaultConfig = this->Makefiles.front()->GetDefinition( + "CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE"); + if (defaultConfig) { + std::unique_ptr<cmGeneratedFileStream> defaultStream; + if (!this->OpenFileStream(defaultStream, NINJA_BUILD_FILE)) { + return false; + } + *defaultStream << "# This file is a convenience file generated by\n" + << "# CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE.\n\n" + << "include " << this->GetNinjaFilename(defaultConfig) + << "\n"; + } + + return true; +} |