diff options
Diffstat (limited to 'Source/cmGlobalNinjaGenerator.cxx')
-rw-r--r-- | Source/cmGlobalNinjaGenerator.cxx | 431 |
1 files changed, 276 insertions, 155 deletions
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 02ffaf7..4f17408 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -34,6 +34,7 @@ #include "cmOutputConverter.h" #include "cmProperty.h" #include "cmRange.h" +#include "cmScanDepFormat.h" #include "cmState.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" @@ -55,6 +56,52 @@ std::string const cmGlobalNinjaGenerator::SHELL_NOOP = "cd ."; std::string const cmGlobalNinjaGenerator::SHELL_NOOP = ":"; #endif +bool operator==( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return lhs.Target == rhs.Target && lhs.Config == rhs.Config && + lhs.GenexOutput == rhs.GenexOutput; +} + +bool operator!=( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return !(lhs == rhs); +} + +bool operator<( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return lhs.Target < rhs.Target || + (lhs.Target == rhs.Target && + (lhs.Config < rhs.Config || + (lhs.Config == rhs.Config && lhs.GenexOutput < rhs.GenexOutput))); +} + +bool operator>( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return rhs < lhs; +} + +bool operator<=( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return !(lhs > rhs); +} + +bool operator>=( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return rhs <= lhs; +} + void cmGlobalNinjaGenerator::Indent(std::ostream& os, int count) { for (int i = 0; i < count; ++i) { @@ -135,7 +182,7 @@ std::string cmGlobalNinjaGenerator::EncodePath(const std::string& path) else std::replace(result.begin(), result.end(), '/', '\\'); #endif - result = EncodeLiteral(result); + result = this->EncodeLiteral(result); cmSystemTools::ReplaceString(result, " ", "$ "); cmSystemTools::ReplaceString(result, ":", "$:"); return result; @@ -167,7 +214,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, { // Write explicit outputs for (std::string const& output : build.Outputs) { - buildStr += cmStrCat(' ', EncodePath(output)); + buildStr += cmStrCat(' ', this->EncodePath(output)); if (this->ComputingUnknownDependencies) { this->CombinedBuildOutputs.insert(output); } @@ -176,7 +223,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, if (!build.ImplicitOuts.empty()) { buildStr += " |"; for (std::string const& implicitOut : build.ImplicitOuts) { - buildStr += cmStrCat(' ', EncodePath(implicitOut)); + buildStr += cmStrCat(' ', this->EncodePath(implicitOut)); } } buildStr += ':'; @@ -191,14 +238,14 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, // Write explicit dependencies. for (std::string const& explicitDep : build.ExplicitDeps) { - arguments += cmStrCat(' ', EncodePath(explicitDep)); + arguments += cmStrCat(' ', this->EncodePath(explicitDep)); } // Write implicit dependencies. if (!build.ImplicitDeps.empty()) { arguments += " |"; for (std::string const& implicitDep : build.ImplicitDeps) { - arguments += cmStrCat(' ', EncodePath(implicitDep)); + arguments += cmStrCat(' ', this->EncodePath(implicitDep)); } } @@ -206,7 +253,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, if (!build.OrderOnlyDeps.empty()) { arguments += " ||"; for (std::string const& orderOnlyDep : build.OrderOnlyDeps) { - arguments += cmStrCat(' ', EncodePath(orderOnlyDep)); + arguments += cmStrCat(' ', this->EncodePath(orderOnlyDep)); } } @@ -284,11 +331,11 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( #endif vars["COMMAND"] = std::move(cmd); } - vars["DESC"] = EncodeLiteral(description); + vars["DESC"] = this->EncodeLiteral(description); if (restat) { vars["restat"] = "1"; } - if (uses_terminal && SupportsConsolePool()) { + if (uses_terminal && this->SupportsConsolePool()) { vars["pool"] = "console"; } else if (!job_pool.empty()) { vars["pool"] = job_pool; @@ -315,7 +362,7 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( void cmGlobalNinjaGenerator::AddMacOSXContentRule() { cmNinjaRule rule("COPY_OSX_CONTENT"); - rule.Command = cmStrCat(CMakeCmd(), " -E copy $in $out"); + rule.Command = cmStrCat(this->CMakeCmd(), " -E copy $in $out"); rule.Description = "Copying OS X Content $out"; rule.Comment = "Rule for copying OS X bundle content file."; this->AddRule(rule); @@ -508,6 +555,7 @@ void cmGlobalNinjaGenerator::Generate() this->TargetAll = this->NinjaOutputPath("all"); this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt"); this->DisableCleandead = false; + this->DiagnosedCxxModuleSupport = false; this->PolicyCMP0058 = this->LocalGenerators[0]->GetMakefile()->GetPolicyStatus( @@ -708,6 +756,37 @@ bool cmGlobalNinjaGenerator::CheckLanguages( return true; } +bool cmGlobalNinjaGenerator::CheckCxxModuleSupport() +{ + bool const diagnose = !this->DiagnosedCxxModuleSupport && + !this->CMakeInstance->GetIsInTryCompile(); + if (diagnose) { + this->DiagnosedCxxModuleSupport = true; + this->GetCMakeInstance()->IssueMessage( + MessageType::AUTHOR_WARNING, + "C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP " + "is experimental. It is meant only for compiler developers to try."); + } + if (this->NinjaSupportsDyndeps) { + return true; + } + if (diagnose) { + std::ostringstream e; + /* clang-format off */ + e << + "The Ninja generator does not support C++20 modules " + "using Ninja version \n" + " " << this->NinjaVersion << "\n" + "due to lack of required features. " + "Ninja " << RequiredNinjaVersionForDyndeps() << " or higher is required." + ; + /* clang-format on */ + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str()); + cmSystemTools::SetFatalErrorOccured(); + } + return false; +} + bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const { if (this->NinjaSupportsDyndeps) { @@ -719,7 +798,8 @@ bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const e << "The Ninja generator does not support Fortran using Ninja version\n" " " << this->NinjaVersion << "\n" - "due to lack of required features. Ninja 1.10 or higher is required." + "due to lack of required features. " + "Ninja " << RequiredNinjaVersionForDyndeps() << " or higher is required." ; /* clang-format on */ mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); @@ -738,7 +818,9 @@ bool cmGlobalNinjaGenerator::CheckISPC(cmMakefile* mf) const e << "The Ninja generator does not support ISPC using Ninja version\n" " " << this->NinjaVersion << "\n" - "due to lack of required features. Ninja 1.10 or higher is required." + "due to lack of required features. " + "Ninja " << RequiredNinjaVersionForMultipleOutputs() << + " or higher is required." ; /* clang-format on */ mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); @@ -985,8 +1067,8 @@ static void EnsureTrailingSlash(std::string& path) std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath( const std::string& path) const { - auto const f = ConvertToNinjaPathCache.find(path); - if (f != ConvertToNinjaPathCache.end()) { + auto const f = this->ConvertToNinjaPathCache.find(path); + if (f != this->ConvertToNinjaPathCache.end()) { return f->second; } @@ -998,7 +1080,7 @@ std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath( #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); #endif - return ConvertToNinjaPathCache.emplace(path, std::move(convPath)) + return this->ConvertToNinjaPathCache.emplace(path, std::move(convPath)) .first->second; } @@ -1056,7 +1138,7 @@ void cmGlobalNinjaGenerator::CloseCompileCommandsStream() } } -void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os) +void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os) const { os << "# CMAKE generated file: DO NOT EDIT!\n" << "# Generated by \"" << this->GetName() << "\"" @@ -1070,12 +1152,13 @@ void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies() cmNinjaDeps orderOnlyDeps; std::copy(asd.second.begin(), asd.second.end(), std::back_inserter(orderOnlyDeps)); - WriteCustomCommandBuild(/*command=*/"", /*description=*/"", - "Assume dependencies for generated source file.", - /*depfile*/ "", /*job_pool*/ "", - /*uses_terminal*/ false, - /*restat*/ true, cmNinjaDeps(1, asd.first), "", - cmNinjaDeps(), orderOnlyDeps); + this->WriteCustomCommandBuild( + /*command=*/"", /*description=*/"", + "Assume dependencies for generated source file.", + /*depfile*/ "", /*job_pool*/ "", + /*uses_terminal*/ false, + /*restat*/ true, cmNinjaDeps(1, asd.first), "", cmNinjaDeps(), + orderOnlyDeps); } } @@ -1087,7 +1170,7 @@ std::string cmGlobalNinjaGenerator::OrderDependsTargetForTarget( void cmGlobalNinjaGenerator::AppendTargetOutputs( cmGeneratorTarget const* target, cmNinjaDeps& outputs, - const std::string& config, cmNinjaTargetDepends depends) + const std::string& config, cmNinjaTargetDepends depends) const { // for frameworks, we want the real name, not smple name // frameworks always appear versioned, and the build.ninja @@ -1100,7 +1183,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( case cmStateEnums::STATIC_LIBRARY: case cmStateEnums::MODULE_LIBRARY: { if (depends == DependOnTargetOrdering) { - outputs.push_back(OrderDependsTargetForTarget(target, config)); + outputs.push_back(this->OrderDependsTargetForTarget(target, config)); break; } } @@ -1112,7 +1195,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( } case cmStateEnums::OBJECT_LIBRARY: { if (depends == DependOnTargetOrdering) { - outputs.push_back(OrderDependsTargetForTarget(target, config)); + outputs.push_back(this->OrderDependsTargetForTarget(target, config)); break; } } @@ -1193,23 +1276,30 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( void cmGlobalNinjaGenerator::AppendTargetDependsClosure( cmGeneratorTarget const* target, cmNinjaDeps& outputs, - const std::string& config) + const std::string& config, const std::string& fileConfig, bool genexOutput) { cmNinjaOuts outs; - this->AppendTargetDependsClosure(target, outs, config, true); + this->AppendTargetDependsClosure(target, outs, config, fileConfig, + genexOutput, true); cm::append(outputs, outs); } void cmGlobalNinjaGenerator::AppendTargetDependsClosure( cmGeneratorTarget const* target, cmNinjaOuts& outputs, - const std::string& config, bool omit_self) + const std::string& config, const std::string& fileConfig, bool genexOutput, + bool omit_self) { // try to locate the target in the cache - auto find = this->Configs[config].TargetDependsClosures.lower_bound(target); + ByConfig::TargetDependsClosureKey key{ + target, + config, + genexOutput, + }; + auto find = this->Configs[fileConfig].TargetDependsClosures.lower_bound(key); - if (find == this->Configs[config].TargetDependsClosures.end() || - find->first != target) { + if (find == this->Configs[fileConfig].TargetDependsClosures.end() || + find->first != key) { // 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 @@ -1219,18 +1309,27 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure( cmNinjaOuts this_outs; // this will be the new cache entry for (auto const& dep_target : this->GetTargetDirectDepends(target)) { - if (!dep_target->IsInBuildSystem() || - (target->GetType() != cmStateEnums::UTILITY && - dep_target->GetType() != cmStateEnums::UTILITY && - this->EnableCrossConfigBuild() && !dep_target.IsCross())) { + if (!dep_target->IsInBuildSystem()) { continue; } - // Collect the dependent targets for _this_ target - this->AppendTargetDependsClosure(dep_target, this_outs, config, false); + if (!this->IsSingleConfigUtility(target) && + !this->IsSingleConfigUtility(dep_target) && + this->EnableCrossConfigBuild() && !dep_target.IsCross() && + !genexOutput) { + continue; + } + + if (dep_target.IsCross()) { + this->AppendTargetDependsClosure(dep_target, this_outs, fileConfig, + fileConfig, genexOutput, false); + } else { + this->AppendTargetDependsClosure(dep_target, this_outs, config, + fileConfig, genexOutput, false); + } } - find = this->Configs[config].TargetDependsClosures.emplace_hint( - find, target, std::move(this_outs)); + find = this->Configs[fileConfig].TargetDependsClosures.emplace_hint( + find, key, std::move(this_outs)); } // now fill the outputs of the final result from the newly generated cache @@ -1413,7 +1512,7 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) build.Outputs.front() = this->BuildAlias(buildDirAllTarget, config); configDeps.emplace_back(build.Outputs.front()); for (DirectoryTarget::Target const& t : dt.Targets) { - if (!IsExcludedFromAllInConfig(t, config)) { + if (!this->IsExcludedFromAllInConfig(t, config)) { this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config, DependOnTargetArtifact); } @@ -1626,7 +1725,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) { cmNinjaRule rule("RERUN_CMAKE"); rule.Command = - cmStrCat(CMakeCmd(), " --regenerate-during-build -S", + cmStrCat(this->CMakeCmd(), " --regenerate-during-build -S", lg->ConvertToOutputFormat(lg->GetSourceDirectory(), cmOutputConverter::SHELL), " -B", @@ -1651,7 +1750,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) // Use 'console' pool to get non buffered output of the CMake re-run call // Available since Ninja 1.5 - if (SupportsConsolePool()) { + if (this->SupportsConsolePool()) { reBuild.Variables["pool"] = "console"; } @@ -1660,7 +1759,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) { cmNinjaRule rule("VERIFY_GLOBS"); rule.Command = - cmStrCat(CMakeCmd(), " -P ", + cmStrCat(this->CMakeCmd(), " -P ", lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(), cmOutputConverter::SHELL)); rule.Description = "Re-checking globbed directories..."; @@ -1721,8 +1820,8 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) 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(), + this->CustomCommandOutputs.begin(), + this->CustomCommandOutputs.end(), std::back_inserter(build.Outputs)); this->WriteBuild(os, build); } @@ -1806,7 +1905,8 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) fout << " file(REMOVE_RECURSE\n"; for (std::string const& acf : it->second.AdditionalCleanFiles) { fout << " " - << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf)) + << cmOutputConverter::EscapeForCMake( + this->ConvertToNinjaPath(acf)) << '\n'; } fout << " )\n"; @@ -1821,7 +1921,7 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) { cmNinjaRule rule("CLEAN_ADDITIONAL"); rule.Command = cmStrCat( - CMakeCmd(), " -DCONFIG=$CONFIG -P ", + this->CMakeCmd(), " -DCONFIG=$CONFIG -P ", lgr->ConvertToOutputFormat(this->NinjaOutputPath(cleanScriptRel), cmOutputConverter::SHELL)); rule.Description = "Cleaning additional files..."; @@ -1838,13 +1938,13 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) build.Outputs.front() = this->BuildAlias( this->NinjaOutputPath(this->GetAdditionalCleanTargetName()), config); build.Variables["CONFIG"] = config; - WriteBuild(os, build); + this->WriteBuild(os, build); } if (this->IsMultiConfig()) { build.Outputs.front() = this->NinjaOutputPath(this->GetAdditionalCleanTargetName()); build.Variables["CONFIG"] = ""; - WriteBuild(os, build); + this->WriteBuild(os, build); } } // Return success @@ -1854,13 +1954,13 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) { // -- Additional clean target - bool additionalFiles = WriteTargetCleanAdditional(os); + bool additionalFiles = this->WriteTargetCleanAdditional(os); // -- Default clean target // Write rule { cmNinjaRule rule("CLEAN"); - rule.Command = cmStrCat(NinjaCmd(), " $FILE_ARG -t clean $TARGETS"); + rule.Command = cmStrCat(this->NinjaCmd(), " $FILE_ARG -t clean $TARGETS"); rule.Description = "Cleaning all built files..."; rule.Comment = "Rule for cleaning all built files."; WriteRule(*this->RulesFileStream, rule); @@ -1961,13 +2061,13 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) build.Outputs.emplace_back( this->ConvertToNinjaPath(GetByproductsForCleanTargetName())); build.ExplicitDeps = this->ByproductsForCleanTarget; - WriteBuild(os, build); + this->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); + this->WriteBuild(os, build); } } } @@ -1976,7 +2076,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os) { { cmNinjaRule rule("HELP"); - rule.Command = cmStrCat(NinjaCmd(), " -t targets"); + rule.Command = cmStrCat(this->NinjaCmd(), " -t targets"); rule.Description = "All primary targets available:"; rule.Comment = "Rule for printing all primary targets available."; WriteRule(*this->RulesFileStream, rule); @@ -1985,7 +2085,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os) cmNinjaBuild build("HELP"); build.Comment = "Print all primary targets available."; build.Outputs.push_back(this->NinjaOutputPath("help")); - WriteBuild(os, build); + this->WriteBuild(os, build); } } @@ -2016,6 +2116,8 @@ void cmGlobalNinjaGenerator::StripNinjaOutputPathPrefixAsSuffix( cmStripSuffixIfExists(path, this->OutputPathPrefix); } +#if !defined(CMAKE_BOOTSTRAP) + /* We use the following approach to support Fortran. Each target already @@ -2095,16 +2197,6 @@ Compilation of source files within a target is split into the following steps: (because the latter consumes the module). */ -struct cmSourceInfo -{ - // Set of provided and required modules. - std::set<std::string> Provides; - std::set<std::string> Requires; - - // Set of files included in the translation unit. - std::set<std::string> Includes; -}; - static std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran( std::string const& arg_tdi, std::string const& arg_pp); @@ -2112,6 +2204,7 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, std::vector<std::string>::const_iterator argEnd) { std::string arg_tdi; + std::string arg_src; std::string arg_pp; std::string arg_dep; std::string arg_obj; @@ -2120,6 +2213,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, for (std::string const& arg : cmMakeRange(argBeg, argEnd)) { if (cmHasLiteralPrefix(arg, "--tdi=")) { arg_tdi = arg.substr(6); + } else if (cmHasLiteralPrefix(arg, "--src=")) { + arg_src = arg.substr(6); } else if (cmHasLiteralPrefix(arg, "--pp=")) { arg_pp = arg.substr(5); } else if (cmHasLiteralPrefix(arg, "--dep=")) { @@ -2160,6 +2255,9 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, cmSystemTools::Error("-E cmake_ninja_depends requires value for --lang="); return 1; } + if (arg_src.empty()) { + arg_src = cmStrCat("<", arg_obj, " input file>"); + } std::unique_ptr<cmSourceInfo> info; if (arg_lang == "Fortran") { @@ -2176,6 +2274,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, return 1; } + info->PrimaryOutput = arg_obj; + { cmGeneratedFileStream depfile(arg_dep); depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":"; @@ -2185,24 +2285,7 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, depfile << "\n"; } - Json::Value ddi(Json::objectValue); - ddi["object"] = arg_obj; - - Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue; - for (std::string const& provide : info->Provides) { - ddi_provides.append(provide); - } - Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue; - for (std::string const& r : info->Requires) { - // Require modules not provided in the same source. - if (!info->Provides.count(r)) { - ddi_requires.append(r); - } - } - - cmGeneratedFileStream ddif(arg_ddi); - ddif << ddi; - if (!ddif) { + if (!cmScanDepFormat_P1689_Write(arg_ddi, arg_src, *info)) { cmSystemTools::Error( cmStrCat("-E cmake_ninja_depends failed to write ", arg_ddi)); return 1; @@ -2260,26 +2343,35 @@ std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran( } auto info = cm::make_unique<cmSourceInfo>(); - info->Provides = finfo.Provides; - info->Requires = finfo.Requires; - info->Includes = finfo.Includes; + for (std::string const& provide : finfo.Provides) { + cmSourceReqInfo src_info; + src_info.LogicalName = provide; + src_info.CompiledModulePath = provide; + info->Provides.emplace_back(src_info); + } + for (std::string const& require : finfo.Requires) { + // Require modules not provided in the same source. + if (finfo.Provides.count(require)) { + continue; + } + cmSourceReqInfo src_info; + src_info.LogicalName = require; + src_info.CompiledModulePath = require; + info->Requires.emplace_back(src_info); + } + for (std::string const& include : finfo.Includes) { + info->Includes.push_back(include); + } return info; } -struct cmDyndepObjectInfo -{ - std::string Object; - std::vector<std::string> Provides; - std::vector<std::string> Requires; -}; - bool cmGlobalNinjaGenerator::WriteDyndepFile( std::string const& dir_top_src, std::string const& dir_top_bld, std::string const& dir_cur_src, std::string const& dir_cur_bld, std::string const& arg_dd, std::vector<std::string> const& arg_ddis, std::string const& module_dir, std::vector<std::string> const& linked_target_dirs, - std::string const& arg_lang) + std::string const& arg_lang, std::string const& arg_modmapfmt) { // Setup path conversions. { @@ -2294,34 +2386,14 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( this->LocalGenerators.push_back(std::move(lgd)); } - std::vector<cmDyndepObjectInfo> objects; + std::vector<cmSourceInfo> objects; for (std::string const& arg_ddi : arg_ddis) { - // Load the ddi file and compute the module file paths it provides. - Json::Value ddio; - Json::Value const& ddi = ddio; - cmsys::ifstream ddif(arg_ddi.c_str(), std::ios::in | std::ios::binary); - Json::Reader reader; - if (!reader.parse(ddif, ddio, false)) { - cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", - arg_ddi, - reader.getFormattedErrorMessages())); + cmSourceInfo info; + if (!cmScanDepFormat_P1689_Parse(arg_ddi, &info)) { + cmSystemTools::Error( + cmStrCat("-E cmake_ninja_dyndep failed to parse ddi file ", arg_ddi)); return false; } - - cmDyndepObjectInfo info; - info.Object = ddi["object"].asString(); - Json::Value const& ddi_provides = ddi["provides"]; - if (ddi_provides.isArray()) { - for (auto const& ddi_provide : ddi_provides) { - info.Provides.push_back(ddi_provide.asString()); - } - } - Json::Value const& ddi_requires = ddi["requires"]; - if (ddi_requires.isArray()) { - for (auto const& ddi_require : ddi_requires) { - info.Requires.push_back(ddi_require.asString()); - } - } objects.push_back(std::move(info)); } @@ -2352,11 +2424,12 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( // We do this after loading the modules provided by linked targets // in case we have one of the same name that must be preferred. Json::Value tm = Json::objectValue; - for (cmDyndepObjectInfo const& object : objects) { - for (std::string const& p : object.Provides) { - std::string const mod = cmStrCat(module_dir, p); - mod_files[p] = mod; - tm[p] = mod; + for (cmSourceInfo const& object : objects) { + for (auto const& p : object.Provides) { + std::string const mod = cmStrCat( + module_dir, cmSystemTools::GetFilenameName(p.CompiledModulePath)); + mod_files[p.LogicalName] = mod; + tm[p.LogicalName] = mod; } } @@ -2366,15 +2439,16 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( { cmNinjaBuild build("dyndep"); build.Outputs.emplace_back(""); - for (cmDyndepObjectInfo const& object : objects) { - build.Outputs[0] = object.Object; + for (cmSourceInfo const& object : objects) { + build.Outputs[0] = this->ConvertToNinjaPath(object.PrimaryOutput); build.ImplicitOuts.clear(); - for (std::string const& p : object.Provides) { - build.ImplicitOuts.push_back(this->ConvertToNinjaPath(mod_files[p])); + for (auto const& p : object.Provides) { + build.ImplicitOuts.push_back( + this->ConvertToNinjaPath(mod_files[p.LogicalName])); } build.ImplicitDeps.clear(); - for (std::string const& r : object.Requires) { - auto mit = mod_files.find(r); + for (auto const& r : object.Requires) { + auto mit = mod_files.find(r.LogicalName); if (mit != mod_files.end()) { build.ImplicitDeps.push_back(this->ConvertToNinjaPath(mit->second)); } @@ -2384,6 +2458,48 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( build.Variables.emplace("restat", "1"); } + if (arg_modmapfmt.empty()) { + // nothing to do. + } else { + std::stringstream mm; + if (arg_modmapfmt == "gcc") { + // Documented in GCC's documentation. The format is a series of lines + // with a module name and the associated filename separated by + // spaces. The first line may use `$root` as the module name to + // specify a "repository root". That is used to anchor any relative + // paths present in the file (CMake should never generate any). + + // Write the root directory to use for module paths. + mm << "$root .\n"; + + for (auto const& l : object.Provides) { + auto m = mod_files.find(l.LogicalName); + if (m != mod_files.end()) { + mm << l.LogicalName << " " << this->ConvertToNinjaPath(m->second) + << "\n"; + } + } + for (auto const& r : object.Requires) { + auto m = mod_files.find(r.LogicalName); + if (m != mod_files.end()) { + mm << r.LogicalName << " " << this->ConvertToNinjaPath(m->second) + << "\n"; + } + } + } else { + cmSystemTools::Error( + cmStrCat("-E cmake_ninja_dyndep does not understand the ", + arg_modmapfmt, " module map format")); + return false; + } + + // XXX(modmap): If changing this path construction, change + // `cmNinjaTargetGenerator::WriteObjectBuildStatements` to generate the + // corresponding file path. + cmGeneratedFileStream mmf(cmStrCat(object.PrimaryOutput, ".modmap")); + mmf << mm.str(); + } + this->WriteBuild(ddf, build); } } @@ -2398,11 +2514,6 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( return true; } -bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const -{ - return !this->CrossConfigs.empty(); -} - int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, std::vector<std::string>::const_iterator argEnd) { @@ -2412,6 +2523,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, std::string arg_dd; std::string arg_lang; std::string arg_tdi; + std::string arg_modmapfmt; std::vector<std::string> arg_ddis; for (std::string const& arg : arg_full) { if (cmHasLiteralPrefix(arg, "--tdi=")) { @@ -2420,6 +2532,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, arg_lang = arg.substr(7); } else if (cmHasLiteralPrefix(arg, "--dd=")) { arg_dd = arg.substr(5); + } else if (cmHasLiteralPrefix(arg, "--modmapfmt=")) { + arg_modmapfmt = arg.substr(12); } else if (!cmHasLiteralPrefix(arg, "--") && cmHasLiteralSuffix(arg, ".ddi")) { arg_ddis.push_back(arg); @@ -2478,12 +2592,19 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, if (!ggd || !cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd).WriteDyndepFile( dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis, - module_dir, linked_target_dirs, arg_lang)) { + module_dir, linked_target_dirs, arg_lang, arg_modmapfmt)) { return 1; } return 0; } +#endif + +bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const +{ + return !this->CrossConfigs.empty(); +} + void cmGlobalNinjaGenerator::AppendDirectoryForConfig( const std::string& prefix, const std::string& config, const std::string& suffix, std::string& dir) @@ -2501,6 +2622,13 @@ std::set<std::string> cmGlobalNinjaGenerator::GetCrossConfigs( return result; } +bool cmGlobalNinjaGenerator::IsSingleConfigUtility( + cmGeneratorTarget const* target) const +{ + return target->GetType() == cmStateEnums::UTILITY && + !this->PerConfigUtilityTargets.count(target->GetName()); +} + const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE = "CMakeFiles/common.ninja"; const char* cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION = ".ninja"; @@ -2651,30 +2779,17 @@ void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs( bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables() { - this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_BUILD_TYPE"); - this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_CROSS_CONFIGS"); - this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_CONFIGS"); - return this->ReadCacheEntriesForBuild(*this->Makefiles.front()->GetState()); -} - -std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const -{ - return ""; -} - -bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( - const cmState& state) -{ std::vector<std::string> configsVec; - cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CONFIGURATION_TYPES"), - configsVec); + cmExpandList( + this->Makefiles.front()->GetSafeDefinition("CMAKE_CONFIGURATION_TYPES"), + configsVec); if (configsVec.empty()) { configsVec.emplace_back(); } std::set<std::string> configs(configsVec.cbegin(), configsVec.cend()); this->DefaultFileConfig = - state.GetSafeCacheEntryValue("CMAKE_DEFAULT_BUILD_TYPE"); + this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_BUILD_TYPE"); if (this->DefaultFileConfig.empty()) { this->DefaultFileConfig = configsVec.front(); } @@ -2689,8 +2804,9 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( } std::vector<std::string> crossConfigsVec; - cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CROSS_CONFIGS"), - crossConfigsVec); + cmExpandList( + this->Makefiles.front()->GetSafeDefinition("CMAKE_CROSS_CONFIGS"), + crossConfigsVec); auto crossConfigs = ListSubsetWithAll(configs, configs, crossConfigsVec); if (!crossConfigs) { std::ostringstream msg; @@ -2703,7 +2819,7 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( this->CrossConfigs = *crossConfigs; auto defaultConfigsString = - state.GetSafeCacheEntryValue("CMAKE_DEFAULT_CONFIGS"); + this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_CONFIGS"); if (defaultConfigsString.empty()) { defaultConfigsString = this->DefaultFileConfig; } @@ -2737,6 +2853,11 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( return true; } +std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const +{ + return ""; +} + std::string cmGlobalNinjaMultiGenerator::OrderDependsTargetForTarget( cmGeneratorTarget const* target, const std::string& config) const { |