cmDyndepCollation: write build database metadata

Generators will hook this up into the build graph as needed.
diff --git a/Source/cmDyndepCollation.cxx b/Source/cmDyndepCollation.cxx
index 545782f..1c05f25 100644
--- a/Source/cmDyndepCollation.cxx
+++ b/Source/cmDyndepCollation.cxx
@@ -194,6 +194,20 @@
   return info;
 }
 
+Json::Value CollationInformationDatabaseInfo(cmGeneratorTarget const* gt,
+                                             std::string const& config)
+{
+  Json::Value db_info;
+
+  auto db_path = gt->BuildDatabasePath("CXX", config);
+  if (!db_path.empty()) {
+    db_info["template-path"] = cmStrCat(db_path, ".in");
+    db_info["output"] = db_path;
+  }
+
+  return db_info;
+}
+
 Json::Value CollationInformationBmiInstallation(cmGeneratorTarget const* gt,
                                                 std::string const& config)
 {
@@ -323,6 +337,7 @@
   auto sourcesInfo = CollationInformationSources(gt, config, cb);
   tdi["sources"] = sourcesInfo.Sources;
   tdi["cxx-modules"] = sourcesInfo.CxxModules;
+  tdi["database-info"] = CollationInformationDatabaseInfo(gt, config);
   tdi["bmi-installation"] = CollationInformationBmiInstallation(gt, config);
   tdi["exports"] = CollationInformationExports(gt);
   tdi["config"] = config;
@@ -414,6 +429,15 @@
       export_info->Exports.push_back(exp);
     }
   }
+  auto const& database_info = tdi["database-info"];
+  if (database_info.isObject()) {
+    CxxModuleDatabaseInfo db_info;
+
+    db_info.TemplatePath = database_info["template-path"].asString();
+    db_info.Output = database_info["output"].asString();
+
+    export_info->DatabaseInfo = db_info;
+  }
   auto const& bmi_installation = tdi["bmi-installation"];
   if (bmi_installation.isObject()) {
     CxxModuleBmiInstall bmi_install;
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 293a4b7..ced18fd 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5921,6 +5921,27 @@
   return policyAnswer;
 }
 
+std::string cmGeneratorTarget::BuildDatabasePath(
+  std::string const& lang, std::string const& config) const
+{
+  // Check to see if the target wants it.
+  if (!this->GetPropertyAsBool("EXPORT_BUILD_DATABASE")) {
+    return {};
+  }
+  // Check to see if the generator supports it.
+  if (!this->GetGlobalGenerator()->SupportsBuildDatabase()) {
+    return {};
+  }
+
+  if (this->GetGlobalGenerator()->IsMultiConfig()) {
+    return cmStrCat(this->GetSupportDirectory(), '/', config, '/', lang,
+                    "_build_database.json");
+  }
+
+  return cmStrCat(this->GetSupportDirectory(), '/', lang,
+                  "_build_database.json");
+}
+
 void cmGeneratorTarget::BuildFileSetInfoCache(std::string const& config) const
 {
   auto& per_config = this->Configs[config];
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 210f0ab..b056733 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -1502,6 +1502,9 @@
   };
   CxxModuleSupport NeedCxxDyndep(std::string const& config) const;
 
+  std::string BuildDatabasePath(std::string const& lang,
+                                std::string const& config) const;
+
 private:
   void BuildFileSetInfoCache(std::string const& config) const;
   struct InfoByConfig
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 85dec72..355cb80 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -171,6 +171,8 @@
     return false;
   }
 
+  virtual bool SupportsBuildDatabase() const { return false; }
+
   virtual bool IsGNUMakeJobServerAware() const { return false; }
 
   bool Compute();
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json
index 4bb2455..dfca73e 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json
@@ -38,6 +38,7 @@
       "visibility": "PRIVATE"
     }
   },
+  "database-info": null,
   "dir-cur-bld": "<BINARY_DIR>",
   "dir-cur-src": "<SOURCE_DIR>",
   "dir-top-bld": "<BINARY_DIR>",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json
index 364bce2..20f164a 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json
@@ -38,6 +38,7 @@
       "visibility": "PUBLIC"
     }
   },
+  "database-info": null,
   "dir-cur-bld": "<BINARY_DIR>",
   "dir-cur-src": "<SOURCE_DIR>",
   "dir-top-bld": "<BINARY_DIR>",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json
index 45cd8ab..235e17d 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json
@@ -33,6 +33,7 @@
       "visibility": "PRIVATE"
     }
   },
+  "database-info": null,
   "dir-cur-bld": "<BINARY_DIR>",
   "dir-cur-src": "<SOURCE_DIR>",
   "dir-top-bld": "<BINARY_DIR>",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json
index 43a4e4f..ed19dd8 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json
@@ -33,6 +33,7 @@
       "visibility": "PUBLIC"
     }
   },
+  "database-info": null,
   "dir-cur-bld": "<BINARY_DIR>",
   "dir-cur-src": "<SOURCE_DIR>",
   "dir-top-bld": "<BINARY_DIR>",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-private.json
index 03e2018..22005a2 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-private.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-private.json
@@ -33,6 +33,7 @@
       "visibility": "PRIVATE"
     }
   },
+  "database-info": null,
   "dir-cur-bld": "<BINARY_DIR>",
   "dir-cur-src": "<SOURCE_DIR>",
   "dir-top-bld": "<BINARY_DIR>",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-public.json
index 4128252..e9d4852 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-public.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-public.json
@@ -33,6 +33,7 @@
       "visibility": "PUBLIC"
     }
   },
+  "database-info": null,
   "dir-cur-bld": "<BINARY_DIR>",
   "dir-cur-src": "<SOURCE_DIR>",
   "dir-top-bld": "<BINARY_DIR>",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json
index f4e19f4..571998f 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json
@@ -33,6 +33,7 @@
       "visibility": "PRIVATE"
     }
   },
+  "database-info": null,
   "dir-cur-bld": "<BINARY_DIR>",
   "dir-cur-src": "<SOURCE_DIR>",
   "dir-top-bld": "<BINARY_DIR>",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json
index 9604ba2..781b988 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json
@@ -33,6 +33,7 @@
       "visibility": "PUBLIC"
     }
   },
+  "database-info": null,
   "dir-cur-bld": "<BINARY_DIR>",
   "dir-cur-src": "<SOURCE_DIR>",
   "dir-top-bld": "<BINARY_DIR>",