From 3fc2de5c7439973cafc42c9c74d0821271df4825 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 29 Nov 2022 18:26:30 -0500 Subject: cmDyndepCollation: factor out writing C++ module info from Ninja To facilitate other generators being able to build C++20 modules, start pulling out collator logic into a generator-agnostic location. This commit starts by factoring out the information written to the "target depend info" object consumed during the build to handle writing out export and installation scripts expected during those steps. --- Source/CMakeLists.txt | 2 + Source/cmDyndepCollation.cxx | 262 ++++++++++++++++++++++++++++++++++++++ Source/cmDyndepCollation.h | 29 +++++ Source/cmNinjaTargetGenerator.cxx | 224 ++------------------------------ 4 files changed, 303 insertions(+), 214 deletions(-) create mode 100644 Source/cmDyndepCollation.cxx create mode 100644 Source/cmDyndepCollation.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index c0709c6..41a901a 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -198,6 +198,8 @@ add_library( cmDocumentationFormatter.cxx cmDynamicLoader.cxx cmDynamicLoader.h + cmDyndepCollation.cxx + cmDyndepCollation.h cmELF.h cmELF.cxx cmExprParserHelper.cxx diff --git a/Source/cmDyndepCollation.cxx b/Source/cmDyndepCollation.cxx new file mode 100644 index 0000000..92ad697 --- /dev/null +++ b/Source/cmDyndepCollation.cxx @@ -0,0 +1,262 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include "cmDyndepCollation.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "cmExportBuildFileGenerator.h" +#include "cmExportSet.h" +#include "cmFileSet.h" +#include "cmGeneratorExpression.h" // IWYU pragma: keep +#include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmInstallCxxModuleBmiGenerator.h" +#include "cmInstallExportGenerator.h" +#include "cmInstallFileSetGenerator.h" +#include "cmInstallGenerator.h" +#include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmSourceFile.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmTarget.h" +#include "cmTargetExport.h" + +namespace { + +Json::Value CollationInformationCxxModules( + cmGeneratorTarget const* gt, std::string const& config, + cmDyndepGeneratorCallbacks const& cb) +{ + cmTarget const* tgt = gt->Target; + auto all_file_sets = tgt->GetAllFileSetNames(); + Json::Value tdi_cxx_module_info = Json::objectValue; + for (auto const& file_set_name : all_file_sets) { + auto const* file_set = tgt->GetFileSet(file_set_name); + if (!file_set) { + gt->Makefile->IssueMessage(MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), + "\" is tracked to have file set \"", + file_set_name, + "\", but it was not found.")); + continue; + } + auto fs_type = file_set->GetType(); + // We only care about C++ module sources here. + if (fs_type != "CXX_MODULES"_s) { + continue; + } + + auto fileEntries = file_set->CompileFileEntries(); + auto directoryEntries = file_set->CompileDirectoryEntries(); + + auto directories = file_set->EvaluateDirectoryEntries( + directoryEntries, gt->LocalGenerator, config, gt); + std::map> files_per_dirs; + for (auto const& entry : fileEntries) { + file_set->EvaluateFileEntry(directories, files_per_dirs, entry, + gt->LocalGenerator, config, gt); + } + + std::map sf_map; + { + std::vector objectSources; + gt->GetObjectSources(objectSources, config); + for (auto const* sf : objectSources) { + auto full_path = sf->GetFullPath(); + if (full_path.empty()) { + gt->Makefile->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), + "\" has a full path-less source file.")); + continue; + } + sf_map[full_path] = sf; + } + } + + Json::Value fs_dest = Json::nullValue; + for (auto const& ig : gt->Makefile->GetInstallGenerators()) { + if (auto const* fsg = + dynamic_cast(ig.get())) { + if (fsg->GetTarget() == gt && fsg->GetFileSet() == file_set) { + fs_dest = fsg->GetDestination(config); + continue; + } + } + } + + for (auto const& files_per_dir : files_per_dirs) { + for (auto const& file : files_per_dir.second) { + auto lookup = sf_map.find(file); + if (lookup == sf_map.end()) { + gt->Makefile->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), "\" has source file \"", + file, + R"(" which is not in any of its "FILE_SET BASE_DIRS".)")); + continue; + } + + auto const* sf = lookup->second; + + if (!sf) { + gt->Makefile->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), "\" has source file \"", + file, "\" which has not been tracked properly.")); + continue; + } + + auto obj_path = cb.ObjectFilePath(sf, config); + Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] = + Json::objectValue; + + tdi_module_info["source"] = file; + tdi_module_info["relative-directory"] = files_per_dir.first; + tdi_module_info["name"] = file_set->GetName(); + tdi_module_info["type"] = file_set->GetType(); + tdi_module_info["visibility"] = + std::string(cmFileSetVisibilityToName(file_set->GetVisibility())); + tdi_module_info["destination"] = fs_dest; + } + } + } + + return tdi_cxx_module_info; +} + +Json::Value CollationInformationBmiInstallation(cmGeneratorTarget const* gt, + std::string const& config) +{ + cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr; + for (auto const& ig : gt->Makefile->GetInstallGenerators()) { + if (auto const* bmig = + dynamic_cast(ig.get())) { + if (bmig->GetTarget() == gt) { + bmi_gen = bmig; + continue; + } + } + } + if (bmi_gen) { + Json::Value tdi_bmi_info = Json::objectValue; + + tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions(); + tdi_bmi_info["destination"] = bmi_gen->GetDestination(config); + const char* msg_level = ""; + switch (bmi_gen->GetMessageLevel()) { + case cmInstallGenerator::MessageDefault: + break; + case cmInstallGenerator::MessageAlways: + msg_level = "MESSAGE_ALWAYS"; + break; + case cmInstallGenerator::MessageLazy: + msg_level = "MESSAGE_LAZY"; + break; + case cmInstallGenerator::MessageNever: + msg_level = "MESSAGE_NEVER"; + break; + } + tdi_bmi_info["message-level"] = msg_level; + tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config); + + return tdi_bmi_info; + } + return Json::nullValue; +} + +Json::Value CollationInformationExports(cmGeneratorTarget const* gt) +{ + Json::Value tdi_exports = Json::arrayValue; + std::string export_name = gt->GetExportName(); + + auto const& all_install_exports = gt->GetGlobalGenerator()->GetExportSets(); + for (auto const& exp : all_install_exports) { + // Ignore exports sets which are not for this target. + auto const& targets = exp.second.GetTargetExports(); + auto tgt_export = + std::find_if(targets.begin(), targets.end(), + [gt](std::unique_ptr const& te) { + return te->Target == gt; + }); + if (tgt_export == targets.end()) { + continue; + } + + auto const* installs = exp.second.GetInstallations(); + for (auto const* install : *installs) { + Json::Value tdi_export_info = Json::objectValue; + + auto const& ns = install->GetNamespace(); + auto const& dest = install->GetDestination(); + auto const& cxxm_dir = install->GetCxxModuleDirectory(); + auto const& export_prefix = install->GetTempDir(); + + tdi_export_info["namespace"] = ns; + tdi_export_info["export-name"] = export_name; + tdi_export_info["destination"] = dest; + tdi_export_info["cxx-module-info-dir"] = cxxm_dir; + tdi_export_info["export-prefix"] = export_prefix; + tdi_export_info["install"] = true; + + tdi_exports.append(tdi_export_info); + } + } + + auto const& all_build_exports = gt->Makefile->GetExportBuildFileGenerators(); + for (auto const& exp : all_build_exports) { + std::vector targets; + exp->GetTargets(targets); + + // Ignore exports sets which are not for this target. + auto const& name = gt->GetName(); + bool has_current_target = + std::any_of(targets.begin(), targets.end(), + [name](std::string const& tname) { return tname == name; }); + if (!has_current_target) { + continue; + } + + Json::Value tdi_export_info = Json::objectValue; + + auto const& ns = exp->GetNamespace(); + auto const& main_fn = exp->GetMainExportFileName(); + auto const& cxxm_dir = exp->GetCxxModuleDirectory(); + auto dest = cmsys::SystemTools::GetParentDirectory(main_fn); + auto const& export_prefix = + cmSystemTools::GetFilenamePath(exp->GetMainExportFileName()); + + tdi_export_info["namespace"] = ns; + tdi_export_info["export-name"] = export_name; + tdi_export_info["destination"] = dest; + tdi_export_info["cxx-module-info-dir"] = cxxm_dir; + tdi_export_info["export-prefix"] = export_prefix; + tdi_export_info["install"] = false; + + tdi_exports.append(tdi_export_info); + } + + return tdi_exports; +} +} + +void cmDyndepCollation::AddCollationInformation( + Json::Value& tdi, cmGeneratorTarget const* gt, std::string const& config, + cmDyndepGeneratorCallbacks const& cb) +{ + tdi["cxx-modules"] = CollationInformationCxxModules(gt, config, cb); + tdi["bmi-installation"] = CollationInformationBmiInstallation(gt, config); + tdi["exports"] = CollationInformationExports(gt); + tdi["config"] = config; +} diff --git a/Source/cmDyndepCollation.h b/Source/cmDyndepCollation.h new file mode 100644 index 0000000..088a3a0 --- /dev/null +++ b/Source/cmDyndepCollation.h @@ -0,0 +1,29 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include +#include + +class cmGeneratorTarget; +class cmSourceFile; + +namespace Json { +class Value; +} + +struct cmDyndepGeneratorCallbacks +{ + std::function + ObjectFilePath; +}; + +struct cmDyndepCollation +{ + static void AddCollationInformation(Json::Value& tdi, + cmGeneratorTarget const* gt, + std::string const& config, + cmDyndepGeneratorCallbacks const& cb); +}; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 095bf40..85a6fc2 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -21,17 +22,12 @@ #include "cmComputeLinkInformation.h" #include "cmCustomCommandGenerator.h" -#include "cmExportBuildFileGenerator.h" -#include "cmExportSet.h" +#include "cmDyndepCollation.h" #include "cmFileSet.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalNinjaGenerator.h" -#include "cmInstallCxxModuleBmiGenerator.h" -#include "cmInstallExportGenerator.h" -#include "cmInstallFileSetGenerator.h" -#include "cmInstallGenerator.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" @@ -47,7 +43,6 @@ #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" -#include "cmTargetExport.h" #include "cmValue.h" #include "cmake.h" @@ -1637,214 +1632,15 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, tdi_linked_target_dirs.append(l); } - cmTarget* tgt = this->GeneratorTarget->Target; - auto all_file_sets = tgt->GetAllFileSetNames(); - Json::Value& tdi_cxx_module_info = tdi["cxx-modules"] = Json::objectValue; - for (auto const& file_set_name : all_file_sets) { - auto* file_set = tgt->GetFileSet(file_set_name); - if (!file_set) { - this->GetMakefile()->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("Target \"", tgt->GetName(), - "\" is tracked to have file set \"", file_set_name, - "\", but it was not found.")); - continue; - } - auto fs_type = file_set->GetType(); - // We only care about C++ module sources here. - if (fs_type != "CXX_MODULES"_s) { - continue; - } - - auto fileEntries = file_set->CompileFileEntries(); - auto directoryEntries = file_set->CompileDirectoryEntries(); - - auto directories = file_set->EvaluateDirectoryEntries( - directoryEntries, this->GeneratorTarget->LocalGenerator, config, - this->GeneratorTarget); - std::map> files_per_dirs; - for (auto const& entry : fileEntries) { - file_set->EvaluateFileEntry(directories, files_per_dirs, entry, - this->GeneratorTarget->LocalGenerator, - config, this->GeneratorTarget); - } - - std::map sf_map; - { - std::vector objectSources; - this->GeneratorTarget->GetObjectSources(objectSources, config); - for (auto const* sf : objectSources) { - auto full_path = sf->GetFullPath(); - if (full_path.empty()) { - this->GetMakefile()->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("Target \"", tgt->GetName(), - "\" has a full path-less source file.")); - continue; - } - sf_map[full_path] = sf; - } - } - - Json::Value fs_dest = Json::nullValue; - for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) { - if (auto const* fsg = - dynamic_cast(ig.get())) { - if (fsg->GetTarget() == this->GeneratorTarget && - fsg->GetFileSet() == file_set) { - fs_dest = fsg->GetDestination(config); - continue; - } - } - } - - for (auto const& files_per_dir : files_per_dirs) { - for (auto const& file : files_per_dir.second) { - auto lookup = sf_map.find(file); - if (lookup == sf_map.end()) { - this->GetMakefile()->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("Target \"", tgt->GetName(), "\" has source file \"", - file, - R"(" which is not in any of its "FILE_SET BASE_DIRS".)")); - continue; - } - - auto const* sf = lookup->second; - - if (!sf) { - this->GetMakefile()->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("Target \"", tgt->GetName(), "\" has source file \"", - file, "\" which has not been tracked properly.")); - continue; - } - - auto obj_path = this->GetObjectFilePath(sf, config); - Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] = - Json::objectValue; - - tdi_module_info["source"] = file; - tdi_module_info["relative-directory"] = files_per_dir.first; - tdi_module_info["name"] = file_set->GetName(); - tdi_module_info["type"] = file_set->GetType(); - tdi_module_info["visibility"] = - std::string(cmFileSetVisibilityToName(file_set->GetVisibility())); - tdi_module_info["destination"] = fs_dest; - } - } - } - - tdi["config"] = config; + cmDyndepGeneratorCallbacks cb; + cb.ObjectFilePath = [this](cmSourceFile const* sf, std::string const& cnf) { + return this->GetObjectFilePath(sf, cnf); + }; - // Add information about the export sets that this target is a member of. - Json::Value& tdi_exports = tdi["exports"] = Json::arrayValue; - std::string export_name = this->GeneratorTarget->GetExportName(); - - cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr; - for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) { - if (auto const* bmig = - dynamic_cast(ig.get())) { - if (bmig->GetTarget() == this->GeneratorTarget) { - bmi_gen = bmig; - continue; - } - } - } - if (bmi_gen) { - Json::Value tdi_bmi_info = Json::objectValue; - - tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions(); - tdi_bmi_info["destination"] = bmi_gen->GetDestination(config); - const char* msg_level = ""; - switch (bmi_gen->GetMessageLevel()) { - case cmInstallGenerator::MessageDefault: - break; - case cmInstallGenerator::MessageAlways: - msg_level = "MESSAGE_ALWAYS"; - break; - case cmInstallGenerator::MessageLazy: - msg_level = "MESSAGE_LAZY"; - break; - case cmInstallGenerator::MessageNever: - msg_level = "MESSAGE_NEVER"; - break; - } - tdi_bmi_info["message-level"] = msg_level; - tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config); - - tdi["bmi-installation"] = tdi_bmi_info; - } else { - tdi["bmi-installation"] = Json::nullValue; - } - - auto const& all_install_exports = - this->GetGlobalGenerator()->GetExportSets(); - for (auto const& exp : all_install_exports) { - // Ignore exports sets which are not for this target. - auto const& targets = exp.second.GetTargetExports(); - auto tgt_export = - std::find_if(targets.begin(), targets.end(), - [this](std::unique_ptr const& te) { - return te->Target == this->GeneratorTarget; - }); - if (tgt_export == targets.end()) { - continue; - } - - auto const* installs = exp.second.GetInstallations(); - for (auto const* install : *installs) { - Json::Value tdi_export_info = Json::objectValue; - - auto const& ns = install->GetNamespace(); - auto const& dest = install->GetDestination(); - auto const& cxxm_dir = install->GetCxxModuleDirectory(); - auto const& export_prefix = install->GetTempDir(); - - tdi_export_info["namespace"] = ns; - tdi_export_info["export-name"] = export_name; - tdi_export_info["destination"] = dest; - tdi_export_info["cxx-module-info-dir"] = cxxm_dir; - tdi_export_info["export-prefix"] = export_prefix; - tdi_export_info["install"] = true; - - tdi_exports.append(tdi_export_info); - } - } - - auto const& all_build_exports = - this->GetMakefile()->GetExportBuildFileGenerators(); - for (auto const& exp : all_build_exports) { - std::vector targets; - exp->GetTargets(targets); - - // Ignore exports sets which are not for this target. - auto const& name = this->GeneratorTarget->GetName(); - bool has_current_target = - std::any_of(targets.begin(), targets.end(), - [name](std::string const& tname) { return tname == name; }); - if (!has_current_target) { - continue; - } - - Json::Value tdi_export_info = Json::objectValue; - - auto const& ns = exp->GetNamespace(); - auto const& main_fn = exp->GetMainExportFileName(); - auto const& cxxm_dir = exp->GetCxxModuleDirectory(); - auto dest = cmsys::SystemTools::GetParentDirectory(main_fn); - auto const& export_prefix = - cmSystemTools::GetFilenamePath(exp->GetMainExportFileName()); - - tdi_export_info["namespace"] = ns; - tdi_export_info["export-name"] = export_name; - tdi_export_info["destination"] = dest; - tdi_export_info["cxx-module-info-dir"] = cxxm_dir; - tdi_export_info["export-prefix"] = export_prefix; - tdi_export_info["install"] = false; - - tdi_exports.append(tdi_export_info); - } +#if !defined(CMAKE_BOOTSTRAP) + cmDyndepCollation::AddCollationInformation(tdi, this->GeneratorTarget, + config, cb); +#endif std::string const tdin = this->GetTargetDependInfoPath(lang, config); cmGeneratedFileStream tdif(tdin); -- cgit v0.12 From 2f93a272d08e44a66249b0c22fed8ff472dda73c Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 30 Nov 2022 09:10:10 -0500 Subject: cmDyndepCollation: factor out parsing dyndep information --- Source/cmDyndepCollation.cxx | 62 ++++++++++++++++++++++++- Source/cmDyndepCollation.h | 49 ++++++++++++++++++++ Source/cmGlobalNinjaGenerator.cxx | 97 ++------------------------------------- Source/cmGlobalNinjaGenerator.h | 4 +- 4 files changed, 116 insertions(+), 96 deletions(-) diff --git a/Source/cmDyndepCollation.cxx b/Source/cmDyndepCollation.cxx index 92ad697..f933e2a 100644 --- a/Source/cmDyndepCollation.cxx +++ b/Source/cmDyndepCollation.cxx @@ -5,10 +5,10 @@ #include #include -#include #include #include +#include #include #include @@ -260,3 +260,63 @@ void cmDyndepCollation::AddCollationInformation( tdi["exports"] = CollationInformationExports(gt); tdi["config"] = config; } + +std::unique_ptr cmDyndepCollation::ParseExportInfo( + Json::Value const& tdi) +{ + auto export_info = cm::make_unique(); + + export_info->Config = tdi["config"].asString(); + if (export_info->Config.empty()) { + export_info->Config = "noconfig"; + } + Json::Value const& tdi_exports = tdi["exports"]; + if (tdi_exports.isArray()) { + for (auto const& tdi_export : tdi_exports) { + CxxModuleExport exp; + exp.Install = tdi_export["install"].asBool(); + exp.Name = tdi_export["export-name"].asString(); + exp.Destination = tdi_export["destination"].asString(); + exp.Prefix = tdi_export["export-prefix"].asString(); + exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString(); + exp.Namespace = tdi_export["namespace"].asString(); + + export_info->Exports.push_back(exp); + } + } + auto const& bmi_installation = tdi["bmi-installation"]; + if (bmi_installation.isObject()) { + CxxModuleBmiInstall bmi_install; + + bmi_install.Component = bmi_installation["component"].asString(); + bmi_install.Destination = bmi_installation["destination"].asString(); + bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool(); + bmi_install.Optional = bmi_installation["optional"].asBool(); + bmi_install.Permissions = bmi_installation["permissions"].asString(); + bmi_install.MessageLevel = bmi_installation["message-level"].asString(); + bmi_install.ScriptLocation = + bmi_installation["script-location"].asString(); + + export_info->BmiInstallation = bmi_install; + } + Json::Value const& tdi_cxx_modules = tdi["cxx-modules"]; + if (tdi_cxx_modules.isObject()) { + for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) { + CxxModuleFileSet& fsi = export_info->ObjectToFileSet[i.key().asString()]; + auto const& tdi_cxx_module_info = *i; + fsi.Name = tdi_cxx_module_info["name"].asString(); + fsi.RelativeDirectory = + tdi_cxx_module_info["relative-directory"].asString(); + fsi.SourcePath = tdi_cxx_module_info["source"].asString(); + fsi.Type = tdi_cxx_module_info["type"].asString(); + fsi.Visibility = cmFileSetVisibilityFromName( + tdi_cxx_module_info["visibility"].asString(), nullptr); + auto const& tdi_fs_dest = tdi_cxx_module_info["destination"]; + if (tdi_fs_dest.isString()) { + fsi.Destination = tdi_fs_dest.asString(); + } + } + } + + return export_info; +} diff --git a/Source/cmDyndepCollation.h b/Source/cmDyndepCollation.h index 088a3a0..5f78707 100644 --- a/Source/cmDyndepCollation.h +++ b/Source/cmDyndepCollation.h @@ -5,7 +5,14 @@ #include "cmConfigure.h" // IWYU pragma: keep #include +#include +#include #include +#include + +#include + +#include "cmFileSet.h" class cmGeneratorTarget; class cmSourceFile; @@ -20,10 +27,52 @@ struct cmDyndepGeneratorCallbacks ObjectFilePath; }; +struct CxxModuleFileSet +{ + std::string Name; + std::string RelativeDirectory; + std::string SourcePath; + std::string Type; + cmFileSetVisibility Visibility; + cm::optional Destination; +}; + +struct CxxModuleBmiInstall +{ + std::string Component; + std::string Destination; + bool ExcludeFromAll; + bool Optional; + std::string Permissions; + std::string MessageLevel; + std::string ScriptLocation; +}; + +struct CxxModuleExport +{ + std::string Name; + std::string Destination; + std::string Prefix; + std::string CxxModuleInfoDir; + std::string Namespace; + bool Install; +}; + +struct cmCxxModuleExportInfo +{ + std::map ObjectToFileSet; + cm::optional BmiInstallation; + std::vector Exports; + std::string Config; +}; + struct cmDyndepCollation { static void AddCollationInformation(Json::Value& tdi, cmGeneratorTarget const* gt, std::string const& config, cmDyndepGeneratorCallbacks const& cb); + + static std::unique_ptr ParseExportInfo( + Json::Value const& tdi); }; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 618dfb7..cd8d9d5 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -25,6 +25,7 @@ #include "cmsys/FStream.hxx" #include "cmCxxModuleMapper.h" +#include "cmDyndepCollation.h" #include "cmFileSet.h" #include "cmFortranParser.h" #include "cmGeneratedFileStream.h" @@ -2468,45 +2469,6 @@ cm::optional cmcmd_cmake_ninja_depends_fortran( } } -struct CxxModuleFileSet -{ - std::string Name; - std::string RelativeDirectory; - std::string SourcePath; - std::string Type; - cmFileSetVisibility Visibility; - cm::optional Destination; -}; - -struct CxxModuleBmiInstall -{ - std::string Component; - std::string Destination; - bool ExcludeFromAll; - bool Optional; - std::string Permissions; - std::string MessageLevel; - std::string ScriptLocation; -}; - -struct CxxModuleExport -{ - std::string Name; - std::string Destination; - std::string Prefix; - std::string CxxModuleInfoDir; - std::string Namespace; - bool Install; -}; - -struct cmGlobalNinjaGenerator::CxxModuleExportInfo -{ - std::map ObjectToFileSet; - cm::optional BmiInstallation; - std::vector Exports; - std::string Config; -}; - 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, @@ -2514,7 +2476,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( std::string const& module_dir, std::vector const& linked_target_dirs, std::string const& arg_lang, std::string const& arg_modmapfmt, - CxxModuleExportInfo const& export_info) + cmCxxModuleExportInfo const& export_info) { // Setup path conversions. { @@ -3095,58 +3057,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector::const_iterator argBeg, } } - cmGlobalNinjaGenerator::CxxModuleExportInfo export_info; - export_info.Config = tdi["config"].asString(); - if (export_info.Config.empty()) { - export_info.Config = "noconfig"; - } - Json::Value const& tdi_exports = tdi["exports"]; - if (tdi_exports.isArray()) { - for (auto const& tdi_export : tdi_exports) { - CxxModuleExport exp; - exp.Install = tdi_export["install"].asBool(); - exp.Name = tdi_export["export-name"].asString(); - exp.Destination = tdi_export["destination"].asString(); - exp.Prefix = tdi_export["export-prefix"].asString(); - exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString(); - exp.Namespace = tdi_export["namespace"].asString(); - - export_info.Exports.push_back(exp); - } - } - auto const& bmi_installation = tdi["bmi-installation"]; - if (bmi_installation.isObject()) { - CxxModuleBmiInstall bmi_install; - - bmi_install.Component = bmi_installation["component"].asString(); - bmi_install.Destination = bmi_installation["destination"].asString(); - bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool(); - bmi_install.Optional = bmi_installation["optional"].asBool(); - bmi_install.Permissions = bmi_installation["permissions"].asString(); - bmi_install.MessageLevel = bmi_installation["message-level"].asString(); - bmi_install.ScriptLocation = - bmi_installation["script-location"].asString(); - - export_info.BmiInstallation = bmi_install; - } - Json::Value const& tdi_cxx_modules = tdi["cxx-modules"]; - if (tdi_cxx_modules.isObject()) { - for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) { - CxxModuleFileSet& fsi = export_info.ObjectToFileSet[i.key().asString()]; - auto const& tdi_cxx_module_info = *i; - fsi.Name = tdi_cxx_module_info["name"].asString(); - fsi.RelativeDirectory = - tdi_cxx_module_info["relative-directory"].asString(); - fsi.SourcePath = tdi_cxx_module_info["source"].asString(); - fsi.Type = tdi_cxx_module_info["type"].asString(); - fsi.Visibility = cmFileSetVisibilityFromName( - tdi_cxx_module_info["visibility"].asString(), nullptr); - auto const& tdi_fs_dest = tdi_cxx_module_info["destination"]; - if (tdi_fs_dest.isString()) { - fsi.Destination = tdi_fs_dest.asString(); - } - } - } + auto export_info = cmDyndepCollation::ParseExportInfo(tdi); cmake cm(cmake::RoleInternal, cmState::Unknown); cm.SetHomeDirectory(dir_top_src); @@ -3156,7 +3067,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector::const_iterator argBeg, !cm::static_reference_cast(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, arg_modmapfmt, - export_info)) { + *export_info)) { return 1; } return 0; diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 6f654f6..775e792 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -35,6 +35,7 @@ class cmMakefile; class cmOutputConverter; class cmStateDirectory; class cmake; +struct cmCxxModuleExportInfo; /** * \class cmGlobalNinjaGenerator @@ -417,7 +418,6 @@ public: bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); } void StripNinjaOutputPathPrefixAsSuffix(std::string& path); - struct CxxModuleExportInfo; bool 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, @@ -425,7 +425,7 @@ public: std::string const& module_dir, std::vector const& linked_target_dirs, std::string const& arg_lang, std::string const& arg_modmapfmt, - CxxModuleExportInfo const& export_info); + cmCxxModuleExportInfo const& export_info); virtual std::string BuildAlias(const std::string& alias, const std::string& /*config*/) const -- cgit v0.12 From f4a17b29d3bbdf602052ff6a19f8bda658929fab Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 30 Nov 2022 09:39:02 -0500 Subject: cmDyndepCollation: factor out metadata writing for dyndep --- Source/cmDyndepCollation.cxx | 336 +++++++++++++++++++++++++++++++++++++- Source/cmDyndepCollation.h | 50 ++---- Source/cmGlobalNinjaGenerator.cxx | 282 ++------------------------------ 3 files changed, 355 insertions(+), 313 deletions(-) diff --git a/Source/cmDyndepCollation.cxx b/Source/cmDyndepCollation.cxx index f933e2a..2827659 100644 --- a/Source/cmDyndepCollation.cxx +++ b/Source/cmDyndepCollation.cxx @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include @@ -17,6 +19,7 @@ #include "cmExportBuildFileGenerator.h" #include "cmExportSet.h" #include "cmFileSet.h" +#include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" // IWYU pragma: keep #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" @@ -26,6 +29,8 @@ #include "cmInstallGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmOutputConverter.h" +#include "cmScanDepFormat.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -261,10 +266,56 @@ void cmDyndepCollation::AddCollationInformation( tdi["config"] = config; } -std::unique_ptr cmDyndepCollation::ParseExportInfo( - Json::Value const& tdi) +struct CxxModuleFileSet { - auto export_info = cm::make_unique(); + std::string Name; + std::string RelativeDirectory; + std::string SourcePath; + std::string Type; + cmFileSetVisibility Visibility; + cm::optional Destination; +}; + +struct CxxModuleBmiInstall +{ + std::string Component; + std::string Destination; + bool ExcludeFromAll; + bool Optional; + std::string Permissions; + std::string MessageLevel; + std::string ScriptLocation; +}; + +struct CxxModuleExport +{ + std::string Name; + std::string Destination; + std::string Prefix; + std::string CxxModuleInfoDir; + std::string Namespace; + bool Install; +}; + +struct cmCxxModuleExportInfo +{ + std::map ObjectToFileSet; + cm::optional BmiInstallation; + std::vector Exports; + std::string Config; +}; + +void cmCxxModuleExportInfoDeleter::operator()(cmCxxModuleExportInfo* ei) const +{ + delete ei; +} + +std::unique_ptr +cmDyndepCollation::ParseExportInfo(Json::Value const& tdi) +{ + auto export_info = + std::unique_ptr( + new cmCxxModuleExportInfo); export_info->Config = tdi["config"].asString(); if (export_info->Config.empty()) { @@ -320,3 +371,282 @@ std::unique_ptr cmDyndepCollation::ParseExportInfo( return export_info; } + +bool cmDyndepCollation::WriteDyndepMetadata( + std::string const& lang, std::vector const& objects, + cmCxxModuleExportInfo const& export_info, + cmDyndepMetadataCallbacks const& cb) +{ + // Only C++ supports any of the file-set or BMI installation considered + // below. + if (lang != "CXX"_s) { + return true; + } + + bool result = true; + + // Prepare the export information blocks. + std::string const config_upper = + cmSystemTools::UpperCase(export_info.Config); + std::vector< + std::pair, CxxModuleExport const*>> + exports; + for (auto const& exp : export_info.Exports) { + std::unique_ptr properties; + + std::string const export_dir = + cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/'); + std::string const property_file_path = cmStrCat( + export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake"); + properties = cm::make_unique(property_file_path); + + // Set up the preamble. + *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name + << "\"\n" + << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper << '\n'; + + exports.emplace_back(std::move(properties), &exp); + } + + std::unique_ptr bmi_install_script; + if (export_info.BmiInstallation) { + bmi_install_script = cm::make_unique( + export_info.BmiInstallation->ScriptLocation); + } + + auto cmEscape = [](cm::string_view str) { + return cmOutputConverter::EscapeForCMake( + str, cmOutputConverter::WrapQuotes::NoWrap); + }; + auto install_destination = + [&cmEscape](std::string const& dest) -> std::pair { + if (cmSystemTools::FileIsFullPath(dest)) { + return std::make_pair(true, cmEscape(dest)); + } + return std::make_pair(false, + cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest))); + }; + + // public/private requirement tracking. + std::set private_modules; + std::map> public_source_requires; + + for (cmScanDepInfo const& object : objects) { + // Convert to forward slashes. + auto output_path = object.PrimaryOutput; +#ifdef _WIN32 + cmSystemTools::ConvertToUnixSlashes(output_path); +#endif + // Find the fileset for this object. + auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path); + bool const has_provides = !object.Provides.empty(); + if (fileset_info_itr == export_info.ObjectToFileSet.end()) { + // If it provides anything, it should have a `CXX_MODULES` or + // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present. + if (has_provides) { + // Take the first module provided to provide context. + auto const& provides = object.Provides[0]; + char const* ok_types = "`CXX_MODULES`"; + if (provides.LogicalName.find(':') != std::string::npos) { + ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if " + "it is not `export`ed)"; + } + cmSystemTools::Error(cmStrCat( + "Output ", object.PrimaryOutput, " provides the `", + provides.LogicalName, + "` module but it is not found in a `FILE_SET` of type ", ok_types)); + result = false; + } + + // This object file does not provide anything, so nothing more needs to + // be done. + continue; + } + + auto const& file_set = fileset_info_itr->second; + + // Verify the fileset type for the object. + if (file_set.Type == "CXX_MODULES"_s) { + if (!has_provides) { + cmSystemTools::Error( + cmStrCat("Output ", object.PrimaryOutput, + " is of type `CXX_MODULES` but does not provide a module")); + result = false; + continue; + } + } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) { + if (!has_provides) { + cmSystemTools::Error( + cmStrCat("Source ", file_set.SourcePath, + " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not " + "provide a module")); + result = false; + continue; + } + auto const& provides = object.Provides[0]; + if (provides.LogicalName.find(':') == std::string::npos) { + cmSystemTools::Error( + cmStrCat("Source ", file_set.SourcePath, + " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not " + "provide a module partition")); + result = false; + continue; + } + } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) { + // TODO. + } else { + if (has_provides) { + auto const& provides = object.Provides[0]; + char const* ok_types = "`CXX_MODULES`"; + if (provides.LogicalName.find(':') != std::string::npos) { + ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if " + "it is not `export`ed)"; + } + cmSystemTools::Error( + cmStrCat("Source ", file_set.SourcePath, " provides the `", + provides.LogicalName, "` C++ module but is of type `", + file_set.Type, "` module but must be of type ", ok_types)); + result = false; + } + + // Not a C++ module; ignore. + continue; + } + + if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) { + // Nothing needs to be conveyed about non-`PUBLIC` modules. + for (auto const& p : object.Provides) { + private_modules.insert(p.LogicalName); + } + continue; + } + + // The module is public. Record what it directly requires. + { + auto& reqs = public_source_requires[file_set.SourcePath]; + for (auto const& r : object.Requires) { + reqs.insert(r.LogicalName); + } + } + + // Write out properties and install rules for any exports. + for (auto const& p : object.Provides) { + bool bmi_dest_is_abs = false; + std::string bmi_destination; + if (export_info.BmiInstallation) { + auto dest = + install_destination(export_info.BmiInstallation->Destination); + bmi_dest_is_abs = dest.first; + bmi_destination = cmStrCat(dest.second, '/'); + } + + std::string install_bmi_path; + std::string build_bmi_path; + auto m = cb.ModuleFile(p.LogicalName); + if (m) { + install_bmi_path = cmStrCat( + bmi_destination, cmEscape(cmSystemTools::GetFilenameName(*m))); + build_bmi_path = cmEscape(*m); + } + + for (auto const& exp : exports) { + std::string iface_source; + if (exp.second->Install && file_set.Destination) { + auto dest = install_destination(*file_set.Destination); + iface_source = cmStrCat( + dest.second, '/', cmEscape(file_set.RelativeDirectory), + cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath))); + } else { + iface_source = cmEscape(file_set.SourcePath); + } + + std::string bmi_path; + if (exp.second->Install && export_info.BmiInstallation) { + bmi_path = install_bmi_path; + } else if (!exp.second->Install) { + bmi_path = build_bmi_path; + } + + if (iface_source.empty()) { + // No destination for the C++ module source; ignore this property + // value. + continue; + } + + *exp.first << " \"" << cmEscape(p.LogicalName) << '=' + << iface_source; + if (!bmi_path.empty()) { + *exp.first << ',' << bmi_path; + } + *exp.first << "\"\n"; + } + + if (bmi_install_script) { + auto const& bmi_install = *export_info.BmiInstallation; + + *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \"" + << cmEscape(bmi_install.Component) << '\"'; + if (!bmi_install.ExcludeFromAll) { + *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT"; + } + *bmi_install_script << ")\n"; + *bmi_install_script << " file(INSTALL\n" + " DESTINATION \""; + if (!bmi_dest_is_abs) { + *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/"; + } + *bmi_install_script << cmEscape(bmi_install.Destination) + << "\"\n" + " TYPE FILE\n"; + if (bmi_install.Optional) { + *bmi_install_script << " OPTIONAL\n"; + } + if (!bmi_install.MessageLevel.empty()) { + *bmi_install_script << " " << bmi_install.MessageLevel << "\n"; + } + if (!bmi_install.Permissions.empty()) { + *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions + << "\n"; + } + *bmi_install_script << " FILES \"" << *m << "\")\n"; + if (bmi_dest_is_abs) { + *bmi_install_script + << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n" + " \"" + << cmEscape(cmSystemTools::GetFilenameName(*m)) + << "\")\n" + " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n" + " message(WARNING\n" + " \"ABSOLUTE path INSTALL DESTINATION : " + "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n" + " endif ()\n" + " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n" + " message(FATAL_ERROR\n" + " \"ABSOLUTE path INSTALL DESTINATION forbidden (by " + "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n" + " endif ()\n"; + } + *bmi_install_script << "endif ()\n"; + } + } + } + + // Add trailing parenthesis for the `set_property` call. + for (auto const& exp : exports) { + *exp.first << ")\n"; + } + + // Check that public sources only require public modules. + for (auto const& pub_reqs : public_source_requires) { + for (auto const& req : pub_reqs.second) { + if (private_modules.count(req)) { + cmSystemTools::Error(cmStrCat( + "Public C++ module source `", pub_reqs.first, "` requires the `", + req, "` C++ module which is provided by a private source")); + result = false; + } + } + } + + return result; +} diff --git a/Source/cmDyndepCollation.h b/Source/cmDyndepCollation.h index 5f78707..e70ac09 100644 --- a/Source/cmDyndepCollation.h +++ b/Source/cmDyndepCollation.h @@ -5,16 +5,14 @@ #include "cmConfigure.h" // IWYU pragma: keep #include -#include #include #include #include #include -#include "cmFileSet.h" - class cmGeneratorTarget; +struct cmScanDepInfo; class cmSourceFile; namespace Json { @@ -27,43 +25,15 @@ struct cmDyndepGeneratorCallbacks ObjectFilePath; }; -struct CxxModuleFileSet -{ - std::string Name; - std::string RelativeDirectory; - std::string SourcePath; - std::string Type; - cmFileSetVisibility Visibility; - cm::optional Destination; -}; - -struct CxxModuleBmiInstall -{ - std::string Component; - std::string Destination; - bool ExcludeFromAll; - bool Optional; - std::string Permissions; - std::string MessageLevel; - std::string ScriptLocation; -}; - -struct CxxModuleExport +struct cmDyndepMetadataCallbacks { - std::string Name; - std::string Destination; - std::string Prefix; - std::string CxxModuleInfoDir; - std::string Namespace; - bool Install; + std::function(std::string const& name)> ModuleFile; }; -struct cmCxxModuleExportInfo +struct cmCxxModuleExportInfo; +struct cmCxxModuleExportInfoDeleter { - std::map ObjectToFileSet; - cm::optional BmiInstallation; - std::vector Exports; - std::string Config; + void operator()(cmCxxModuleExportInfo* ei) const; }; struct cmDyndepCollation @@ -73,6 +43,10 @@ struct cmDyndepCollation std::string const& config, cmDyndepGeneratorCallbacks const& cb); - static std::unique_ptr ParseExportInfo( - Json::Value const& tdi); + static std::unique_ptr + ParseExportInfo(Json::Value const& tdi); + static bool WriteDyndepMetadata(std::string const& lang, + std::vector const& objects, + cmCxxModuleExportInfo const& export_info, + cmDyndepMetadataCallbacks const& cb); }; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index cd8d9d5..4500f33 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -26,7 +26,6 @@ #include "cmCxxModuleMapper.h" #include "cmDyndepCollation.h" -#include "cmFileSet.h" #include "cmFortranParser.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpressionEvaluationFile.h" @@ -2711,279 +2710,18 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( cmGeneratedFileStream tmf(target_mods_file); tmf << target_module_info; - bool result = true; - - // Fortran doesn't support any of the file-set or BMI installation considered - // below. - if (arg_lang != "Fortran"_s) { - // Prepare the export information blocks. - std::string const config_upper = - cmSystemTools::UpperCase(export_info.Config); - std::vector, - CxxModuleExport const*>> - exports; - for (auto const& exp : export_info.Exports) { - std::unique_ptr properties; - - std::string const export_dir = - cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/'); - std::string const property_file_path = cmStrCat( - export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake"); - properties = cm::make_unique(property_file_path); - - // Set up the preamble. - *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name - << "\"\n" - << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper - << '\n'; - - exports.emplace_back(std::move(properties), &exp); - } - - std::unique_ptr bmi_install_script; - if (export_info.BmiInstallation) { - bmi_install_script = cm::make_unique( - export_info.BmiInstallation->ScriptLocation); + cmDyndepMetadataCallbacks cb; + cb.ModuleFile = + [mod_files](std::string const& name) -> cm::optional { + auto m = mod_files.find(name); + if (m != mod_files.end()) { + return m->second; } + return {}; + }; - auto cmEscape = [](cm::string_view str) { - return cmOutputConverter::EscapeForCMake( - str, cmOutputConverter::WrapQuotes::NoWrap); - }; - auto install_destination = - [&cmEscape](std::string const& dest) -> std::pair { - if (cmSystemTools::FileIsFullPath(dest)) { - return std::make_pair(true, cmEscape(dest)); - } - return std::make_pair(false, - cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest))); - }; - - // public/private requirement tracking. - std::set private_modules; - std::map> public_source_requires; - - for (cmScanDepInfo const& object : objects) { - // Convert to forward slashes. - auto output_path = object.PrimaryOutput; -# ifdef _WIN32 - cmSystemTools::ConvertToUnixSlashes(output_path); -# endif - // Find the fileset for this object. - auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path); - bool const has_provides = !object.Provides.empty(); - if (fileset_info_itr == export_info.ObjectToFileSet.end()) { - // If it provides anything, it should have a `CXX_MODULES` or - // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present. - if (has_provides) { - // Take the first module provided to provide context. - auto const& provides = object.Provides[0]; - char const* ok_types = "`CXX_MODULES`"; - if (provides.LogicalName.find(':') != std::string::npos) { - ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if " - "it is not `export`ed)"; - } - cmSystemTools::Error( - cmStrCat("Output ", object.PrimaryOutput, " provides the `", - provides.LogicalName, - "` module but it is not found in a `FILE_SET` of type ", - ok_types)); - result = false; - } - - // This object file does not provide anything, so nothing more needs to - // be done. - continue; - } - - auto const& file_set = fileset_info_itr->second; - - // Verify the fileset type for the object. - if (file_set.Type == "CXX_MODULES"_s) { - if (!has_provides) { - cmSystemTools::Error(cmStrCat( - "Output ", object.PrimaryOutput, - " is of type `CXX_MODULES` but does not provide a module")); - result = false; - continue; - } - } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) { - if (!has_provides) { - cmSystemTools::Error(cmStrCat( - "Source ", file_set.SourcePath, - " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not " - "provide a module")); - result = false; - continue; - } - auto const& provides = object.Provides[0]; - if (provides.LogicalName.find(':') == std::string::npos) { - cmSystemTools::Error(cmStrCat( - "Source ", file_set.SourcePath, - " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not " - "provide a module partition")); - result = false; - continue; - } - } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) { - // TODO. - } else { - if (has_provides) { - auto const& provides = object.Provides[0]; - char const* ok_types = "`CXX_MODULES`"; - if (provides.LogicalName.find(':') != std::string::npos) { - ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if " - "it is not `export`ed)"; - } - cmSystemTools::Error(cmStrCat( - "Source ", file_set.SourcePath, " provides the `", - provides.LogicalName, "` C++ module but is of type `", - file_set.Type, "` module but must be of type ", ok_types)); - result = false; - } - - // Not a C++ module; ignore. - continue; - } - - if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) { - // Nothing needs to be conveyed about non-`PUBLIC` modules. - for (auto const& p : object.Provides) { - private_modules.insert(p.LogicalName); - } - continue; - } - - // The module is public. Record what it directly requires. - { - auto& reqs = public_source_requires[file_set.SourcePath]; - for (auto const& r : object.Requires) { - reqs.insert(r.LogicalName); - } - } - - // Write out properties and install rules for any exports. - for (auto const& p : object.Provides) { - bool bmi_dest_is_abs = false; - std::string bmi_destination; - if (export_info.BmiInstallation) { - auto dest = - install_destination(export_info.BmiInstallation->Destination); - bmi_dest_is_abs = dest.first; - bmi_destination = cmStrCat(dest.second, '/'); - } - - std::string install_bmi_path; - std::string build_bmi_path; - auto m = mod_files.find(p.LogicalName); - if (m != mod_files.end()) { - install_bmi_path = - cmStrCat(bmi_destination, - cmEscape(cmSystemTools::GetFilenameName(m->second))); - build_bmi_path = cmEscape(m->second); - } - - for (auto const& exp : exports) { - std::string iface_source; - if (exp.second->Install && file_set.Destination) { - auto dest = install_destination(*file_set.Destination); - iface_source = cmStrCat( - dest.second, '/', cmEscape(file_set.RelativeDirectory), - cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath))); - } else { - iface_source = cmEscape(file_set.SourcePath); - } - - std::string bmi_path; - if (exp.second->Install && export_info.BmiInstallation) { - bmi_path = install_bmi_path; - } else if (!exp.second->Install) { - bmi_path = build_bmi_path; - } - - if (iface_source.empty()) { - // No destination for the C++ module source; ignore this property - // value. - continue; - } - - *exp.first << " \"" << cmEscape(p.LogicalName) << '=' - << iface_source; - if (!bmi_path.empty()) { - *exp.first << ',' << bmi_path; - } - *exp.first << "\"\n"; - } - - if (bmi_install_script) { - auto const& bmi_install = *export_info.BmiInstallation; - - *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \"" - << cmEscape(bmi_install.Component) << '\"'; - if (!bmi_install.ExcludeFromAll) { - *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT"; - } - *bmi_install_script << ")\n"; - *bmi_install_script << " file(INSTALL\n" - " DESTINATION \""; - if (!bmi_dest_is_abs) { - *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/"; - } - *bmi_install_script << cmEscape(bmi_install.Destination) - << "\"\n" - " TYPE FILE\n"; - if (bmi_install.Optional) { - *bmi_install_script << " OPTIONAL\n"; - } - if (!bmi_install.MessageLevel.empty()) { - *bmi_install_script << " " << bmi_install.MessageLevel << "\n"; - } - if (!bmi_install.Permissions.empty()) { - *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions - << "\n"; - } - *bmi_install_script << " FILES \"" << m->second << "\")\n"; - if (bmi_dest_is_abs) { - *bmi_install_script - << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n" - " \"" - << cmEscape(cmSystemTools::GetFilenameName(m->second)) - << "\")\n" - " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n" - " message(WARNING\n" - " \"ABSOLUTE path INSTALL DESTINATION : " - "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n" - " endif ()\n" - " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n" - " message(FATAL_ERROR\n" - " \"ABSOLUTE path INSTALL DESTINATION forbidden (by " - "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n" - " endif ()\n"; - } - *bmi_install_script << "endif ()\n"; - } - } - } - - // Add trailing parenthesis for the `set_property` call. - for (auto const& exp : exports) { - *exp.first << ")\n"; - } - - // Check that public sources only require public modules. - for (auto const& pub_reqs : public_source_requires) { - for (auto const& req : pub_reqs.second) { - if (private_modules.count(req)) { - cmSystemTools::Error(cmStrCat( - "Public C++ module source `", pub_reqs.first, "` requires the `", - req, "` C++ module which is provided by a private source")); - result = false; - } - } - } - } - - return result; + return cmDyndepCollation::WriteDyndepMetadata(arg_lang, objects, export_info, + cb); } int cmcmd_cmake_ninja_dyndep(std::vector::const_iterator argBeg, -- cgit v0.12