Browse Source

cmDyndepCollation: update template module database files if requested

Ben Boeckel 2 years ago
parent
commit
bea4fb7cd6
3 changed files with 119 additions and 0 deletions
  1. 34 0
      Source/cmBuildDatabase.cxx
  2. 8 0
      Source/cmBuildDatabase.h
  3. 77 0
      Source/cmDyndepCollation.cxx

+ 34 - 0
Source/cmBuildDatabase.cxx

@@ -37,6 +37,40 @@ cmBuildDatabase::cmBuildDatabase() = default;
 cmBuildDatabase::cmBuildDatabase(cmBuildDatabase const&) = default;
 cmBuildDatabase::~cmBuildDatabase() = default;
 
+cmBuildDatabase::LookupTable cmBuildDatabase::GenerateLookupTable()
+{
+  LookupTable lut;
+
+  for (auto& Set_ : this->Sets) {
+    for (auto& TranslationUnit_ : Set_.TranslationUnits) {
+      // This table is from source path to TU instance. This is fine because a
+      // single target (where this is used) cannot contain the same source file
+      // multiple times.
+      lut[TranslationUnit_.Source] = &TranslationUnit_;
+    }
+  }
+
+  return lut;
+}
+
+bool cmBuildDatabase::HasPlaceholderNames() const
+{
+  for (auto const& Set_ : this->Sets) {
+    for (auto const& TranslationUnit_ : Set_.TranslationUnits) {
+      for (auto const& provide : TranslationUnit_.Provides) {
+        if (provide.first == PlaceholderName) {
+          return true;
+        }
+        if (provide.second == PlaceholderName) {
+          return true;
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
 void cmBuildDatabase::Write(std::string const& path) const
 {
   Json::Value mcdb = Json::objectValue;

+ 8 - 0
Source/cmBuildDatabase.h

@@ -41,6 +41,14 @@ public:
   cmBuildDatabase(cmBuildDatabase const&);
   ~cmBuildDatabase();
 
+  using LookupTable = std::map<std::string, TranslationUnit*>;
+  // Generate a lookup table for the database.
+  //
+  // Only use when loading a single target's database in order to populate it.
+  LookupTable GenerateLookupTable();
+
+  bool HasPlaceholderNames() const;
+
   void Write(std::string const& path) const;
 
   static std::unique_ptr<cmBuildDatabase> Load(std::string const& path);

+ 77 - 0
Source/cmDyndepCollation.cxx

@@ -16,6 +16,7 @@
 
 #include <cm3p/json/value.h>
 
+#include "cmBuildDatabase.h"
 #include "cmExportBuildFileGenerator.h"
 #include "cmExportSet.h"
 #include "cmFileSet.h"
@@ -344,6 +345,12 @@ struct CxxModuleFileSet
   cm::optional<std::string> Destination;
 };
 
+struct CxxModuleDatabaseInfo
+{
+  std::string TemplatePath;
+  std::string Output;
+};
+
 struct CxxModuleBmiInstall
 {
   std::string Component;
@@ -370,6 +377,7 @@ struct cmCxxModuleExportInfo
 {
   std::map<std::string, SourceInfo> ObjectToSource;
   std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
+  cm::optional<CxxModuleDatabaseInfo> DatabaseInfo;
   cm::optional<CxxModuleBmiInstall> BmiInstallation;
   std::vector<CxxModuleExport> Exports;
   std::string Config;
@@ -494,6 +502,21 @@ bool cmDyndepCollation::WriteDyndepMetadata(
     exports.emplace_back(std::move(properties), &exp);
   }
 
+  std::unique_ptr<cmBuildDatabase> module_database;
+  cmBuildDatabase::LookupTable build_database_lookup;
+  if (export_info.DatabaseInfo) {
+    module_database =
+      cmBuildDatabase::Load(export_info.DatabaseInfo->TemplatePath);
+    if (module_database) {
+      build_database_lookup = module_database->GenerateLookupTable();
+    } else {
+      cmSystemTools::Error(
+        cmStrCat("Failed to read the template build database ",
+                 export_info.DatabaseInfo->TemplatePath));
+      result = false;
+    }
+  }
+
   std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
   if (export_info.BmiInstallation) {
     bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
@@ -523,6 +546,25 @@ bool cmDyndepCollation::WriteDyndepMetadata(
 #ifdef _WIN32
     cmSystemTools::ConvertToUnixSlashes(output_path);
 #endif
+
+    auto source_info_itr = export_info.ObjectToSource.find(output_path);
+
+    // Update the module compilation database `requires` field if needed.
+    if (source_info_itr != export_info.ObjectToSource.end()) {
+      auto const& sourcePath = source_info_itr->second.SourcePath;
+      auto bdb_entry = build_database_lookup.find(sourcePath);
+      if (bdb_entry != build_database_lookup.end()) {
+        bdb_entry->second->Requires.clear();
+        for (auto const& req : object.Requires) {
+          bdb_entry->second->Requires.push_back(req.LogicalName);
+        }
+      } else if (export_info.DatabaseInfo) {
+        cmSystemTools::Error(
+          cmStrCat("Failed to find module database entry for ", sourcePath));
+        result = false;
+      }
+    }
+
     // Find the fileset for this object.
     auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
     bool const has_provides = !object.Provides.empty();
@@ -547,6 +589,31 @@ bool cmDyndepCollation::WriteDyndepMetadata(
 
     auto const& file_set = fileset_info_itr->second;
 
+    // Update the module compilation database `provides` field if needed.
+    {
+      auto bdb_entry = build_database_lookup.find(file_set.SourcePath);
+      if (bdb_entry != build_database_lookup.end()) {
+        // Clear the provides mapping; we will re-initialize it here.
+        if (!object.Provides.empty()) {
+          bdb_entry->second->Provides.clear();
+        }
+        for (auto const& prov : object.Provides) {
+          auto bmiName = cb.ModuleFile(prov.LogicalName);
+          if (bmiName) {
+            bdb_entry->second->Provides[prov.LogicalName] = *bmiName;
+          } else {
+            cmSystemTools::Error(
+              cmStrCat("Failed to find BMI location for ", prov.LogicalName));
+            result = false;
+          }
+        }
+      } else if (export_info.DatabaseInfo) {
+        cmSystemTools::Error(cmStrCat(
+          "Failed to find module database entry for ", file_set.SourcePath));
+        result = false;
+      }
+    }
+
     // Verify the fileset type for the object.
     if (file_set.Type == "CXX_MODULES"_s) {
       if (!has_provides) {
@@ -708,6 +775,16 @@ bool cmDyndepCollation::WriteDyndepMetadata(
     }
   }
 
+  if (module_database) {
+    if (module_database->HasPlaceholderNames()) {
+      cmSystemTools::Error(
+        "Module compilation database still contains placeholders");
+      result = false;
+    } else {
+      module_database->Write(export_info.DatabaseInfo->Output);
+    }
+  }
+
   return result;
 }