瀏覽代碼

Merge topic 'build-databases'

e77655555c cmExperimental: gate build database support behind a flag
23cbeb5035 ci: enable `build_database` CXXModules tests
6863c1d823 Tests/CXXModules: add tests for module commands
123107c1a4 Tests/CXXModules: add support for running targets under a given config
438038b5e1 Tests/CXXModules: support building specific targets of example trees
84bc710d84 cmGlobalGenerator: generate build database files for targets
670f753f24 cmDyndepCollation: write build database metadata
dcf9a66ffe cxxmodules: plumb control data for exporting build databases
...

Acked-by: Kitware Robot <[email protected]>
Merge-request: !9708
Brad King 1 年之前
父節點
當前提交
2daeb0b504
共有 93 個文件被更改,包括 5367 次插入106 次删除
  1. 1 1
      .gitlab/ci/configure_fedora40_ninja.cmake
  2. 1 1
      .gitlab/ci/configure_fedora40_ninja_clang.cmake
  3. 1 1
      .gitlab/ci/configure_fedora40_ninja_multi.cmake
  4. 1 1
      .gitlab/ci/configure_fedora40_ninja_multi_clang.cmake
  5. 1 1
      .gitlab/ci/configure_windows_clang_ninja.cmake
  6. 1 1
      .gitlab/ci/configure_windows_msvc_cxx_modules_common.cmake
  7. 21 0
      Help/dev/experimental.rst
  8. 17 0
      Help/envvar/CMAKE_EXPORT_BUILD_DATABASE.rst
  9. 2 0
      Help/guide/user-interaction/index.rst
  10. 1 0
      Help/manual/cmake-env-variables.7.rst
  11. 1 0
      Help/manual/cmake-properties.7.rst
  12. 1 0
      Help/manual/cmake-variables.7.rst
  13. 15 0
      Help/prop_tgt/EXPORT_BUILD_DATABASE.rst
  14. 8 0
      Help/release/dev/module-cdb.rst
  15. 86 0
      Help/variable/CMAKE_EXPORT_BUILD_DATABASE.rst
  16. 7 0
      Modules/CMakeGenericSystem.cmake
  17. 3 0
      Source/CMakeLists.txt
  18. 581 0
      Source/cmBuildDatabase.cxx
  19. 61 0
      Source/cmBuildDatabase.h
  20. 188 39
      Source/cmDyndepCollation.cxx
  21. 9 0
      Source/cmExperimental.cxx
  22. 1 0
      Source/cmExperimental.h
  23. 473 0
      Source/cmGeneratorTarget.cxx
  24. 63 0
      Source/cmGeneratorTarget.h
  25. 228 0
      Source/cmGlobalGenerator.cxx
  26. 26 0
      Source/cmGlobalGenerator.h
  27. 5 0
      Source/cmGlobalNinjaGenerator.cxx
  28. 3 0
      Source/cmGlobalNinjaGenerator.h
  29. 15 2
      Source/cmMakefile.cxx
  30. 23 5
      Source/cmMakefile.h
  31. 16 0
      Source/cmNinjaTargetGenerator.cxx
  32. 16 0
      Source/cmTarget.cxx
  33. 1 0
      Source/cmTarget.h
  34. 8 0
      Source/cmcmd.cxx
  35. 2 0
      Tests/RunCMake/CXXModules/Inspect.cmake
  36. 39 0
      Tests/RunCMake/CXXModules/NinjaDependInfoCompileDatabase-check.cmake
  37. 4 0
      Tests/RunCMake/CXXModules/NinjaDependInfoCompileDatabase-stderr.txt
  38. 54 0
      Tests/RunCMake/CXXModules/NinjaDependInfoCompileDatabase.cmake
  39. 69 45
      Tests/RunCMake/CXXModules/RunCMakeTest.cmake
  40. 65 1
      Tests/RunCMake/CXXModules/check-json.cmake
  41. 81 0
      Tests/RunCMake/CXXModules/examples/build-database-check.cmake
  42. 300 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-all-multi.json
  43. 153 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-all.json
  44. 153 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-config.json
  45. 153 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx-config.json
  46. 300 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx-multi.json
  47. 153 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx.json
  48. 278 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-all-multi.json
  49. 142 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-all.json
  50. 142 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-config.json
  51. 142 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx-config.json
  52. 278 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx-multi.json
  53. 142 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx.json
  54. 59 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-target.json
  55. 153 0
      Tests/RunCMake/CXXModules/examples/expect/export-build-database-target.json
  56. 19 0
      Tests/RunCMake/CXXModules/examples/export-build-database-build-check.cmake
  57. 19 0
      Tests/RunCMake/CXXModules/examples/export-build-database-check.cmake
  58. 39 0
      Tests/RunCMake/CXXModules/examples/export-build-database-setup.cmake
  59. 4 0
      Tests/RunCMake/CXXModules/examples/export-build-database-stderr.txt
  60. 21 0
      Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database-check.cmake
  61. 21 0
      Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database/CXX-check.cmake
  62. 14 0
      Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database/CXX/Debug-check.cmake
  63. 14 0
      Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database/CXX/Release-Release-check.cmake
  64. 14 0
      Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database/Debug-check.cmake
  65. 14 0
      Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database/Release-Release-check.cmake
  66. 85 0
      Tests/RunCMake/CXXModules/examples/export-build-database/CMakeLists.txt
  67. 0 0
      Tests/RunCMake/CXXModules/examples/export-build-database/dep_interface_include/anchor
  68. 6 0
      Tests/RunCMake/CXXModules/examples/export-build-database/importable.cxx
  69. 6 0
      Tests/RunCMake/CXXModules/examples/export-build-database/lib.cxx
  70. 0 0
      Tests/RunCMake/CXXModules/examples/export-build-database/target_interface_include/anchor
  71. 0 0
      Tests/RunCMake/CXXModules/examples/export-build-database/target_public_include/anchor
  72. 18 0
      Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-build-check.cmake
  73. 18 0
      Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-check.cmake
  74. 4 0
      Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-stderr.txt
  75. 22 0
      Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database-check.cmake
  76. 22 0
      Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX-check.cmake
  77. 19 0
      Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX/Debug-check.cmake
  78. 19 0
      Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX/Release-Release-check.cmake
  79. 19 0
      Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/Debug-check.cmake
  80. 19 0
      Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/Release-check.cmake
  81. 22 0
      Tests/RunCMake/CXXModules/examples/import-modules/CMakeLists.txt
  82. 3 1
      Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json
  83. 3 1
      Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json
  84. 51 0
      Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-private.json
  85. 51 0
      Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-public.json
  86. 3 1
      Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json
  87. 3 1
      Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json
  88. 3 1
      Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-private.json
  89. 3 1
      Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-public.json
  90. 20 1
      Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json
  91. 20 1
      Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json
  92. 1 0
      Tests/RunCMake/property_init/CompileSources.cmake
  93. 1 0
      bootstrap

+ 1 - 1
.gitlab/ci/configure_fedora40_ninja.cmake

@@ -2,7 +2,7 @@ set(CMake_TEST_GUI "ON" CACHE BOOL "")
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_ISPC "ON" CACHE STRING "")
 endif()
-set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL_BAD "https://badtls-expired.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")

+ 1 - 1
.gitlab/ci/configure_fedora40_ninja_clang.cmake

@@ -1,3 +1,3 @@
-set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database" CACHE STRING "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora40_common_clang.cmake")

+ 1 - 1
.gitlab/ci/configure_fedora40_ninja_multi.cmake

@@ -1,6 +1,6 @@
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_ISPC "ON" CACHE STRING "")
 endif()
-set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database" CACHE STRING "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")

+ 1 - 1
.gitlab/ci/configure_fedora40_ninja_multi_clang.cmake

@@ -1,3 +1,3 @@
-set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database" CACHE STRING "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora40_common_clang.cmake")

+ 1 - 1
.gitlab/ci/configure_windows_clang_ninja.cmake

@@ -1,4 +1,4 @@
 if("$ENV{CMAKE_CI_BUILD_NAME}" MATCHES "(^|_)gnu(_|$)")
-  set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly" CACHE STRING "")
+  set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database" CACHE STRING "")
 endif()
 include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_clang_common.cmake")

+ 1 - 1
.gitlab/ci/configure_windows_msvc_cxx_modules_common.cmake

@@ -1 +1 @@
-set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,shared,export_bmi,install_bmi,bmionly,import_std23" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,shared,export_bmi,install_bmi,bmionly,import_std23,build_database" CACHE STRING "")

+ 21 - 0
Help/dev/experimental.rst

@@ -80,3 +80,24 @@ When activated, this experimental feature provides the following:
 
 .. _CPS: https://cps-org.github.io/cps/
 .. |CPS| replace:: Common Package Specification
+
+Build database support
+======================
+
+In order to activate support for exporting build databases, set
+
+* variable ``CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE`` to
+* value ``4bd552e2-b7fb-429a-ab23-c83ef53f3f13``.
+
+This UUID may change in future versions of CMake.  Be sure to use the value
+documented here by the source tree of the version of CMake with which you are
+experimenting.
+
+When activated, this experimental feature provides the following:
+
+* The :prop_tgt:`EXPORT_BUILD_DATABASE` target property and its initializing
+  variable :variable:`CMAKE_EXPORT_BUILD_DATABASE` and environment variable
+  :envvar:`CMAKE_EXPORT_BUILD_DATABASE`.
+
+* Targets with the property set to a true value will have their C++ build
+  information exported to the build database.

+ 17 - 0
Help/envvar/CMAKE_EXPORT_BUILD_DATABASE.rst

@@ -0,0 +1,17 @@
+CMAKE_EXPORT_BUILD_DATABASE
+---------------------------
+
+.. versionadded:: 3.31
+
+.. include:: ENV_VAR.txt
+
+The default value for :variable:`CMAKE_EXPORT_BUILD_DATABASE` when there is no
+explicit configuration given on the first run while creating a new build tree.
+On later runs in an existing build tree the value persists in the cache as
+:variable:`CMAKE_EXPORT_BUILD_DATABASE`.
+
+.. note ::
+
+   This variable is meaningful only when experimental support for build
+   databases has been enabled by the
+   ``CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE`` gate.

+ 2 - 0
Help/guide/user-interaction/index.rst

@@ -300,6 +300,8 @@ the table below:
                                             commands used without a type
  :variable:`CMAKE_EXPORT_COMPILE_COMMANDS`  Generate a ``compile_commands.json``
                                             file for use with clang-based tools
+ :variable:`CMAKE_EXPORT_BUILD_DATABASE`    Generate a ``build_database.json``
+                                            file for use with clang-based tools
 ========================================== ============================================================
 
 Other project-specific variables may be available

+ 1 - 0
Help/manual/cmake-env-variables.7.rst

@@ -47,6 +47,7 @@ Environment Variables that Control the Build
    /envvar/CMAKE_CONFIG_TYPE
    /envvar/CMAKE_CONFIGURATION_TYPES
    /envvar/CMAKE_CROSSCOMPILING_EMULATOR
+   /envvar/CMAKE_EXPORT_BUILD_DATABASE
    /envvar/CMAKE_EXPORT_COMPILE_COMMANDS
    /envvar/CMAKE_GENERATOR
    /envvar/CMAKE_GENERATOR_INSTANCE

+ 1 - 0
Help/manual/cmake-properties.7.rst

@@ -217,6 +217,7 @@ Properties on Targets
    /prop_tgt/EXCLUDE_FROM_ALL
    /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD
    /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG
+   /prop_tgt/EXPORT_BUILD_DATABASE
    /prop_tgt/EXPORT_COMPILE_COMMANDS
    /prop_tgt/EXPORT_FIND_PACKAGE_NAME
    /prop_tgt/EXPORT_NAME

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -195,6 +195,7 @@ Variables that Change Behavior
    /variable/CMAKE_ERROR_DEPRECATED
    /variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
    /variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO
+   /variable/CMAKE_EXPORT_BUILD_DATABASE
    /variable/CMAKE_EXPORT_COMPILE_COMMANDS
    /variable/CMAKE_EXPORT_PACKAGE_REGISTRY
    /variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY

+ 15 - 0
Help/prop_tgt/EXPORT_BUILD_DATABASE.rst

@@ -0,0 +1,15 @@
+EXPORT_BUILD_DATABASE
+---------------------
+
+.. versionadded:: 3.31
+
+Enable/Disable output of a build database for a target.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_EXPORT_BUILD_DATABASE` if it is set when a target is created.
+
+.. note ::
+
+   This property is meaningful only when experimental support for build
+   databases has been enabled by the
+   ``CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE`` gate.

+ 8 - 0
Help/release/dev/module-cdb.rst

@@ -0,0 +1,8 @@
+module-cdb
+==========
+
+* Targets with C++ modules may now export their module compile commands using
+  the :prop_tgt:`EXPORT_BUILD_DATABASE` target property. This is initialized
+  with the :variable:`CMAKE_EXPORT_BUILD_DATABASE` variable which is itself
+  initialized using the :envvar:`CMAKE_EXPORT_BUILD_DATABASE` environment
+  variable. Only supported with the :ref:`Ninja Generators`.

+ 86 - 0
Help/variable/CMAKE_EXPORT_BUILD_DATABASE.rst

@@ -0,0 +1,86 @@
+CMAKE_EXPORT_BUILD_DATABASE
+---------------------------
+
+.. versionadded:: 3.31
+
+.. note ::
+
+   This variable is meaningful only when experimental support for build
+   databases has been enabled by the
+   ``CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE`` gate.
+
+Enable/Disable output of module compile commands during the build.
+
+If enabled, generates a ``build_database.json`` file containing the
+information necessary to compile a target's C++ module sources with any
+tooling. The format of the JSON file looks like:
+
+.. code-block:: javascript
+
+  {
+    "version": 1,
+    "revision": 0,
+    "sets": [
+      {
+        "family-name" : "export_build_database",
+        "name" : "export_build_database@Debug",
+        "translation-units" : [
+          {
+            "arguments": [
+              "/path/to/compiler",
+              "...",
+            ],
+            "baseline-arguments" :
+            [
+              "...",
+            ],
+            "local-arguments" :
+            [
+              "...",
+            ],
+            "object": "CMakeFiles/target.dir/source.cxx.o",
+            "private": true,
+            "provides": {
+              "importable": "path/to/bmi"
+            },
+            "requires" : [],
+            "source": "path/to/source.cxx",
+            "work-directory": "/path/to/working/directory"
+          }
+        ],
+        "visible-sets" : []
+      }
+    ]
+  }
+
+This is initialized by the :envvar:`CMAKE_EXPORT_BUILD_DATABASE` environment
+variable, and initializes the :prop_tgt:`EXPORT_BUILD_DATABASE` target
+property for all targets.
+
+.. note::
+  This option is implemented only by the :ref:`Ninja Generators`.  It is
+  ignored on other generators.
+
+When supported and enabled, numerous targets are created in order to make it
+possible to build a file containing just the commands that are needed for the
+tool in question.
+
+``cmake_build_database-<CONFIG>``
+  Writes ``build_database_<CONFIG>.json``. Writes a build database for the
+  entire build for the given configuration and all languages. Not available if
+  the configuration name is the empty string.
+
+``cmake_build_database-<LANG>-<CONFIG>``
+  Writes ``build_database_<LANG>_<CONFIG>.json``. Writes build database for
+  the entire build for the given configuration and language. Not available if
+  the configuration name is the empty string.
+
+``cmake_build_database-<LANG>``
+  Writes ``build_database_<LANG>.json``. Writes build database for the entire
+  build for the given language and all configurations. In a multi-config
+  generator, other build configuration database may be assumed to exist.
+
+``cmake_build_database``
+  Writes to ``build_database.json``. Writes build database for all languages
+  and configurations. In a multi-config generator, other build configuration
+  database may be assumed to exist.

+ 7 - 0
Modules/CMakeGenericSystem.cmake

@@ -78,6 +78,13 @@ if(NOT DEFINED CMAKE_EXPORT_COMPILE_COMMANDS AND CMAKE_GENERATOR MATCHES "Ninja|
   mark_as_advanced(CMAKE_EXPORT_COMPILE_COMMANDS)
 endif()
 
+if(NOT DEFINED CMAKE_EXPORT_BUILD_DATABASE AND CMAKE_GENERATOR MATCHES "Ninja")
+  set(CMAKE_EXPORT_BUILD_DATABASE "$ENV{CMAKE_EXPORT_BUILD_DATABASE}"
+    CACHE BOOL "Enable/Disable output of build database during the build."
+    )
+  mark_as_advanced(CMAKE_EXPORT_BUILD_DATABASE)
+endif()
+
 # GetDefaultWindowsPrefixBase
 #
 # Compute the base directory for CMAKE_INSTALL_PREFIX based on:

+ 3 - 0
Source/CMakeLists.txt

@@ -121,6 +121,8 @@ add_library(
   cmBinUtilsWindowsPELinker.h
   cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
   cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
+  cmBuildDatabase.cxx
+  cmBuildDatabase.h
   cmBuildOptions.h
   cmCacheManager.cxx
   cmCacheManager.h
@@ -140,6 +142,7 @@ add_library(
   cmCMakePresetsGraphReadJSONTestPresets.cxx
   cmCMakePresetsGraphReadJSONWorkflowPresets.cxx
   cmCommandArgumentParserHelper.cxx
+  cmCommandLineArgument.h
   cmCommonTargetGenerator.cxx
   cmCommonTargetGenerator.h
   cmComputeComponentGraph.cxx

+ 581 - 0
Source/cmBuildDatabase.cxx

@@ -0,0 +1,581 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmBuildDatabase.h"
+
+#include <cstdlib>
+#include <set>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmComputeLinkInformation.h"
+#include "cmFileSet.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+
+std::string PlaceholderName = "<__CMAKE_UNKNOWN>";
+
+}
+
+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;
+
+  mcdb["version"] = 1;
+  mcdb["revision"] = 0;
+
+  Json::Value& sets = mcdb["sets"] = Json::arrayValue;
+
+  for (auto const& Set_ : this->Sets) {
+    Json::Value set = Json::objectValue;
+
+    set["name"] = Set_.Name;
+    set["family-name"] = Set_.FamilyName;
+
+    Json::Value& visible_sets = set["visible-sets"] = Json::arrayValue;
+    for (auto const& VisibleSet : Set_.VisibleSets) {
+      visible_sets.append(VisibleSet);
+    }
+
+    Json::Value& tus = set["translation-units"] = Json::arrayValue;
+    for (auto const& TranslationUnit_ : Set_.TranslationUnits) {
+      Json::Value tu = Json::objectValue;
+
+      if (!TranslationUnit_.WorkDirectory.empty()) {
+        tu["work-directory"] = TranslationUnit_.WorkDirectory;
+      }
+      tu["source"] = TranslationUnit_.Source;
+      if (TranslationUnit_.Object) {
+        tu["object"] = *TranslationUnit_.Object;
+      }
+      tu["private"] = TranslationUnit_.Private;
+
+      Json::Value& reqs = tu["requires"] = Json::arrayValue;
+      for (auto const& Require : TranslationUnit_.Requires) {
+        reqs.append(Require);
+      }
+
+      Json::Value& provides = tu["provides"] = Json::objectValue;
+      for (auto const& Provide : TranslationUnit_.Provides) {
+        provides[Provide.first] = Provide.second;
+      }
+
+      Json::Value& baseline_arguments = tu["baseline-arguments"] =
+        Json::arrayValue;
+      for (auto const& BaselineArgument : TranslationUnit_.BaselineArguments) {
+        baseline_arguments.append(BaselineArgument);
+      }
+
+      Json::Value& local_arguments = tu["local-arguments"] = Json::arrayValue;
+      for (auto const& LocalArgument : TranslationUnit_.LocalArguments) {
+        local_arguments.append(LocalArgument);
+      }
+
+      Json::Value& arguments = tu["arguments"] = Json::arrayValue;
+      for (auto const& Argument : TranslationUnit_.Arguments) {
+        arguments.append(Argument);
+      }
+
+      tus.append(tu);
+    }
+
+    sets.append(set);
+  }
+
+  cmGeneratedFileStream mcdbf(path);
+  mcdbf << mcdb;
+}
+
+static bool ParseFilename(Json::Value const& val, std::string& result)
+{
+  if (val.isString()) {
+    result = val.asString();
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+#define PARSE_BLOB(val, res)                                                  \
+  do {                                                                        \
+    if (!ParseFilename(val, res)) {                                           \
+      cmSystemTools::Error(cmStrCat("-E cmake_module_compile_db failed to ",  \
+                                    "parse ", path, ": invalid blob"));       \
+      return {};                                                              \
+    }                                                                         \
+  } while (0)
+
+#define PARSE_FILENAME(val, res, make_full)                                   \
+  do {                                                                        \
+    if (!ParseFilename(val, res)) {                                           \
+      cmSystemTools::Error(cmStrCat("-E cmake_module_compile_db failed to ",  \
+                                    "parse ", path, ": invalid filename"));   \
+      return {};                                                              \
+    }                                                                         \
+                                                                              \
+    if (make_full && work_directory && !work_directory->empty() &&            \
+        !cmSystemTools::FileIsFullPath(res)) {                                \
+      res = cmStrCat(*work_directory, '/', res);                              \
+    }                                                                         \
+  } while (0)
+
+std::unique_ptr<cmBuildDatabase> cmBuildDatabase::Load(std::string const& path)
+{
+  Json::Value mcdb;
+  {
+    cmsys::ifstream mcdbf(path.c_str(), std::ios::in | std::ios::binary);
+    Json::Reader reader;
+    if (!reader.parse(mcdbf, mcdb, false)) {
+      cmSystemTools::Error(
+        cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                 reader.getFormattedErrorMessages()));
+      return {};
+    }
+  }
+
+  Json::Value const& version = mcdb["version"];
+  if (version.asUInt() > 1) {
+    cmSystemTools::Error(
+      cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+               ": version ", version.asString()));
+    return {};
+  }
+
+  auto db = cm::make_unique<cmBuildDatabase>();
+
+  Json::Value const& sets = mcdb["sets"];
+  if (sets.isArray()) {
+    for (auto const& set : sets) {
+      Set Set_;
+
+      Json::Value const& name = set["name"];
+      if (!name.isString()) {
+        cmSystemTools::Error(
+          cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                   ": name is not a string"));
+        return {};
+      }
+      Set_.Name = name.asString();
+
+      Json::Value const& family_name = set["family-name"];
+      if (!family_name.isString()) {
+        cmSystemTools::Error(
+          cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                   ": family-name is not a string"));
+        return {};
+      }
+      Set_.FamilyName = family_name.asString();
+
+      Json::Value const& visible_sets = set["visible-sets"];
+      if (!visible_sets.isArray()) {
+        cmSystemTools::Error(
+          cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                   ": visible-sets is not an array"));
+        return {};
+      }
+      for (auto const& visible_set : visible_sets) {
+        if (!visible_set.isString()) {
+          cmSystemTools::Error(
+            cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                     ": a visible-sets item is not a string"));
+          return {};
+        }
+
+        Set_.VisibleSets.emplace_back(visible_set.asString());
+      }
+
+      Json::Value const& translation_units = set["translation-units"];
+      if (!translation_units.isArray()) {
+        cmSystemTools::Error(
+          cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                   ": translation-units is not an array"));
+        return {};
+      }
+      for (auto const& translation_unit : translation_units) {
+        if (!translation_unit.isObject()) {
+          cmSystemTools::Error(
+            cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                     ": a translation-units item is not an object"));
+          return {};
+        }
+
+        TranslationUnit TranslationUnit_;
+
+        cm::optional<std::string> work_directory;
+        Json::Value const& workdir = translation_unit["work-directory"];
+        if (workdir.isString()) {
+          PARSE_BLOB(workdir, TranslationUnit_.WorkDirectory);
+          work_directory = TranslationUnit_.WorkDirectory;
+        } else if (!workdir.isNull()) {
+          cmSystemTools::Error(
+            cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                     ": work-directory is not a string"));
+          return {};
+        }
+
+        Json::Value const& source = translation_unit["source"];
+        PARSE_FILENAME(source, TranslationUnit_.Source, true);
+
+        if (translation_unit.isMember("object")) {
+          Json::Value const& object = translation_unit["object"];
+          if (!object.isNull()) {
+            TranslationUnit_.Object = "";
+            PARSE_FILENAME(object, *TranslationUnit_.Object, false);
+          }
+        }
+
+        if (translation_unit.isMember("private")) {
+          Json::Value const& priv = translation_unit["private"];
+          if (!priv.isBool()) {
+            cmSystemTools::Error(
+              cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                       ": private is not a boolean"));
+            return {};
+          }
+          TranslationUnit_.Private = priv.asBool();
+        }
+
+        if (translation_unit.isMember("requires")) {
+          Json::Value const& reqs = translation_unit["requires"];
+          if (!reqs.isArray()) {
+            cmSystemTools::Error(
+              cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                       ": requires is not an array"));
+            return {};
+          }
+
+          for (auto const& require : reqs) {
+            if (!require.isString()) {
+              cmSystemTools::Error(
+                cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                         ": a requires item is not a string"));
+              return {};
+            }
+
+            TranslationUnit_.Requires.emplace_back(require.asString());
+          }
+        }
+
+        if (translation_unit.isMember("provides")) {
+          Json::Value const& provides = translation_unit["provides"];
+          if (!provides.isObject()) {
+            cmSystemTools::Error(
+              cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                       ": provides is not an object"));
+            return {};
+          }
+
+          for (auto i = provides.begin(); i != provides.end(); ++i) {
+            if (!i->isString()) {
+              cmSystemTools::Error(
+                cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                         ": a provides value is not a string"));
+              return {};
+            }
+
+            TranslationUnit_.Provides[i.key().asString()] = i->asString();
+          }
+        }
+
+        if (translation_unit.isMember("baseline-arguments")) {
+          Json::Value const& baseline_arguments =
+            translation_unit["baseline-arguments"];
+          if (!baseline_arguments.isArray()) {
+            cmSystemTools::Error(
+              cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                       ": baseline_arguments is not an array"));
+            return {};
+          }
+
+          for (auto const& baseline_argument : baseline_arguments) {
+            if (baseline_argument.isString()) {
+              TranslationUnit_.BaselineArguments.emplace_back(
+                baseline_argument.asString());
+            } else {
+              cmSystemTools::Error(
+                cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                         ": a baseline argument is not a string"));
+              return {};
+            }
+          }
+        }
+
+        if (translation_unit.isMember("local-arguments")) {
+          Json::Value const& local_arguments =
+            translation_unit["local-arguments"];
+          if (!local_arguments.isArray()) {
+            cmSystemTools::Error(
+              cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                       ": local_arguments is not an array"));
+            return {};
+          }
+
+          for (auto const& local_argument : local_arguments) {
+            if (local_argument.isString()) {
+              TranslationUnit_.LocalArguments.emplace_back(
+                local_argument.asString());
+            } else {
+              cmSystemTools::Error(
+                cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                         ": a local argument is not a string"));
+              return {};
+            }
+          }
+        }
+
+        if (translation_unit.isMember("arguments")) {
+          Json::Value const& arguments = translation_unit["arguments"];
+          if (!arguments.isArray()) {
+            cmSystemTools::Error(
+              cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                       ": arguments is not an array"));
+            return {};
+          }
+
+          for (auto const& argument : arguments) {
+            if (argument.isString()) {
+              TranslationUnit_.Arguments.emplace_back(argument.asString());
+            } else {
+              cmSystemTools::Error(
+                cmStrCat("-E cmake_module_compile_db failed to parse ", path,
+                         ": an argument is not a string"));
+              return {};
+            }
+          }
+        }
+
+        Set_.TranslationUnits.emplace_back(std::move(TranslationUnit_));
+      }
+
+      db->Sets.emplace_back(std::move(Set_));
+    }
+  }
+
+  return db;
+}
+
+cmBuildDatabase cmBuildDatabase::Merge(
+  std::vector<cmBuildDatabase> const& components)
+{
+  cmBuildDatabase db;
+
+  for (auto const& component : components) {
+    db.Sets.insert(db.Sets.end(), component.Sets.begin(),
+                   component.Sets.end());
+  }
+
+  return db;
+}
+
+cmBuildDatabase cmBuildDatabase::ForTarget(cmGeneratorTarget* gt,
+                                           std::string const& config)
+{
+  cmBuildDatabase db;
+
+  Set set;
+  set.Name = cmStrCat(gt->GetName(), '@', config);
+  set.FamilyName = gt->GetFamilyName();
+  if (auto* cli = gt->GetLinkInformation(config)) {
+    std::set<cmGeneratorTarget const*> emitted;
+    std::vector<cmGeneratorTarget const*> targets;
+    for (auto const& item : cli->GetItems()) {
+      auto const* linkee = item.Target;
+      if (linkee && linkee->HaveCxx20ModuleSources() &&
+          !linkee->IsImported() && emitted.insert(linkee).second) {
+        set.VisibleSets.push_back(cmStrCat(linkee->GetName(), '@', config));
+      }
+    }
+  }
+
+  for (auto const& sfbt : gt->GetSourceFiles(config)) {
+    auto const* sf = sfbt.Value;
+
+    bool isCXXModule = false;
+    bool isPrivate = true;
+    if (sf->GetLanguage() != "CXX"_s) {
+      auto const* fs = gt->GetFileSetForSource(config, sf);
+      if (fs && fs->GetType() == "CXX_MODULES"_s) {
+        isCXXModule = true;
+        isPrivate = !cmFileSetVisibilityIsForInterface(fs->GetVisibility());
+      }
+    }
+
+    TranslationUnit tu;
+
+    // FIXME: Makefiles will want this to be the current working directory.
+    tu.WorkDirectory = gt->GetLocalGenerator()->GetBinaryDirectory();
+    tu.Source = sf->GetFullPath();
+    if (!gt->IsSynthetic()) {
+      auto* gg = gt->GetGlobalGenerator();
+      std::string const objectDir = gg->ConvertToOutputPath(
+        cmStrCat(gt->GetSupportDirectory(), gg->GetConfigDirectory(config)));
+      std::string const objectFileName = gt->GetObjectName(sf);
+      tu.Object = cmStrCat(objectDir, '/', objectFileName);
+    }
+    if (isCXXModule) {
+      tu.Provides[PlaceholderName] = PlaceholderName;
+    }
+
+    cmGeneratorTarget::ClassifiedFlags classifiedFlags =
+      gt->GetClassifiedFlagsForSource(sf, config);
+    for (auto const& classifiedFlag : classifiedFlags) {
+      if (classifiedFlag.Classification ==
+          cmGeneratorTarget::FlagClassification::BaselineFlag) {
+        tu.BaselineArguments.push_back(classifiedFlag.Flag);
+        tu.LocalArguments.push_back(classifiedFlag.Flag);
+      } else if (classifiedFlag.Classification ==
+                 cmGeneratorTarget::FlagClassification::PrivateFlag) {
+        tu.LocalArguments.push_back(classifiedFlag.Flag);
+      }
+      tu.Arguments.push_back(classifiedFlag.Flag);
+    }
+    tu.Private = isPrivate;
+
+    set.TranslationUnits.emplace_back(std::move(tu));
+  }
+
+  db.Sets.emplace_back(std::move(set));
+
+  return db;
+}
+
+int cmcmd_cmake_module_compile_db(
+  std::vector<std::string>::const_iterator argBeg,
+  std::vector<std::string>::const_iterator argEnd)
+{
+  const std::string* command = nullptr;
+  const std::string* output = nullptr;
+  std::vector<const std::string*> inputs;
+
+  bool next_is_output = false;
+  for (auto i = argBeg; i != argEnd; ++i) {
+    // The first argument is always the command.
+    if (!command) {
+      command = &(*i);
+      continue;
+    }
+
+    if (*i == "-o"_s) {
+      next_is_output = true;
+      continue;
+    }
+    if (next_is_output) {
+      if (output) {
+        cmSystemTools::Error(
+          "-E cmake_module_compile_db only supports one output file");
+        return EXIT_FAILURE;
+      }
+
+      output = &(*i);
+      next_is_output = false;
+      continue;
+    }
+
+    inputs.emplace_back(&(*i));
+  }
+
+  if (!command) {
+    cmSystemTools::Error("-E cmake_module_compile_db requires a subcommand");
+    return EXIT_FAILURE;
+  }
+
+  int ret = EXIT_SUCCESS;
+
+  if (*command == "verify"_s) {
+    if (output) {
+      cmSystemTools::Error(
+        "-E cmake_module_compile_db verify does not support an output");
+      return EXIT_FAILURE;
+    }
+
+    for (auto const* i : inputs) {
+      auto db = cmBuildDatabase::Load(*i);
+      if (!db) {
+        cmSystemTools::Error(cmStrCat("failed to verify ", *i));
+        ret = EXIT_FAILURE;
+      }
+    }
+  } else if (*command == "merge"_s) {
+    if (!output) {
+      cmSystemTools::Error(
+        "-E cmake_module_compile_db verify requires an output");
+      return EXIT_FAILURE;
+    }
+
+    std::vector<cmBuildDatabase> dbs;
+
+    for (auto const* i : inputs) {
+      auto db = cmBuildDatabase::Load(*i);
+      if (!db) {
+        cmSystemTools::Error(cmStrCat("failed to read ", *i));
+        return EXIT_FAILURE;
+      }
+
+      dbs.emplace_back(std::move(*db));
+    }
+
+    auto db = cmBuildDatabase::Merge(dbs);
+    db.Write(*output);
+  } else {
+    cmSystemTools::Error(
+      cmStrCat("-E cmake_module_compile_db unknown subcommand ", *command));
+    return EXIT_FAILURE;
+  }
+
+  return ret;
+}

+ 61 - 0
Source/cmBuildDatabase.h

@@ -0,0 +1,61 @@
+/* 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 <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+
+class cmGeneratorTarget;
+
+class cmBuildDatabase
+{
+public:
+  struct TranslationUnit
+  {
+    std::string WorkDirectory;
+    std::string Source;
+    cm::optional<std::string> Object;
+    std::vector<std::string> Requires;
+    std::map<std::string, std::string> Provides;
+    std::vector<std::string> BaselineArguments;
+    std::vector<std::string> LocalArguments;
+    std::vector<std::string> Arguments;
+    bool Private = false;
+  };
+
+  struct Set
+  {
+    std::string Name;
+    std::string FamilyName;
+    std::vector<std::string> VisibleSets;
+    std::vector<TranslationUnit> TranslationUnits;
+  };
+
+  cmBuildDatabase();
+  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);
+  static cmBuildDatabase Merge(std::vector<cmBuildDatabase> const& components);
+  static cmBuildDatabase ForTarget(cmGeneratorTarget* gt,
+                                   std::string const& config);
+
+private:
+  std::vector<Set> Sets;
+};

+ 188 - 39
Source/cmDyndepCollation.cxx

@@ -16,6 +16,7 @@
 
 #include <cm3p/json/value.h>
 
+#include "cmBuildDatabase.h"
 #include "cmExportBuildFileGenerator.h"
 #include "cmExportSet.h"
 #include "cmFileSet.h"
@@ -39,13 +40,55 @@
 
 namespace {
 
-Json::Value CollationInformationCxxModules(
-  cmGeneratorTarget const* gt, std::string const& config,
-  cmDyndepGeneratorCallbacks const& cb)
+struct TdiSourceInfo
 {
+  Json::Value Sources;
+  Json::Value CxxModules;
+};
+
+TdiSourceInfo CollationInformationSources(cmGeneratorTarget const* gt,
+                                          std::string const& config,
+                                          cmDyndepGeneratorCallbacks const& cb)
+{
+  TdiSourceInfo info;
   cmTarget const* tgt = gt->Target;
   auto all_file_sets = tgt->GetAllFileSetNames();
-  Json::Value tdi_cxx_module_info = Json::objectValue;
+  Json::Value& tdi_sources = info.Sources = Json::objectValue;
+  Json::Value& tdi_cxx_module_info = info.CxxModules = Json::objectValue;
+
+  enum class CompileType
+  {
+    ObjectAndBmi,
+    BmiOnly,
+  };
+  std::map<std::string, std::pair<cmSourceFile const*, CompileType>> sf_map;
+  {
+    auto fill_sf_map = [gt, tgt, &sf_map](cmSourceFile const* sf,
+                                          CompileType type) {
+      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."));
+        return;
+      }
+      sf_map[full_path] = std::make_pair(sf, type);
+    };
+
+    std::vector<cmSourceFile const*> objectSources;
+    gt->GetObjectSources(objectSources, config);
+    for (auto const* sf : objectSources) {
+      fill_sf_map(sf, CompileType::ObjectAndBmi);
+    }
+
+    std::vector<cmSourceFile const*> cxxModuleSources;
+    gt->GetCxxModuleSources(cxxModuleSources, config);
+    for (auto const* sf : cxxModuleSources) {
+      fill_sf_map(sf, CompileType::BmiOnly);
+    }
+  }
+
   for (auto const& file_set_name : all_file_sets) {
     auto const* file_set = tgt->GetFileSet(file_set_name);
     if (!file_set) {
@@ -73,39 +116,6 @@ Json::Value CollationInformationCxxModules(
                                   gt->LocalGenerator, config, gt);
     }
 
-    enum class CompileType
-    {
-      ObjectAndBmi,
-      BmiOnly,
-    };
-    std::map<std::string, std::pair<cmSourceFile const*, CompileType>> sf_map;
-    {
-      auto fill_sf_map = [gt, tgt, &sf_map](cmSourceFile const* sf,
-                                            CompileType type) {
-        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."));
-          return;
-        }
-        sf_map[full_path] = std::make_pair(sf, type);
-      };
-
-      std::vector<cmSourceFile const*> objectSources;
-      gt->GetObjectSources(objectSources, config);
-      for (auto const* sf : objectSources) {
-        fill_sf_map(sf, CompileType::ObjectAndBmi);
-      }
-
-      std::vector<cmSourceFile const*> cxxModuleSources;
-      gt->GetCxxModuleSources(cxxModuleSources, config);
-      for (auto const* sf : cxxModuleSources) {
-        fill_sf_map(sf, CompileType::BmiOnly);
-      }
-    }
-
     Json::Value fs_dest = Json::nullValue;
     for (auto const& ig : gt->Makefile->GetInstallGenerators()) {
       if (auto const* fsg =
@@ -134,6 +144,8 @@ Json::Value CollationInformationCxxModules(
         auto const* sf = lookup->second.first;
         CompileType const ct = lookup->second.second;
 
+        sf_map.erase(lookup);
+
         if (!sf) {
           gt->Makefile->IssueMessage(
             MessageType::INTERNAL_ERROR,
@@ -160,7 +172,40 @@ Json::Value CollationInformationCxxModules(
     }
   }
 
-  return tdi_cxx_module_info;
+  for (auto const& sf_entry : sf_map) {
+    CompileType const ct = sf_entry.second.second;
+    if (ct == CompileType::BmiOnly) {
+      continue;
+    }
+
+    auto const* sf = sf_entry.second.first;
+    if (!gt->NeedDyndepForSource(sf->GetLanguage(), config, sf)) {
+      continue;
+    }
+
+    auto full_file = cmSystemTools::CollapseFullPath(sf->GetFullPath());
+    auto obj_path = cb.ObjectFilePath(sf, config);
+    Json::Value& tdi_source_info = tdi_sources[obj_path] = Json::objectValue;
+
+    tdi_source_info["source"] = full_file;
+    tdi_source_info["language"] = sf->GetLanguage();
+  }
+
+  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,
@@ -289,12 +334,21 @@ void cmDyndepCollation::AddCollationInformation(
   Json::Value& tdi, cmGeneratorTarget const* gt, std::string const& config,
   cmDyndepGeneratorCallbacks const& cb)
 {
-  tdi["cxx-modules"] = CollationInformationCxxModules(gt, config, cb);
+  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;
 }
 
+struct SourceInfo
+{
+  std::string SourcePath;
+  std::string Language;
+};
+
 struct CxxModuleFileSet
 {
   std::string Name;
@@ -306,6 +360,12 @@ struct CxxModuleFileSet
   cm::optional<std::string> Destination;
 };
 
+struct CxxModuleDatabaseInfo
+{
+  std::string TemplatePath;
+  std::string Output;
+};
+
 struct CxxModuleBmiInstall
 {
   std::string Component;
@@ -330,7 +390,9 @@ struct CxxModuleExport
 
 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;
@@ -367,6 +429,15 @@ cmDyndepCollation::ParseExportInfo(Json::Value const& tdi)
       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;
@@ -405,6 +476,15 @@ cmDyndepCollation::ParseExportInfo(Json::Value const& tdi)
       }
     }
   }
+  Json::Value const& tdi_sources = tdi["sources"];
+  if (tdi_sources.isObject()) {
+    for (auto i = tdi_sources.begin(); i != tdi_sources.end(); ++i) {
+      SourceInfo& si = export_info->ObjectToSource[i.key().asString()];
+      auto const& tdi_source = *i;
+      si.SourcePath = tdi_source["source"].asString();
+      si.Language = tdi_source["language"].asString();
+    }
+  }
 
   return export_info;
 }
@@ -446,6 +526,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>(
@@ -475,6 +570,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();
@@ -499,6 +613,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) {
@@ -660,6 +799,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;
 }
 

+ 9 - 0
Source/cmExperimental.cxx

@@ -56,6 +56,15 @@ cmExperimental::FeatureData LookupTable[] = {
     {},
     cmExperimental::TryCompileCondition::Always,
     false },
+  // ExportBuildDatabase
+  { "ExportBuildDatabase",
+    "4bd552e2-b7fb-429a-ab23-c83ef53f3f13",
+    "CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE",
+    "CMake's support for exporting build databases is experimental. It is "
+    "meant only for experimentation and feedback to CMake developers.",
+    {},
+    cmExperimental::TryCompileCondition::Never,
+    false },
 };
 static_assert(sizeof(LookupTable) / sizeof(LookupTable[0]) ==
                 static_cast<size_t>(cmExperimental::Feature::Sentinel),

+ 1 - 0
Source/cmExperimental.h

@@ -21,6 +21,7 @@ public:
     WindowsKernelModeDriver,
     CxxImportStd,
     ExportPackageInfo,
+    ExportBuildDatabase,
 
     Sentinel,
   };

+ 473 - 0
Source/cmGeneratorTarget.cxx

@@ -37,6 +37,7 @@
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPropertyMap.h"
+#include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
 #include "cmSourceFileLocation.h"
 #include "cmSourceFileLocationKind.h"
@@ -138,6 +139,20 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
   } else {
     this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE");
   }
+
+  auto configs =
+    this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+  std::string build_db_languages[] = { "CXX" };
+  for (auto const& language : build_db_languages) {
+    for (auto const& config : configs) {
+      auto bdb_path = this->BuildDatabasePath(language, config);
+      if (!bdb_path.empty()) {
+        this->Makefile->GetOrCreateGeneratedSource(bdb_path);
+        this->GetGlobalGenerator()->AddBuildDatabaseFile(language, config,
+                                                         bdb_path);
+      }
+    }
+  }
 }
 
 cmGeneratorTarget::~cmGeneratorTarget() = default;
@@ -173,6 +188,20 @@ const std::string& cmGeneratorTarget::GetName() const
   return this->Target->GetName();
 }
 
+std::string cmGeneratorTarget::GetFamilyName() const
+{
+  if (!this->IsImported() && !this->IsSynthetic()) {
+    return this->Target->GetTemplateName();
+  }
+  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
+  constexpr size_t HASH_TRUNCATION = 12;
+  auto dirhash =
+    hasher.HashString(this->GetLocalGenerator()->GetCurrentBinaryDirectory());
+  auto targetIdent = hasher.HashString(cmStrCat("@d_", dirhash));
+  return cmStrCat(this->Target->GetTemplateName(), '@',
+                  targetIdent.substr(0, HASH_TRUNCATION));
+}
+
 std::string cmGeneratorTarget::GetExportName() const
 {
   cmValue exportName = this->GetProperty("EXPORT_NAME");
@@ -2010,6 +2039,425 @@ std::vector<std::string> cmGeneratorTarget::GetAppleArchs(
   return std::move(archList.data());
 }
 
+namespace {
+
+bool IsSupportedClassifiedFlagsLanguage(std::string const& lang)
+{
+  return lang == "CXX"_s;
+}
+
+bool CanUseCompilerLauncher(std::string const& lang)
+{
+  // Also found in `cmCommonTargetGenerator::GetCompilerLauncher`.
+  return lang == "C"_s || lang == "CXX"_s || lang == "Fortran"_s ||
+    lang == "CUDA"_s || lang == "HIP"_s || lang == "ISPC"_s ||
+    lang == "OBJC"_s || lang == "OBJCXX"_s;
+}
+
+// FIXME: return a vector of `cm::string_view` instead to avoid lots of tiny
+// allocations.
+std::vector<std::string> SplitFlags(std::string const& flags)
+{
+  std::vector<std::string> options;
+
+#ifdef _WIN32
+  cmSystemTools::ParseWindowsCommandLine(flags.c_str(), options);
+#else
+  cmSystemTools::ParseUnixCommandLine(flags.c_str(), options);
+#endif
+
+  return options;
+}
+
+}
+
+cmGeneratorTarget::ClassifiedFlags
+cmGeneratorTarget::GetClassifiedFlagsForSource(cmSourceFile const* sf,
+                                               std::string const& config)
+{
+  auto& sourceFlagsCache = this->Configs[config].SourceFlags;
+  auto cacheEntry = sourceFlagsCache.lower_bound(sf);
+  if (cacheEntry != sourceFlagsCache.end() && cacheEntry->first == sf) {
+    return cacheEntry->second;
+  }
+
+  ClassifiedFlags flags;
+  std::string const& lang = sf->GetLanguage();
+
+  if (!IsSupportedClassifiedFlagsLanguage(lang)) {
+    return flags;
+  }
+
+  auto* const lg = this->GetLocalGenerator();
+  auto const* const mf = this->Makefile;
+
+  // Compute the compiler launcher flags.
+  if (CanUseCompilerLauncher(lang)) {
+    // Compiler launchers are all execution flags and should not be relevant to
+    // the actual compilation.
+    FlagClassification cls = FlagClassification::ExecutionFlag;
+    FlagKind kind = FlagKind::NotAFlag;
+
+    std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER");
+    cmValue clauncher = this->GetProperty(clauncher_prop);
+    std::string const evaluatedClauncher = cmGeneratorExpression::Evaluate(
+      *clauncher, lg, config, this, nullptr, this, lang);
+
+    for (auto const& flag : SplitFlags(evaluatedClauncher)) {
+      flags.emplace_back(cls, kind, flag);
+    }
+  }
+
+  ClassifiedFlags define_flags;
+  ClassifiedFlags include_flags;
+  ClassifiedFlags compile_flags;
+
+  SourceVariables sfVars = this->GetSourceVariables(sf, config);
+
+  // Compute language flags.
+  {
+    FlagClassification cls = FlagClassification::BaselineFlag;
+    FlagKind kind = FlagKind::Compile;
+
+    std::string mfFlags;
+    // Explicitly add the explicit language flag before any other flag
+    // so user flags can override it.
+    this->AddExplicitLanguageFlags(mfFlags, *sf);
+
+    for (auto const& flag : SplitFlags(mfFlags)) {
+      flags.emplace_back(cls, kind, flag);
+    }
+  }
+
+  std::unordered_map<std::string, std::string> pchSources;
+  std::string filterArch;
+
+  {
+    std::vector<std::string> pchArchs = this->GetPchArchs(config, lang);
+
+    for (const std::string& arch : pchArchs) {
+      const std::string pchSource = this->GetPchSource(config, lang, arch);
+      if (pchSource == sf->GetFullPath()) {
+        filterArch = arch;
+      }
+      if (!pchSource.empty()) {
+        pchSources.insert(std::make_pair(pchSource, arch));
+      }
+    }
+  }
+
+  // Compute target-wide flags.
+  {
+    FlagClassification cls = FlagClassification::BaselineFlag;
+
+    // Compile flags
+    {
+      FlagKind kind = FlagKind::Compile;
+      std::string targetFlags;
+
+      lg->GetTargetCompileFlags(this, config, lang, targetFlags, filterArch);
+
+      for (auto&& flag : SplitFlags(targetFlags)) {
+        compile_flags.emplace_back(cls, kind, std::move(flag));
+      }
+    }
+
+    // Define flags
+    {
+      FlagKind kind = FlagKind::Definition;
+      std::set<std::string> defines;
+
+      lg->GetTargetDefines(this, config, lang, defines);
+
+      std::string defineFlags;
+      lg->JoinDefines(defines, defineFlags, lang);
+
+      for (auto&& flag : SplitFlags(defineFlags)) {
+        define_flags.emplace_back(cls, kind, std::move(flag));
+      }
+    }
+
+    // Include flags
+    {
+      FlagKind kind = FlagKind::Include;
+      std::vector<std::string> includes;
+
+      lg->GetIncludeDirectories(includes, this, lang, config);
+      auto includeFlags =
+        lg->GetIncludeFlags(includes, this, lang, config, false);
+
+      for (auto&& flag : SplitFlags(includeFlags)) {
+        include_flags.emplace_back(cls, kind, std::move(flag));
+      }
+    }
+  }
+
+  const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+  const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+
+  cmGeneratorExpressionInterpreter genexInterpreter(lg, config, this, lang);
+
+  // Source-specific flags.
+  {
+    FlagClassification cls = FlagClassification::PrivateFlag;
+    FlagKind kind = FlagKind::Compile;
+
+    std::string sourceFlags;
+
+    if (cmValue cflags = sf->GetProperty(COMPILE_FLAGS)) {
+      lg->AppendFlags(sourceFlags,
+                      genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
+    }
+
+    if (cmValue coptions = sf->GetProperty(COMPILE_OPTIONS)) {
+      lg->AppendCompileOptions(
+        sourceFlags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
+    }
+
+    for (auto&& flag : SplitFlags(sourceFlags)) {
+      compile_flags.emplace_back(cls, kind, std::move(flag));
+    }
+
+    // Dependency tracking flags.
+    {
+      if (!sfVars.DependencyFlags.empty()) {
+        cmRulePlaceholderExpander::RuleVariables vars;
+        auto rulePlaceholderExpander = lg->CreateRulePlaceholderExpander();
+
+        vars.DependencyFile = sfVars.DependencyFile.c_str();
+        vars.DependencyTarget = sfVars.DependencyTarget.c_str();
+
+        std::string depfileFlags = sfVars.DependencyFlags;
+        rulePlaceholderExpander->ExpandRuleVariables(lg, depfileFlags, vars);
+        for (auto&& flag : SplitFlags(depfileFlags)) {
+          compile_flags.emplace_back(FlagClassification::LocationFlag,
+                                     FlagKind::BuildSystem, std::move(flag));
+        }
+      }
+    }
+  }
+
+  // Precompiled headers.
+  {
+    FlagClassification cls = FlagClassification::PrivateFlag;
+    FlagKind kind = FlagKind::Compile;
+
+    std::string pchFlags;
+
+    // Add precompile headers compile options.
+    if (!sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+      if (!pchSources.empty()) {
+        std::string pchOptions;
+        auto pchIt = pchSources.find(sf->GetFullPath());
+        if (pchIt != pchSources.end()) {
+          pchOptions =
+            this->GetPchCreateCompileOptions(config, lang, pchIt->second);
+        } else {
+          pchOptions = this->GetPchUseCompileOptions(config, lang);
+        }
+
+        this->LocalGenerator->AppendCompileOptions(
+          pchFlags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS));
+      }
+    }
+
+    for (auto&& flag : SplitFlags(pchFlags)) {
+      compile_flags.emplace_back(cls, kind, std::move(flag));
+    }
+  }
+
+  // C++ module flags.
+  if (lang == "CXX"_s) {
+    FlagClassification cls = FlagClassification::LocationFlag;
+    FlagKind kind = FlagKind::BuildSystem;
+
+    std::string bmiFlags;
+
+    auto const* fs = this->GetFileSetForSource(config, sf);
+    if (fs && fs->GetType() == "CXX_MODULES"_s) {
+      if (lang != "CXX"_s) {
+        mf->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmStrCat(
+            "Target \"", this->Target->GetName(), "\" contains the source\n  ",
+            sf->GetFullPath(), "\nin a file set of type \"", fs->GetType(),
+            R"(" but the source is not classified as a "CXX" source.)"));
+      }
+
+      if (!this->Target->IsNormal()) {
+        auto flag = mf->GetSafeDefinition("CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
+        cmRulePlaceholderExpander::RuleVariables compileObjectVars;
+        compileObjectVars.Object = sfVars.ObjectFileDir.c_str();
+        auto rulePlaceholderExpander = lg->CreateRulePlaceholderExpander();
+        rulePlaceholderExpander->ExpandRuleVariables(lg, flag,
+                                                     compileObjectVars);
+        lg->AppendCompileOptions(bmiFlags, flag);
+      }
+    }
+
+    for (auto&& flag : SplitFlags(bmiFlags)) {
+      compile_flags.emplace_back(cls, kind, std::move(flag));
+    }
+  }
+
+  cmRulePlaceholderExpander::RuleVariables vars;
+  vars.CMTargetName = this->GetName().c_str();
+  vars.CMTargetType = cmState::GetTargetTypeName(this->GetType()).c_str();
+  vars.Language = lang.c_str();
+  auto const sfPath = this->LocalGenerator->ConvertToOutputFormat(
+    sf->GetFullPath(), cmOutputConverter::SHELL);
+
+  // Compute the base compiler command line. We'll find placeholders and
+  // replace them with arguments later in this function.
+  {
+    FlagClassification cls = FlagClassification::ExecutionFlag;
+    FlagKind kind = FlagKind::NotAFlag;
+
+    std::string const cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT");
+    std::string const& compileCmd = mf->GetRequiredDefinition(cmdVar);
+    cmList compileCmds(compileCmd); // FIXME: which command to use?
+    std::string& cmd = compileCmds[0];
+    auto rulePlaceholderExpander = lg->CreateRulePlaceholderExpander();
+
+    static std::string const PlaceholderDefines = "__CMAKE_DEFINES";
+    static std::string const PlaceholderIncludes = "__CMAKE_INCLUDES";
+    static std::string const PlaceholderFlags = "__CMAKE_FLAGS";
+    static std::string const PlaceholderSource = "__CMAKE_SOURCE";
+
+    vars.Defines = PlaceholderDefines.c_str();
+    vars.Includes = PlaceholderIncludes.c_str();
+    vars.TargetPDB = sfVars.TargetPDB.c_str();
+    vars.TargetCompilePDB = sfVars.TargetCompilePDB.c_str();
+    vars.Object = sfVars.ObjectFileDir.c_str();
+    vars.ObjectDir = sfVars.ObjectDir.c_str();
+    vars.ObjectFileDir = sfVars.ObjectFileDir.c_str();
+    vars.Flags = PlaceholderFlags.c_str();
+    vars.DependencyFile = sfVars.DependencyFile.c_str();
+    vars.DependencyTarget = sfVars.DependencyTarget.c_str();
+    vars.Source = PlaceholderSource.c_str();
+
+    rulePlaceholderExpander->ExpandRuleVariables(lg, cmd, vars);
+    for (auto&& flag : SplitFlags(cmd)) {
+      if (flag == PlaceholderDefines) {
+        flags.insert(flags.end(), define_flags.begin(), define_flags.end());
+      } else if (flag == PlaceholderIncludes) {
+        flags.insert(flags.end(), include_flags.begin(), include_flags.end());
+      } else if (flag == PlaceholderFlags) {
+        flags.insert(flags.end(), compile_flags.begin(), compile_flags.end());
+      } else if (flag == PlaceholderSource) {
+        flags.emplace_back(FlagClassification::LocationFlag,
+                           FlagKind::BuildSystem, sfPath);
+      } else {
+        flags.emplace_back(cls, kind, std::move(flag));
+        // All remaining flags here are build system flags.
+        kind = FlagKind::BuildSystem;
+      }
+    }
+  }
+
+  cacheEntry = sourceFlagsCache.emplace_hint(cacheEntry, sf, std::move(flags));
+  return cacheEntry->second;
+}
+
+cmGeneratorTarget::SourceVariables cmGeneratorTarget::GetSourceVariables(
+  cmSourceFile const* sf, std::string const& config)
+{
+  SourceVariables vars;
+  auto const language = sf->GetLanguage();
+  auto const targetType = this->GetType();
+  auto const* const lg = this->GetLocalGenerator();
+  auto const* const gg = this->GetGlobalGenerator();
+  auto const* const mf = this->Makefile;
+
+  // PDB settings.
+  {
+    if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") ||
+        mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID") ||
+        mf->GetDefinition("MSVC_CUDA_ARCHITECTURE_ID")) {
+      std::string pdbPath;
+      std::string compilePdbPath;
+      if (targetType <= cmStateEnums::OBJECT_LIBRARY) {
+        compilePdbPath = this->GetCompilePDBPath(config);
+        if (compilePdbPath.empty()) {
+          // Match VS default: `$(IntDir)vc$(PlatformToolsetVersion).pdb`.
+          // A trailing slash tells the toolchain to add its default file name.
+          compilePdbPath = this->GetSupportDirectory();
+          if (gg->IsMultiConfig()) {
+            compilePdbPath = cmStrCat(compilePdbPath, '/', config);
+          }
+          compilePdbPath += '/';
+          if (targetType == cmStateEnums::STATIC_LIBRARY) {
+            // Match VS default for static libs: `$(IntDir)$(ProjectName).pdb`.
+            compilePdbPath = cmStrCat(compilePdbPath, this->GetName(), ".pdb");
+          }
+        }
+      }
+
+      if (targetType == cmStateEnums::EXECUTABLE ||
+          targetType == cmStateEnums::STATIC_LIBRARY ||
+          targetType == cmStateEnums::SHARED_LIBRARY ||
+          targetType == cmStateEnums::MODULE_LIBRARY) {
+        pdbPath = cmStrCat(this->GetPDBDirectory(config), '/',
+                           this->GetPDBName(config));
+      }
+
+      vars.TargetPDB = lg->ConvertToOutputFormat(
+        gg->ConvertToOutputPath(std::move(pdbPath)), cmOutputConverter::SHELL);
+      vars.TargetCompilePDB = lg->ConvertToOutputFormat(
+        gg->ConvertToOutputPath(std::move(compilePdbPath)),
+        cmOutputConverter::SHELL);
+    }
+  }
+
+  // Object settings.
+  {
+    std::string const objectDir = gg->ConvertToOutputPath(
+      cmStrCat(this->GetSupportDirectory(), gg->GetConfigDirectory(config)));
+    std::string const objectFileName = this->GetObjectName(sf);
+    std::string const objectFilePath =
+      cmStrCat(objectDir, '/', objectFileName);
+
+    vars.ObjectDir =
+      lg->ConvertToOutputFormat(objectDir, cmOutputConverter::SHELL);
+    vars.ObjectFileDir =
+      lg->ConvertToOutputFormat(objectFilePath, cmOutputConverter::SHELL);
+
+    // Dependency settings.
+    {
+      std::string const depfileFormatName =
+        cmStrCat("CMAKE_", language, "_DEPFILE_FORMAT");
+      std::string const depfileFormat =
+        mf->GetSafeDefinition(depfileFormatName);
+      if (depfileFormat != "msvc"_s) {
+        std::string const flagsName =
+          cmStrCat("CMAKE_DEPFILE_FLAGS_", language);
+        std::string const depfileFlags = mf->GetSafeDefinition(flagsName);
+        if (!depfileFlags.empty()) {
+          bool replaceExt = false;
+          if (!language.empty()) {
+            std::string const repVar =
+              cmStrCat("CMAKE_", language, "_DEPFILE_EXTENSION_REPLACE");
+            replaceExt = mf->IsOn(repVar);
+          }
+          std::string const depfilePath = cmStrCat(
+            objectDir, '/',
+            replaceExt
+              ? cmSystemTools::GetFilenameWithoutLastExtension(objectFileName)
+              : objectFileName,
+            ".d");
+
+          vars.DependencyFlags = depfileFlags;
+          vars.DependencyTarget = vars.ObjectFileDir;
+          vars.DependencyFile =
+            lg->ConvertToOutputFormat(depfilePath, cmOutputConverter::SHELL);
+        }
+      }
+    }
+  }
+
+  return vars;
+}
+
 void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
                                                  cmSourceFile const& sf) const
 {
@@ -5486,6 +5934,31 @@ cmGeneratorTarget::CxxModuleSupport cmGeneratorTarget::NeedCxxDyndep(
   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 {};
+  }
+  if (!cmExperimental::HasSupportEnabled(
+        *this->Makefile, cmExperimental::Feature::ExportBuildDatabase)) {
+    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];

+ 63 - 0
Source/cmGeneratorTarget.h

@@ -108,6 +108,7 @@ public:
 
   cmStateEnums::TargetType GetType() const;
   const std::string& GetName() const;
+  std::string GetFamilyName() const;
   std::string GetExportName() const;
   std::string GetFilesystemExportName() const;
 
@@ -516,6 +517,64 @@ public:
   std::vector<std::string> GetAppleArchs(std::string const& config,
                                          cm::optional<std::string> lang) const;
 
+  // The classification of the flag.
+  enum class FlagClassification
+  {
+    // The flag is for the execution of the tool (e.g., the compiler itself,
+    // any launchers, etc.).
+    ExecutionFlag,
+    // The flag is "baseline" and should be apply to TUs which may interact
+    // with this compilation (e.g., imported modules).
+    BaselineFlag,
+    // The flag is "private" and doesn't need to apply to interacting TUs.
+    PrivateFlag,
+    // Flags for the TU itself (e.g., output paths, dependency scanning, etc.).
+    LocationFlag,
+  };
+  enum class FlagKind
+  {
+    // Not a flag (executable or other entries).
+    NotAFlag,
+    // Flags for support of the build system.
+    BuildSystem,
+    // A compilation flag.
+    Compile,
+    // An include flag.
+    Include,
+    // A compile definition.
+    Definition,
+  };
+  struct ClassifiedFlag
+  {
+    ClassifiedFlag(FlagClassification cls, FlagKind kind, std::string flag)
+      : Classification(cls)
+      , Kind(kind)
+      , Flag(std::move(flag))
+    {
+    }
+
+    FlagClassification Classification;
+    FlagKind Kind;
+    std::string Flag;
+  };
+  using ClassifiedFlags = std::vector<ClassifiedFlag>;
+  ClassifiedFlags GetClassifiedFlagsForSource(cmSourceFile const* sf,
+                                              std::string const& config);
+  struct SourceVariables
+  {
+    std::string TargetPDB;
+    std::string TargetCompilePDB;
+    std::string ObjectDir;
+    std::string ObjectFileDir;
+    std::string DependencyFile;
+    std::string DependencyTarget;
+
+    // Dependency flags (if used)
+    std::string DependencyFlags;
+  };
+  SourceVariables GetSourceVariables(cmSourceFile const* sf,
+                                     std::string const& config);
+
   void AddExplicitLanguageFlags(std::string& flags,
                                 cmSourceFile const& sf) const;
 
@@ -1443,6 +1502,9 @@ public:
   };
   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
@@ -1451,6 +1513,7 @@ private:
     std::map<std::string, cmFileSet const*> FileSetCache;
     std::map<cmGeneratorTarget const*, std::vector<cmGeneratorTarget const*>>
       SyntheticDeps;
+    std::map<cmSourceFile const*, ClassifiedFlags> SourceFlags;
   };
   mutable std::map<std::string, InfoByConfig> Configs;
 };

+ 228 - 0
Source/cmGlobalGenerator.cxx

@@ -32,7 +32,9 @@
 #include "cmCryptoHash.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
+#include "cmCustomCommandTypes.h"
 #include "cmDuration.h"
+#include "cmExperimental.h"
 #include "cmExportBuildFileGenerator.h"
 #include "cmExternalMakefileProjectGenerator.h"
 #include "cmGeneratedFileStream.h"
@@ -68,6 +70,8 @@
 #  include "cmQtAutoGenGlobalInitializer.h"
 #endif
 
+class cmListFileBacktrace;
+
 const std::string kCMAKE_PLATFORM_INFO_INITIALIZED =
   "CMAKE_PLATFORM_INFO_INITIALIZED";
 
@@ -1569,6 +1573,10 @@ bool cmGlobalGenerator::Compute()
   }
   this->FinalizeTargetConfiguration();
 
+  if (!this->AddBuildDatabaseTargets()) {
+    return false;
+  }
+
   this->CreateGenerationObjects();
 
   // at this point this->LocalGenerators has been filled,
@@ -1627,6 +1635,13 @@ bool cmGlobalGenerator::Compute()
     return false;
   }
 
+  // Perform after-generator-target generator actions. These involve collecting
+  // information gathered during the construction of generator targets.
+  for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
+    this->Makefiles[i]->GenerateAfterGeneratorTargets(
+      *this->LocalGenerators[i]);
+  }
+
   // Add generator specific helper commands
   for (const auto& localGen : this->LocalGenerators) {
     localGen->AddHelperCommands();
@@ -2827,6 +2842,20 @@ bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName,
                              reason);
 }
 
+bool cmGlobalGenerator::CheckCMP0037Prefix(std::string const& targetPrefix,
+                                           std::string const& reason) const
+{
+  bool ret = true;
+  for (auto const& tgtPair : this->TargetSearchIndex) {
+    if (cmHasPrefix(tgtPair.first, targetPrefix) &&
+        !RaiseCMP0037Message(this->GetCMakeInstance(), tgtPair.second,
+                             tgtPair.first, reason)) {
+      ret = false;
+    }
+  }
+  return ret;
+}
+
 void cmGlobalGenerator::CreateDefaultGlobalTargets(
   std::vector<GlobalTargetInfo>& targets)
 {
@@ -3179,6 +3208,205 @@ void cmGlobalGenerator::AddGlobalTarget_Install(
   }
 }
 
+class ModuleCompilationDatabaseCommandAction
+{
+public:
+  ModuleCompilationDatabaseCommandAction(
+    std::string output, std::function<std::vector<std::string>()> inputs)
+    : Output(std::move(output))
+    , Inputs(std::move(inputs))
+  {
+  }
+  void operator()(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+                  std::unique_ptr<cmCustomCommand> cc);
+
+private:
+  std::string const Output;
+  std::function<std::vector<std::string>()> const Inputs;
+};
+
+void ModuleCompilationDatabaseCommandAction::operator()(
+  cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+  std::unique_ptr<cmCustomCommand> cc)
+{
+  auto inputs = this->Inputs();
+
+  cmCustomCommandLines command_lines;
+  cmCustomCommandLine command_line;
+  {
+    command_line.emplace_back(cmSystemTools::GetCMakeCommand());
+    command_line.emplace_back("-E");
+    command_line.emplace_back("cmake_module_compile_db");
+    command_line.emplace_back("merge");
+    command_line.emplace_back("-o");
+    command_line.emplace_back(this->Output);
+    for (auto const& input : inputs) {
+      command_line.emplace_back(input);
+    }
+  }
+  command_lines.emplace_back(std::move(command_line));
+
+  cc->SetBacktrace(lfbt);
+  cc->SetCommandLines(command_lines);
+  cc->SetWorkingDirectory(lg.GetBinaryDirectory().c_str());
+  cc->SetDependsExplicitOnly(true);
+  cc->SetOutputs(this->Output);
+  if (!inputs.empty()) {
+    cc->SetMainDependency(inputs[0]);
+  }
+  cc->SetDepends(inputs);
+  detail::AddCustomCommandToOutput(lg, cmCommandOrigin::Generator,
+                                   std::move(cc), false);
+}
+
+class ModuleCompilationDatabaseTargetAction
+{
+public:
+  ModuleCompilationDatabaseTargetAction(std::string output, cmTarget* target)
+    : Output(std::move(output))
+    , Target(target)
+  {
+  }
+  void operator()(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+                  std::unique_ptr<cmCustomCommand> cc);
+
+private:
+  std::string const Output;
+  cmTarget* const Target;
+};
+
+void ModuleCompilationDatabaseTargetAction::operator()(
+  cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+  std::unique_ptr<cmCustomCommand> cc)
+{
+  cc->SetBacktrace(lfbt);
+  cc->SetWorkingDirectory(lg.GetBinaryDirectory().c_str());
+  std::vector<std::string> target_inputs;
+  target_inputs.emplace_back(this->Output);
+  cc->SetDepends(target_inputs);
+  detail::AddUtilityCommand(lg, cmCommandOrigin::Generator, this->Target,
+                            std::move(cc));
+}
+
+void cmGlobalGenerator::AddBuildDatabaseFile(std::string const& lang,
+                                             std::string const& config,
+                                             std::string const& path)
+{
+  if (!config.empty()) {
+    this->PerConfigModuleDbs[config][lang].push_back(path);
+  }
+  this->PerLanguageModuleDbs[lang].push_back(path);
+}
+
+bool cmGlobalGenerator::AddBuildDatabaseTargets()
+{
+  auto& mf = this->Makefiles[0];
+  if (!mf->IsOn("CMAKE_EXPORT_BUILD_DATABASE")) {
+    return true;
+  }
+  if (!cmExperimental::HasSupportEnabled(
+        *mf.get(), cmExperimental::Feature::ExportBuildDatabase)) {
+    return {};
+  }
+
+  static const auto reservedTargets = { "cmake_build_database" };
+  for (auto const& target : reservedTargets) {
+    if (!this->CheckCMP0037(target,
+                            "when exporting build databases are enabled")) {
+      return false;
+    }
+  }
+  static const auto reservedPrefixes = { "cmake_build_database-" };
+  for (auto const& prefix : reservedPrefixes) {
+    if (!this->CheckCMP0037Prefix(
+          prefix, "when exporting build databases are enabled")) {
+      return false;
+    }
+  }
+
+  if (!this->SupportsBuildDatabase()) {
+    return true;
+  }
+
+  auto configs = mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+
+  static cm::static_string_view TargetPrefix = "cmake_build_database"_s;
+  auto AddMergeTarget =
+    [&mf](std::string const& name, const char* comment,
+          std::string const& output,
+          std::function<std::vector<std::string>()> inputs) {
+      // Add the custom command.
+      {
+        ModuleCompilationDatabaseCommandAction action{ output,
+                                                       std::move(inputs) };
+        auto cc = cm::make_unique<cmCustomCommand>();
+        cc->SetComment(comment);
+        mf->AddGeneratorAction(
+          std::move(cc), action,
+          cmMakefile::GeneratorActionWhen::AfterGeneratorTargets);
+      }
+
+      // Add a custom target with the given name.
+      {
+        cmTarget* target = mf->AddNewUtilityTarget(name, true);
+        ModuleCompilationDatabaseTargetAction action{ output, target };
+        auto cc = cm::make_unique<cmCustomCommand>();
+        mf->AddGeneratorAction(std::move(cc), action);
+      }
+    };
+
+  std::string module_languages[] = { "CXX" };
+
+  // Add per-configuration targets.
+  for (auto const& config : configs) {
+    // Add per-language targets.
+    std::vector<std::string> all_config_paths;
+    for (auto const& lang : module_languages) {
+      auto comment = cmStrCat("Combining module command databases for ", lang,
+                              " and ", config);
+      auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
+                             lang, '_', config, ".json");
+      mf->GetOrCreateGeneratedSource(output);
+      AddMergeTarget(cmStrCat(TargetPrefix, '-', lang, '-', config),
+                     comment.c_str(), output, [this, config, lang]() {
+                       return this->PerConfigModuleDbs[config][lang];
+                     });
+      all_config_paths.emplace_back(std::move(output));
+    }
+
+    // Add the overall target.
+    auto comment = cmStrCat("Combining module command databases for ", config);
+    auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
+                           config, ".json");
+    mf->GetOrCreateGeneratedSource(output);
+    AddMergeTarget(cmStrCat(TargetPrefix, '-', config), comment.c_str(),
+                   output, [all_config_paths]() { return all_config_paths; });
+  }
+
+  // NMC considerations
+  // Add per-language targets.
+  std::vector<std::string> all_config_paths;
+  for (auto const& lang : module_languages) {
+    auto comment = cmStrCat("Combining module command databases for ", lang);
+    auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
+                           lang, ".json");
+    mf->GetOrCreateGeneratedSource(output);
+    AddMergeTarget(
+      cmStrCat(TargetPrefix, '-', lang), comment.c_str(), output,
+      [this, lang]() { return this->PerLanguageModuleDbs[lang]; });
+    all_config_paths.emplace_back(std::move(output));
+  }
+
+  // Add the overall target.
+  auto const* comment = "Combining all module command databases";
+  auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database.json");
+  mf->GetOrCreateGeneratedSource(output);
+  AddMergeTarget(std::string(TargetPrefix), comment, output,
+                 [all_config_paths]() { return all_config_paths; });
+
+  return true;
+}
+
 std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
 {
   cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(

+ 26 - 0
Source/cmGlobalGenerator.h

@@ -171,6 +171,11 @@ public:
     return false;
   }
 
+  virtual bool SupportsBuildDatabase() const { return false; }
+  bool AddBuildDatabaseTargets();
+  void AddBuildDatabaseFile(std::string const& lang, std::string const& config,
+                            std::string const& path);
+
   virtual bool IsGNUMakeJobServerAware() const { return false; }
 
   bool Compute();
@@ -594,6 +599,18 @@ public:
   virtual bool SupportsCrossConfigs() const { return false; }
   virtual bool SupportsDefaultConfigs() const { return false; }
 
+  virtual std::string ConvertToOutputPath(std::string path) const
+  {
+    return path;
+  }
+  virtual std::string GetConfigDirectory(std::string const& config) const
+  {
+    if (!this->IsMultiConfig() || config.empty()) {
+      return {};
+    }
+    return cmStrCat('/', config);
+  }
+
   static std::string EscapeJSON(const std::string& s);
 
   void ProcessEvaluationFiles();
@@ -859,6 +876,8 @@ private:
 
   bool CheckCMP0037(std::string const& targetName,
                     std::string const& reason) const;
+  bool CheckCMP0037Prefix(std::string const& targetPrefix,
+                          std::string const& reason) const;
 
   void IndexMakefile(cmMakefile* mf);
   void IndexLocalGenerator(cmLocalGenerator* lg);
@@ -904,6 +923,13 @@ private:
   cmFileLockPool FileLockPool;
 #endif
 
+  using PerLanguageModuleDatabases =
+    std::map<std::string, std::vector<std::string>>;
+  using PerConfigModuleDatabases =
+    std::map<std::string, PerLanguageModuleDatabases>;
+  PerConfigModuleDatabases PerConfigModuleDbs;
+  PerLanguageModuleDatabases PerLanguageModuleDbs;
+
 protected:
   float FirstTimeProgress;
   bool NeedSymbolicMark;

+ 5 - 0
Source/cmGlobalNinjaGenerator.cxx

@@ -3149,6 +3149,11 @@ bool cmGlobalNinjaGenerator::IsSingleConfigUtility(
     !this->PerConfigUtilityTargets.count(target->GetName());
 }
 
+std::string cmGlobalNinjaGenerator::ConvertToOutputPath(std::string path) const
+{
+  return this->ConvertToNinjaPath(path);
+}
+
 const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE =
   "CMakeFiles/common.ninja";
 const char* cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION = ".ninja";

+ 3 - 0
Source/cmGlobalNinjaGenerator.h

@@ -483,6 +483,9 @@ public:
   bool IsSingleConfigUtility(cmGeneratorTarget const* target) const;
 
   bool CheckCxxModuleSupport(CxxModuleSupportQuery query) override;
+  bool SupportsBuildDatabase() const override { return true; }
+
+  std::string ConvertToOutputPath(std::string path) const override;
 
 protected:
   std::vector<std::string> const& GetConfigNames() const;

+ 15 - 2
Source/cmMakefile.cxx

@@ -1055,8 +1055,13 @@ void cmMakefile::AddGeneratorAction(GeneratorAction&& action)
 }
 
 void cmMakefile::GeneratorAction::operator()(cmLocalGenerator& lg,
-                                             const cmListFileBacktrace& lfbt)
+                                             const cmListFileBacktrace& lfbt,
+                                             GeneratorActionWhen when)
 {
+  if (this->When != when) {
+    return;
+  }
+
   if (cc) {
     CCAction(lg, lfbt, std::move(cc));
   } else {
@@ -1073,7 +1078,7 @@ void cmMakefile::DoGenerate(cmLocalGenerator& lg)
   // give all the commands a chance to do something
   // after the file has been parsed before generation
   for (auto& action : this->GeneratorActions) {
-    action.Value(lg, action.Backtrace);
+    action.Value(lg, action.Backtrace, GeneratorActionWhen::AfterConfigure);
   }
   this->GeneratorActionsInvoked = true;
 
@@ -1107,6 +1112,14 @@ void cmMakefile::Generate(cmLocalGenerator& lg)
   }
 }
 
+void cmMakefile::GenerateAfterGeneratorTargets(cmLocalGenerator& lg)
+{
+  for (auto& action : this->GeneratorActions) {
+    action.Value(lg, action.Backtrace,
+                 GeneratorActionWhen::AfterGeneratorTargets);
+  }
+}
+
 namespace {
 // There are still too many implicit backtraces through cmMakefile.  As a
 // workaround we reset the backtrace temporarily.

+ 23 - 5
Source/cmMakefile.h

@@ -143,6 +143,14 @@ public:
   bool EnforceUniqueName(std::string const& name, std::string& msg,
                          bool isCustom = false) const;
 
+  enum class GeneratorActionWhen
+  {
+    // Run after all CMake code has been parsed.
+    AfterConfigure,
+    // Run after generator targets have been constructed.
+    AfterGeneratorTargets,
+  };
+
   class GeneratorAction
   {
     using ActionT =
@@ -152,20 +160,29 @@ public:
                          std::unique_ptr<cmCustomCommand> cc)>;
 
   public:
-    GeneratorAction(ActionT&& action)
-      : Action(std::move(action))
+    GeneratorAction(
+      ActionT&& action,
+      GeneratorActionWhen when = GeneratorActionWhen::AfterConfigure)
+      : When(when)
+      , Action(std::move(action))
     {
     }
 
-    GeneratorAction(std::unique_ptr<cmCustomCommand> tcc, CCActionT&& action)
-      : CCAction(std::move(action))
+    GeneratorAction(
+      std::unique_ptr<cmCustomCommand> tcc, CCActionT&& action,
+      GeneratorActionWhen when = GeneratorActionWhen::AfterConfigure)
+      : When(when)
+      , CCAction(std::move(action))
       , cc(std::move(tcc))
     {
     }
 
-    void operator()(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt);
+    void operator()(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+                    GeneratorActionWhen when);
 
   private:
+    GeneratorActionWhen When;
+
     ActionT Action;
 
     // FIXME: Use std::variant
@@ -190,6 +207,7 @@ public:
    * the makefile.
    */
   void Generate(cmLocalGenerator& lg);
+  void GenerateAfterGeneratorTargets(cmLocalGenerator& lg);
 
   /**
    * Get the target for PRE_BUILD, PRE_LINK, or POST_BUILD commands.

+ 16 - 0
Source/cmNinjaTargetGenerator.cxx

@@ -22,6 +22,7 @@
 #include <cm3p/json/value.h>
 #include <cm3p/json/writer.h>
 
+#include "cmBuildDatabase.h"
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommandGenerator.h"
 #include "cmDyndepCollation.h"
@@ -1232,6 +1233,21 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
                language, "Modules.json"));
     build.ImplicitDeps.emplace_back(
       this->GetTargetDependInfoPath(language, config));
+    {
+      auto bdb_path =
+        this->GeneratorTarget->BuildDatabasePath(language, config);
+      if (!bdb_path.empty()) {
+        build.ImplicitOuts.emplace_back(this->ConvertToNinjaPath(bdb_path));
+      }
+    }
+    auto bdb_path = this->GeneratorTarget->BuildDatabasePath(language, config);
+    if (!bdb_path.empty()) {
+      auto db = cmBuildDatabase::ForTarget(this->GeneratorTarget, config);
+      auto mcdb_template_path = cmStrCat(bdb_path, ".in");
+      db.Write(mcdb_template_path);
+      build.ImplicitDeps.emplace_back(std::move(mcdb_template_path));
+      build.ImplicitOuts.emplace_back(std::move(bdb_path));
+    }
     for (auto const& scanFiles : scanningFiles) {
       if (!scanFiles.ScanningOutput.empty()) {
         build.ExplicitDeps.push_back(scanFiles.ScanningOutput);

+ 16 - 0
Source/cmTarget.cxx

@@ -598,6 +598,7 @@ TargetProperty const StaticTargetProperties[] = {
 
   // Metadata
   { "CROSSCOMPILING_EMULATOR"_s, IC::ExecutableTarget },
+  { "EXPORT_BUILD_DATABASE"_s, IC::CanCompileSources },
   { "EXPORT_COMPILE_COMMANDS"_s, IC::CanCompileSources },
   { "FOLDER"_s },
   { "TEST_LAUNCHER"_s, IC::ExecutableTarget },
@@ -645,6 +646,7 @@ public:
   cmStateEnums::TargetType TargetType;
   cmMakefile* Makefile;
   cmPolicies::PolicyMap PolicyMap;
+  cmTarget const* TemplateTarget;
   std::string Name;
   std::string InstallPath;
   std::string RuntimeInstallPath;
@@ -931,6 +933,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
   this->impl->TargetType = type;
   this->impl->Makefile = mf;
   this->impl->Name = name;
+  this->impl->TemplateTarget = nullptr;
   this->impl->IsGeneratorProvided = false;
   this->impl->HaveInstallRule = false;
   this->impl->IsDLLPlatform = false;
@@ -1186,6 +1189,14 @@ const std::string& cmTarget::GetName() const
   return this->impl->Name;
 }
 
+const std::string& cmTarget::GetTemplateName() const
+{
+  if (this->impl->TemplateTarget) {
+    return this->impl->TemplateTarget->GetTemplateName();
+  }
+  return this->impl->Name;
+}
+
 cmPolicies::PolicyStatus cmTarget::GetPolicyStatus(
   cmPolicies::PolicyID policy) const
 {
@@ -1784,6 +1795,7 @@ void cmTarget::CopyPolicyStatuses(cmTarget const* tgt)
   assert(tgt->IsImported());
 
   this->impl->PolicyMap = tgt->impl->PolicyMap;
+  this->impl->TemplateTarget = tgt;
 }
 
 void cmTarget::CopyImportedCxxModulesEntries(cmTarget const* tgt)
@@ -1884,6 +1896,10 @@ void cmTarget::CopyImportedCxxModulesProperties(cmTarget const* tgt)
     // Metadata
     "EchoString",
     "EXPORT_COMPILE_COMMANDS",
+    // Do *not* copy this property; it should be re-initialized at synthesis
+    // time from the `CMAKE_EXPORT_BUILD_DATABASE` variable as `IMPORTED`
+    // targets ignore the property initialization.
+    // "EXPORT_BUILD_DATABASE",
     "FOLDER",
     "LABELS",
     "PROJECT_LABEL",

+ 1 - 0
Source/cmTarget.h

@@ -78,6 +78,7 @@ public:
 
   //! Set/Get the name of the target
   const std::string& GetName() const;
+  const std::string& GetTemplateName() const;
 
   //! Get the policy map
   cmPolicies::PolicyMap const& GetPolicyMap() const;

+ 8 - 0
Source/cmcmd.cxx

@@ -78,6 +78,9 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
                               std::vector<std::string>::const_iterator argEnd);
 int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
                              std::vector<std::string>::const_iterator argEnd);
+int cmcmd_cmake_module_compile_db(
+  std::vector<std::string>::const_iterator argBeg,
+  std::vector<std::string>::const_iterator argEnd);
 
 namespace {
 // ATTENTION If you add new commands, change here,
@@ -1394,6 +1397,11 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
     }
 #endif
 
+    // Internal CMake C++ module compilation database support.
+    if (args[1] == "cmake_module_compile_db") {
+      return cmcmd_cmake_module_compile_db(args.begin() + 2, args.end());
+    }
+
     // Internal CMake unimplemented feature notification.
     if (args[1] == "cmake_unimplemented_variable") {
       std::cerr << "Feature not implemented for this platform.";

+ 2 - 0
Tests/RunCMake/CXXModules/Inspect.cmake

@@ -42,6 +42,8 @@ set(CMAKE_CXX_OUTPUT_EXTENSION \"${CMAKE_CXX_OUTPUT_EXTENSION}\")
 set(CXXModules_default_build_type \"${CMAKE_BUILD_TYPE}\")
 set(CMAKE_CXX_STANDARD_DEFAULT \"${CMAKE_CXX_STANDARD_DEFAULT}\")
 set(CMAKE_CXX20_STANDARD_COMPILE_OPTION \"${CMAKE_CXX20_STANDARD_COMPILE_OPTION}\")
+set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT \"${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}\")
+set(CMAKE_CXX_MODULE_MAP_FORMAT \"${CMAKE_CXX_MODULE_MAP_FORMAT}\")
 ")
 
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}")

+ 39 - 0
Tests/RunCMake/CXXModules/NinjaDependInfoCompileDatabase-check.cmake

@@ -0,0 +1,39 @@
+include("${CMAKE_CURRENT_LIST_DIR}/check-json.cmake")
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(have_file 0)
+  foreach (CXXModules_config IN ITEMS Release Debug RelWithDebInfo MinSizeRel)
+    if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/ninja-compiledb-public.dir/${CXXModules_config}/CXXDependInfo.json")
+      continue ()
+    endif ()
+    set(have_file 1)
+
+    set(CMAKE_BUILD_TYPE "${CXXModules_config}")
+
+    file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/ninja-compiledb-public.dir/${CXXModules_config}/CXXDependInfo.json" actual_contents)
+    file(READ "${CMAKE_CURRENT_LIST_DIR}/expect/NinjaDependInfoCompileDatabase-public.json" expect_contents)
+    check_json("${actual_contents}" "${expect_contents}")
+
+    file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/ninja-compiledb-private.dir/${CXXModules_config}/CXXDependInfo.json" actual_contents)
+    file(READ "${CMAKE_CURRENT_LIST_DIR}/expect/NinjaDependInfoCompileDatabase-private.json" expect_contents)
+    check_json("${actual_contents}" "${expect_contents}")
+  endforeach ()
+
+  if (NOT have_file)
+    list(APPEND RunCMake_TEST_FAILED
+      "No recognized build configurations found.")
+  endif ()
+else ()
+  set(CXXModules_config "${CXXModules_default_build_type}")
+  set(CMAKE_BUILD_TYPE "${CXXModules_default_build_type}")
+
+  file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/ninja-compiledb-public.dir/CXXDependInfo.json" actual_contents)
+  file(READ "${CMAKE_CURRENT_LIST_DIR}/expect/NinjaDependInfoCompileDatabase-public.json" expect_contents)
+  check_json("${actual_contents}" "${expect_contents}")
+
+  file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/ninja-compiledb-private.dir/CXXDependInfo.json" actual_contents)
+  file(READ "${CMAKE_CURRENT_LIST_DIR}/expect/NinjaDependInfoCompileDatabase-private.json" expect_contents)
+  check_json("${actual_contents}" "${expect_contents}")
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 4 - 0
Tests/RunCMake/CXXModules/NinjaDependInfoCompileDatabase-stderr.txt

@@ -0,0 +1,4 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+  CMake's support for exporting build databases is experimental.  It is meant
+  only for experimentation and feedback to CMake developers.
+This warning is for project developers.  Use -Wno-dev to suppress it.

+ 54 - 0
Tests/RunCMake/CXXModules/NinjaDependInfoCompileDatabase.cmake

@@ -0,0 +1,54 @@
+# Fake out that we have dyndep; we only need to generate, not actually build
+# here.
+set(CMAKE_CXX_SCANDEP_SOURCE "")
+
+set(CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE "4bd552e2-b7fb-429a-ab23-c83ef53f3f13")
+
+enable_language(CXX)
+
+if (NOT CMAKE_GENERATOR MATCHES "Ninja")
+  message(FATAL_ERROR
+    "This test requires a 'Ninja' generator to be used.")
+endif ()
+
+add_library(ninja-compiledb-public)
+target_sources(ninja-compiledb-public
+  PRIVATE
+    sources/module-impl.cxx
+    sources/module-internal-part-impl.cxx
+    sources/module-part-impl.cxx
+  PUBLIC
+    FILE_SET modules TYPE CXX_MODULES
+    BASE_DIRS
+      "${CMAKE_CURRENT_SOURCE_DIR}/sources"
+    FILES
+      sources/module.cxx
+      sources/module-part.cxx
+    FILE_SET internal_partitions TYPE CXX_MODULES FILES
+      sources/module-internal-part.cxx)
+target_compile_features(ninja-compiledb-public
+  PRIVATE
+    cxx_std_20)
+set_property(TARGET ninja-compiledb-public
+  PROPERTY EXPORT_BUILD_DATABASE 1)
+
+add_library(ninja-compiledb-private)
+target_sources(ninja-compiledb-private
+  PRIVATE
+    sources/module-impl.cxx
+    sources/module-internal-part-impl.cxx
+    sources/module-part-impl.cxx
+  PRIVATE
+    FILE_SET modules TYPE CXX_MODULES
+    BASE_DIRS
+      "${CMAKE_CURRENT_SOURCE_DIR}/sources"
+    FILES
+      sources/module.cxx
+      sources/module-part.cxx
+    FILE_SET internal_partitions TYPE CXX_MODULES FILES
+      sources/module-internal-part.cxx)
+target_compile_features(ninja-compiledb-private
+  PRIVATE
+    cxx_std_20)
+set_property(TARGET ninja-compiledb-private
+  PROPERTY EXPORT_BUILD_DATABASE 1)

+ 69 - 45
Tests/RunCMake/CXXModules/RunCMakeTest.cmake

@@ -119,6 +119,7 @@ if (RunCMake_GENERATOR MATCHES "Ninja")
   run_cmake(NinjaDependInfoExportFilesystemSafe)
   run_cmake(NinjaDependInfoBMIInstall)
   run_cmake(NinjaForceResponseFile) # issue#25367
+  run_cmake(NinjaDependInfoCompileDatabase)
 elseif (RunCMake_GENERATOR MATCHES "Visual Studio")
   run_cmake(VisualStudioNoSyntheticTargets)
 else ()
@@ -162,6 +163,16 @@ function (run_cxx_module_test directory)
     run_cmake_command("examples/${test_name}-build" "${CMAKE_COMMAND}" --build . --config Debug --target "${RunCMake_CXXModules_TARGET}")
   else ()
     run_cmake_command("examples/${test_name}-build" "${CMAKE_COMMAND}" --build . --config Debug)
+    foreach (RunCMake_CXXModules_TARGET IN LISTS RunCMake_CXXModules_TARGETS)
+      set(RunCMake_CXXModules_CONFIG "Debug")
+      set(RunCMake_CXXModules_NAME_SUFFIX "")
+      if (RunCMake_CXXModules_TARGET MATCHES "(.*)@(.*)")
+        set(RunCMake_CXXModules_TARGET "${CMAKE_MATCH_1}")
+        set(RunCMake_CXXModules_CONFIG "${CMAKE_MATCH_2}")
+        set(RunCMake_CXXModules_NAME_SUFFIX "-${RunCMake_CXXModules_CONFIG}")
+      endif ()
+      run_cmake_command("examples/${test_name}-target-${RunCMake_CXXModules_TARGET}${RunCMake_CXXModules_NAME_SUFFIX}" "${CMAKE_COMMAND}" --build . --target "${RunCMake_CXXModules_TARGET}" --config "${RunCMake_CXXModules_CONFIG}")
+    endforeach ()
   endif ()
   if (RunCMake_CXXModules_INSTALL)
     run_cmake_command("examples/${test_name}-install" "${CMAKE_COMMAND}" --build . --target install --config Debug)
@@ -276,6 +287,32 @@ if ("compile_commands" IN_LIST CMake_TEST_MODULE_COMPILATION)
   run_cxx_module_test(export-compile-commands)
 endif ()
 
+macro (setup_export_build_database_targets)
+  set(RunCMake_CXXModules_TARGETS
+    cmake_build_database-CXX
+    cmake_build_database)
+
+  if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    list(INSERT RunCMake_CXXModules_TARGETS 0
+      cmake_build_database-CXX-Debug
+      cmake_build_database-Debug
+      # Other config targets.
+      cmake_build_database-CXX-Release@Release
+      cmake_build_database-Release@Release)
+  endif ()
+endmacro ()
+
+# Tests which require build database support.
+if ("build_database" IN_LIST CMake_TEST_MODULE_COMPILATION)
+  setup_export_build_database_targets()
+  set(RunCMake_CXXModules_NO_TEST 1)
+
+  run_cxx_module_test(export-build-database)
+
+  unset(RunCMake_CXXModules_NO_TEST)
+  unset(RunCMake_CXXModules_TARGETS)
+endif ()
+
 # Tests which require collation work.
 if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION)
   run_cxx_module_test(public-req-private)
@@ -304,6 +341,17 @@ if ("internal_partitions" IN_LIST CMake_TEST_MODULE_COMPILATION)
   run_cxx_module_test(internal-partitions)
 endif ()
 
+function (run_cxx_module_import_test type name)
+  set(RunCMake_CXXModules_INSTALL 0)
+
+  if ("EXPORT_BUILD_DATABASE" IN_LIST ARGN)
+    list(REMOVE_ITEM ARGN EXPORT_BUILD_DATABASE)
+    list(APPEND ARGN -DCMAKE_EXPORT_BUILD_DATABASE=1)
+  endif ()
+
+  run_cxx_module_test(import-modules "import-modules-${name}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${name}-${type}" ${ARGN})
+endfunction ()
+
 # Tests which install BMIs
 if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
   run_cxx_module_test(export-interface-no-properties-build)
@@ -320,29 +368,22 @@ if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
 
   if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION AND
       "bmionly" IN_LIST CMake_TEST_MODULE_COMPILATION)
-    set(test_suffix export-interface-build)
-    run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build")
-
-    set(test_suffix export-interface-no-properties-build)
-    run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build" -DNO_PROPERTIES=1)
-
-    set(test_suffix export-include-directories-build)
-    run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build" -DINCLUDE_PROPERTIES=1)
-
-    set(test_suffix export-bmi-and-interface-build)
-    run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build" -DWITH_BMIS=1)
+    run_cxx_module_import_test(build export-interface-build)
+    run_cxx_module_import_test(build export-interface-no-properties-build -DNO_PROPERTIES=1)
+    run_cxx_module_import_test(build export-include-directories-build -DINCLUDE_PROPERTIES=1)
+    run_cxx_module_import_test(build export-bmi-and-interface-build -DWITH_BMIS=1)
+    run_cxx_module_import_test(build export-command-sepdir-build -DEXPORT_COMMAND_SEPDIR=1)
+    run_cxx_module_import_test(build export-transitive-targets-build -DTRANSITIVE_TARGETS=1)
+    run_cxx_module_import_test(build export-transitive-modules-build -DTRANSITIVE_MODULES=1)
+    run_cxx_module_import_test(build export-with-headers-build -DWITH_HEADERS=1)
 
-    set(test_suffix export-command-sepdir-build)
-    run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build" -DEXPORT_COMMAND_SEPDIR=1)
+    if ("build_database" IN_LIST CMake_TEST_MODULE_COMPILATION)
+      setup_export_build_database_targets()
 
-    set(test_suffix export-transitive-targets-build)
-    run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build" -DTRANSITIVE_TARGETS=1)
+      run_cxx_module_import_test(build export-build-database -DBUILD_DATABASE=1 EXPORT_BUILD_DATABASE)
 
-    set(test_suffix export-transitive-modules-build)
-    run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build" -DTRANSITIVE_MODULES=1)
-
-    set(test_suffix export-with-headers-build)
-    run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build" -DWITH_HEADERS=1)
+      unset(RunCMake_CXXModules_TARGETS)
+    endif ()
   endif ()
 endif ()
 
@@ -369,31 +410,14 @@ if ("install_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
 
     if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION AND
         "bmionly" IN_LIST CMake_TEST_MODULE_COMPILATION)
-      set(RunCMake_CXXModules_INSTALL 0)
-      set(test_suffix export-interface-install)
-      run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install")
-
-      set(test_suffix export-interface-no-properties-install)
-      run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install" -DNO_PROPERTIES=1)
-
-      set(test_suffix export-include-directories-install)
-      run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install" -DINCLUDE_PROPERTIES=1)
-
-      set(test_suffix export-bmi-and-interface-install)
-      run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install" -DWITH_BMIS=1)
-
-      set(test_suffix export-command-sepdir-install)
-      run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install" -DEXPORT_COMMAND_SEPDIR=1)
-
-      set(test_suffix export-transitive-targets-install)
-      run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install" -DTRANSITIVE_TARGETS=1)
-
-      set(test_suffix export-transitive-modules-install)
-      run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install" -DTRANSITIVE_MODULES=1)
-
-      set(test_suffix export-with-headers-install)
-      run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install" -DWITH_HEADERS=1)
-      set(RunCMake_CXXModules_INSTALL 1)
+      run_cxx_module_import_test(install export-interface-install)
+      run_cxx_module_import_test(install export-interface-no-properties-install -DNO_PROPERTIES=1)
+      run_cxx_module_import_test(install export-include-directories-install -DINCLUDE_PROPERTIES=1)
+      run_cxx_module_import_test(install export-bmi-and-interface-install -DWITH_BMIS=1)
+      run_cxx_module_import_test(install export-command-sepdir-install -DEXPORT_COMMAND_SEPDIR=1)
+      run_cxx_module_import_test(install export-transitive-targets-install -DTRANSITIVE_TARGETS=1)
+      run_cxx_module_import_test(install export-transitive-modules-install -DTRANSITIVE_MODULES=1)
+      run_cxx_module_import_test(install export-with-headers-install -DWITH_HEADERS=1)
     endif ()
   endif ()
 endif ()

+ 65 - 1
Tests/RunCMake/CXXModules/check-json.cmake

@@ -3,19 +3,48 @@ cmake_policy(SET CMP0057 NEW)
 
 function (json_placeholders in out)
   string(REPLACE "<CONFIG>" "${CXXModules_config}" in "${in}")
+  string(TOLOWER "${CXXModules_config}" config_lower)
+  string(REPLACE "<CONFIG_LOWER>" "${config_lower}" in "${in}")
+  string(REPLACE "<CONFIG_OTHER>" "${CXXModules_config_other}" in "${in}")
+  string(TOLOWER "${CXXModules_config_other}" config_lower)
+  string(REPLACE "<CONFIG_OTHER_LOWER>" "${config_lower}" in "${in}")
   if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
     string(REPLACE "<CONFIG_DIR>" "/${CXXModules_config}" in "${in}")
+    string(REPLACE "<CONFIG_OTHER_DIR>" "/${CXXModules_config_other}" in "${in}")
   else ()
     string(REPLACE "<CONFIG_DIR>" "" in "${in}")
+    string(REPLACE "<CONFIG_OTHER_DIR>" "" in "${in}")
   endif ()
   if (CMAKE_BUILD_TYPE)
     string(REPLACE "<CONFIG_FORCE>" "${CXXModules_config}" in "${in}")
+    string(REPLACE "<CONFIG_OTHER_FORCE>" "${CXXModules_config_other}" in "${in}")
   else ()
     string(REPLACE "<CONFIG_FORCE>" "noconfig" in "${in}")
   endif ()
   string(REPLACE "<SOURCE_DIR>" "${RunCMake_SOURCE_DIR}" in "${in}")
   string(REPLACE "<BINARY_DIR>" "${RunCMake_TEST_BINARY_DIR}" in "${in}")
   string(REPLACE "<OBJEXT>" "${CMAKE_CXX_OUTPUT_EXTENSION}" in "${in}")
+  if (CMAKE_CXX_MODULE_MAP_FORMAT STREQUAL "gcc")
+    set(bmiflag "-fmodule-only")
+    set(bmiext "gcm")
+  elseif (CMAKE_CXX_MODULE_MAP_FORMAT STREQUAL "clang")
+    set(bmiflag "--precompile")
+    set(bmiext "pcm")
+  elseif (CMAKE_CXX_MODULE_MAP_FORMAT STREQUAL "msvc")
+    set(bmiflag "-ifcOutput.*")
+    set(bmiext "ifc")
+  endif ()
+  string(REPLACE "<BMI_ONLY_FLAG>" "${bmiflag}" in "${in}")
+  string(REPLACE "<BMIEXT>" ".${bmiext}" in "${in}")
+  set(output_flag "-o")
+  if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
+    set(output_flag "-Fo")
+  endif ()
+  string(REPLACE "<OUTPUT_FLAG>" "${output_flag}" in "${in}")
+  string(REPLACE "<CXX20_OPTION>" "${CMAKE_CXX20_STANDARD_COMPILE_OPTION}" in "${in}")
+  string(REPLACE "<HEX>" "[0-9a-f]+" in "${in}")
+  string(REPLACE "REGEX:" "" in "${in}")
+  string(REPLACE "PATH:" "" in "${in}")
   set("${out}" "${in}" PARENT_SCOPE)
 endfunction ()
 
@@ -46,7 +75,26 @@ function (check_json_value path actual_type expect_type actual_value expect_valu
     endif ()
 
     json_placeholders("${expect_value}" expect_value_expanded)
-    if (NOT actual_value STREQUAL expect_value_expanded)
+    if (expect_value MATCHES "^REGEX:PATH:")
+      string(REPLACE "\\" "/" actual_value_check "${actual_value}")
+      string(REGEX REPLACE "^\"(.*)\"$" "\\1" actual_value_check "${actual_value_check}")
+      if (NOT actual_value_check MATCHES "^${expect_value_expanded}$")
+        list(APPEND RunCMake_TEST_FAILED
+          "String mismatch (path regex) at ${path}: ${actual_value} vs. ^${expect_value_expanded}$")
+      endif ()
+    elseif (expect_value MATCHES "^REGEX:")
+      if (NOT actual_value MATCHES "^${expect_value_expanded}$")
+        list(APPEND RunCMake_TEST_FAILED
+          "String mismatch (regex) at ${path}: ${actual_value} vs. ^${expect_value_expanded}$")
+      endif ()
+    elseif (expect_value MATCHES "^PATH:")
+      string(REPLACE "\\" "/" actual_value_check "${actual_value}")
+      string(REGEX REPLACE "^\"(.*)\"$" "\\1" actual_value_check "${actual_value_check}")
+      if (NOT actual_value_check STREQUAL "${expect_value_expanded}")
+        list(APPEND RunCMake_TEST_FAILED
+          "String mismatch (path) at ${path}: ${actual_value} vs. ^${expect_value_expanded}$")
+      endif ()
+    elseif (NOT actual_value STREQUAL expect_value_expanded)
       list(APPEND RunCMake_TEST_FAILED
         "String mismatch at ${path}: ${actual_value} vs. ${expect_value_expanded}")
     endif ()
@@ -61,6 +109,22 @@ endfunction ()
 
 # Check that two arrays are the same.
 function (check_json_array path actual expect)
+  if (item_filter)
+    string(JSON iter_len LENGTH "${actual}")
+    set(idx 0)
+    while (idx LESS iter_len)
+      string(JSON type TYPE "${actual}" "${idx}")
+      string(JSON item GET "${actual}" "${idx}")
+      if (type STREQUAL "STRING" AND
+          item MATCHES "${item_filter}")
+        string(JSON actual REMOVE "${actual}" "${idx}")
+        math(EXPR iter_len "${iter_len} - 1")
+      else ()
+        math(EXPR idx "${idx} + 1")
+      endif ()
+    endwhile ()
+  endif ()
+
   string(JSON actual_len LENGTH "${actual}")
   string(JSON expect_len LENGTH "${expect}")
 

+ 81 - 0
Tests/RunCMake/CXXModules/examples/build-database-check.cmake

@@ -0,0 +1,81 @@
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW)
+
+include("${CMAKE_CURRENT_LIST_DIR}/../check-json.cmake")
+
+function (check_build_database expect_basename fname component)
+  if (component STREQUAL "NO_EXIST")
+    if (EXISTS "${RunCMake_TEST_BINARY_DIR}/${fname}")
+      list(APPEND RunCMake_TEST_FAILED
+        "Build database detected before it is expected (${fname}).")
+      set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+    endif ()
+    return ()
+  endif ()
+
+  if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${fname}")
+    list(APPEND RunCMake_TEST_FAILED
+      "No build database detected (${fname}).")
+    set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+    return ()
+  endif ()
+
+  if (component STREQUAL "ALL")
+    set(CXXModules_config "Debug")
+    set(suffix "all")
+  elseif (component STREQUAL "ALL_MULTI")
+    set(CXXModules_config "Debug")
+    set(CXXModules_config_other "Release")
+    set(suffix "all-multi")
+  elseif (component STREQUAL "JUST_CXX")
+    set(CXXModules_config "Debug")
+    set(suffix "cxx")
+  elseif (component STREQUAL "JUST_CXX_MULTI")
+    set(CXXModules_config "Debug")
+    set(CXXModules_config_other "Release")
+    set(suffix "cxx-multi")
+  elseif (component STREQUAL "CXX_AND_DEBUG")
+    set(CXXModules_config "Debug")
+    set(suffix "cxx-config")
+  elseif (component STREQUAL "CXX_AND_RELEASE")
+    set(CXXModules_config "Release")
+    set(suffix "cxx-config")
+  elseif (component STREQUAL "JUST_DEBUG")
+    set(CXXModules_config "Debug")
+    set(suffix "config")
+  elseif (component STREQUAL "JUST_RELEASE")
+    set(CXXModules_config "Release")
+    set(suffix "config")
+  elseif (component STREQUAL "JUST_TARGET_DEBUG")
+    set(CXXModules_config "Debug")
+    set(suffix "target")
+  elseif (component STREQUAL "JUST_TARGET_RELEASE")
+    set(CXXModules_config "Release")
+    set(suffix "target")
+  elseif (component STREQUAL "JUST_TARGET")
+    set(CXXModules_config "Debug")
+    set(suffix "target")
+  else ()
+    list(APPEND RunCMake_TEST_FAILED
+      "Unrecognized test component for ${fname}: ${component}")
+    set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+    return ()
+  endif ()
+
+  set(expected_file "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/expect/${expect_basename}-${suffix}.json")
+  if (NOT EXISTS "${expected_file}")
+    list(APPEND RunCMake_TEST_FAILED
+      "No expected output JSON file found: ${expected_file}")
+    set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+    return ()
+  endif ()
+
+  file(READ "${RunCMake_TEST_BINARY_DIR}/${fname}" actual)
+  file(READ "${expected_file}" expect)
+
+  check_json("${actual}" "${expect}")
+
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction ()
+
+cmake_policy(POP)

+ 300 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-all-multi.json

@@ -0,0 +1,300 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "export_build_database",
+      "name": "export_build_database@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
+          "work-directory": "<BINARY_DIR>"
+        },
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    },
+    {
+      "family-name": "export_build_database",
+      "name": "export_build_database@<CONFIG_OTHER>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
+          "work-directory": "<BINARY_DIR>"
+        },
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable<BMIEXT>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 153 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-all.json

@@ -0,0 +1,153 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "export_build_database",
+      "name": "export_build_database@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
+          "work-directory": "<BINARY_DIR>"
+        },
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 153 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-config.json

@@ -0,0 +1,153 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "export_build_database",
+      "name": "export_build_database@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
+          "work-directory": "<BINARY_DIR>"
+        },
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 153 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx-config.json

@@ -0,0 +1,153 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "export_build_database",
+      "name": "export_build_database@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
+          "work-directory": "<BINARY_DIR>"
+        },
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 300 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx-multi.json

@@ -0,0 +1,300 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "export_build_database",
+      "name": "export_build_database@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
+          "work-directory": "<BINARY_DIR>"
+        },
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    },
+    {
+      "family-name": "export_build_database",
+      "name": "export_build_database@<CONFIG_OTHER>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
+          "work-directory": "<BINARY_DIR>"
+        },
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable<BMIEXT>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 153 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx.json

@@ -0,0 +1,153 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "export_build_database",
+      "name": "export_build_database@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
+          "work-directory": "<BINARY_DIR>"
+        },
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 278 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-all-multi.json

@@ -0,0 +1,278 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "use_import_interfaces",
+      "name": "use_import_interfaces@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option",
+            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
+          ],
+          "baseline-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "local-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
+    },
+    {
+      "family-name": "use_import_interfaces",
+      "name": "use_import_interfaces@<CONFIG_OTHER>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option",
+            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
+          ],
+          "baseline-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "local-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG_OTHER>"]
+    },
+    {
+      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
+      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option",
+            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
+            "REGEX:<BMI_ONLY_FLAG>",
+            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<IGNORE>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    },
+    {
+      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
+      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG_OTHER>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option",
+            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/.d\"",
+            "REGEX:<BMI_ONLY_FLAG>",
+            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<IGNORE>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 142 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-all.json

@@ -0,0 +1,142 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "use_import_interfaces",
+      "name": "use_import_interfaces@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option",
+            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
+          ],
+          "baseline-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "local-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
+    },
+    {
+      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
+      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option",
+            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
+            "REGEX:<BMI_ONLY_FLAG>",
+            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<IGNORE>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 142 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-config.json

@@ -0,0 +1,142 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "use_import_interfaces",
+      "name": "use_import_interfaces@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option",
+            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
+          ],
+          "baseline-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "local-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
+    },
+    {
+      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
+      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option",
+            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
+            "REGEX:<BMI_ONLY_FLAG>",
+            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<IGNORE>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 142 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx-config.json

@@ -0,0 +1,142 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "use_import_interfaces",
+      "name": "use_import_interfaces@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option",
+            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
+          ],
+          "baseline-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "local-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
+    },
+    {
+      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
+      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option",
+            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
+            "REGEX:<BMI_ONLY_FLAG>",
+            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<IGNORE>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 278 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx-multi.json

@@ -0,0 +1,278 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "use_import_interfaces",
+      "name": "use_import_interfaces@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option",
+            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
+          ],
+          "baseline-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "local-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
+    },
+    {
+      "family-name": "use_import_interfaces",
+      "name": "use_import_interfaces@<CONFIG_OTHER>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option",
+            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
+          ],
+          "baseline-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "local-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG_OTHER>"]
+    },
+    {
+      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
+      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option",
+            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
+            "REGEX:<BMI_ONLY_FLAG>",
+            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<IGNORE>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    },
+    {
+      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
+      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG_OTHER>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option",
+            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/.d\"",
+            "REGEX:<BMI_ONLY_FLAG>",
+            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<IGNORE>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 142 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx.json

@@ -0,0 +1,142 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "use_import_interfaces",
+      "name": "use_import_interfaces@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option",
+            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
+          ],
+          "baseline-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "local-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
+    },
+    {
+      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
+      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option",
+            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
+            "REGEX:<BMI_ONLY_FLAG>",
+            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_interface_define",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dtarget_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<IGNORE>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 59 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-target.json

@@ -0,0 +1,59 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "use_import_interfaces",
+      "name": "use_import_interfaces@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option",
+            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
+          ],
+          "baseline-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "local-arguments": [
+            "-Dtarget_interface_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dtarget_interface_option",
+            "-Dtarget_public_option"
+          ],
+          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
+    }
+  ]
+}

+ 153 - 0
Tests/RunCMake/CXXModules/examples/expect/export-build-database-target.json

@@ -0,0 +1,153 @@
+{
+  "version": 1,
+  "revision": 0,
+  "sets": [
+    {
+      "family-name": "export_build_database",
+      "name": "export_build_database@<CONFIG>",
+      "translation-units": [
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
+          "private": true,
+          "provides": {},
+          "requires": ["importable"],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
+          "work-directory": "<BINARY_DIR>"
+        },
+        {
+          "arguments": [
+            "<IGNORE>",
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option",
+            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+            "-c",
+            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
+          ],
+          "baseline-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option"
+          ],
+          "local-arguments": [
+            "-Ddep_interface_define",
+            "-Dfrom_compile_definitions",
+            "-Dtarget_private_define",
+            "-Dtarget_public_define",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
+            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
+            "-Dfrom_cmake_cxx_flags",
+            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
+            "<CXX20_OPTION>",
+            "-Dfrom_compile_flags",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
+            "-Dtarget_public_option",
+            "-Ddep_interface_option",
+            "-Dfrom_source_flag",
+            "-Dfrom_source_option"
+          ],
+          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
+          "private": true,
+          "provides": {
+            "importable": "<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
+          },
+          "requires": [],
+          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
+          "work-directory": "<BINARY_DIR>"
+        }
+      ],
+      "visible-sets": []
+    }
+  ]
+}

+ 19 - 0
Tests/RunCMake/CXXModules/examples/export-build-database-build-check.cmake

@@ -0,0 +1,19 @@
+include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
+
+check_build_database("export-build-database" "build_database.json" NO_EXIST)
+check_build_database("export-build-database" "build_database_CXX.json" NO_EXIST)
+
+check_build_database("export-build-database" "build_database_CXX_Debug.json" NO_EXIST)
+check_build_database("export-build-database" "build_database_Debug.json" NO_EXIST)
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+  # check_build_database("export-build-database" "build_database_CXX_Release.json" NO_EXIST)
+  # check_build_database("export-build-database" "build_database_Release.json" NO_EXIST)
+  # check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Release/CXX_build_database.json" NO_EXIST)
+else ()
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/CXX_build_database.json" JUST_TARGET)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 19 - 0
Tests/RunCMake/CXXModules/examples/export-build-database-check.cmake

@@ -0,0 +1,19 @@
+include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
+
+check_build_database("export-build-database" "build_database.json" NO_EXIST)
+check_build_database("export-build-database" "build_database_CXX.json" NO_EXIST)
+
+check_build_database("export-build-database" "build_database_CXX_Debug.json" NO_EXIST)
+check_build_database("export-build-database" "build_database_Debug.json" NO_EXIST)
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Debug/CXX_build_database.json" NO_EXIST)
+
+  check_build_database("export-build-database" "build_database_CXX_Release.json" NO_EXIST)
+  check_build_database("export-build-database" "build_database_Release.json" NO_EXIST)
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Release/CXX_build_database.json" NO_EXIST)
+else ()
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/CXX_build_database.json" NO_EXIST)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 39 - 0
Tests/RunCMake/CXXModules/examples/export-build-database-setup.cmake

@@ -0,0 +1,39 @@
+set(CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE "4bd552e2-b7fb-429a-ab23-c83ef53f3f13")
+
+get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if (is_multiconfig)
+  set(CMAKE_CONFIGURATION_TYPES "Debug" "Release")
+endif ()
+
+set(CMAKE_EXPORT_BUILD_DATABASE 1)
+
+# Mock up depfile flags to keep things consistent; we don't need accurate
+# dependency tracking for this test case anyways.
+set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+set(CMAKE_DEPFILE_FLAGS_CXX "-Ddepflag=\\\"<DEP_FILE>\\\"")
+unset(CMAKE_CXX_DEPFILE_EXTENSION_REPLACE)
+
+# Disable MSVC flag injection from CMake abstractions.
+set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "")
+set(CMAKE_MSVC_RUNTIME_LIBRARY "")
+
+if (CMAKE_CXX_MODULE_BMI_ONLY_FLAG MATCHES "ifcOutput")
+  # Make a single flag for BMI-only to make the JSON expectations simpler.
+  set(CMAKE_CXX_MODULE_BMI_ONLY_FLAG
+    "-ifcOnly;-ifcOutput<OBJECT>")
+endif ()
+
+# Disable extensions to keep flag selection simpler.
+set(CMAKE_CXX_EXTENSIONS 0)
+
+if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
+  set(output_flag "-Fo")
+else ()
+  set(output_flag "-o")
+endif ()
+set(CMAKE_CXX_COMPILE_OBJECT
+  "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> ${output_flag}<OBJECT> -c <SOURCE>")
+
+set(CMAKE_CXX_FLAGS "-Dfrom_cmake_cxx_flags")
+set(CMAKE_CXX_FLAGS_DEBUG "-Dfrom_cmake_cxx_debug_flags")
+set(CMAKE_CXX_FLAGS_RELEASE "-Dfrom_cmake_cxx_release_flags")

+ 4 - 0
Tests/RunCMake/CXXModules/examples/export-build-database-stderr.txt

@@ -0,0 +1,4 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+  CMake's support for exporting build databases is experimental.  It is meant
+  only for experimentation and feedback to CMake developers.
+This warning is for project developers.  Use -Wno-dev to suppress it.

+ 21 - 0
Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database-check.cmake

@@ -0,0 +1,21 @@
+include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database" "build_database.json" ALL_MULTI)
+  check_build_database("export-build-database" "build_database_CXX.json" JUST_CXX_MULTI)
+
+  check_build_database("export-build-database" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+  check_build_database("export-build-database" "build_database_Debug.json" JUST_DEBUG)
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+  check_build_database("export-build-database" "build_database_CXX_Release.json" CXX_AND_RELEASE)
+  check_build_database("export-build-database" "build_database_Release.json" JUST_RELEASE)
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
+else ()
+  check_build_database("export-build-database" "build_database.json" ALL)
+  check_build_database("export-build-database" "build_database_CXX.json" JUST_CXX)
+
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/CXX_build_database.json" JUST_TARGET)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 21 - 0
Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database/CXX-check.cmake

@@ -0,0 +1,21 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../build-database-check.cmake")
+
+check_build_database("export-build-database" "build_database.json" NO_EXIST)
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database" "build_database_CXX.json" JUST_CXX_MULTI)
+
+  check_build_database("export-build-database" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+  check_build_database("export-build-database" "build_database_Debug.json" JUST_DEBUG)
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+  check_build_database("export-build-database" "build_database_CXX_Release.json" CXX_AND_RELEASE)
+  check_build_database("export-build-database" "build_database_Release.json" JUST_RELEASE)
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
+else ()
+  check_build_database("export-build-database" "build_database_CXX.json" JUST_CXX)
+
+  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/CXX_build_database.json" JUST_TARGET)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 14 - 0
Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database/CXX/Debug-check.cmake

@@ -0,0 +1,14 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../../build-database-check.cmake")
+
+check_build_database("export-build-database" "build_database.json" NO_EXIST)
+check_build_database("export-build-database" "build_database_CXX.json" NO_EXIST)
+
+check_build_database("export-build-database" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+check_build_database("export-build-database" "build_database_Debug.json" NO_EXIST)
+check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+check_build_database("export-build-database" "build_database_CXX_Release.json" NO_EXIST)
+check_build_database("export-build-database" "build_database_Release.json" NO_EXIST)
+check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Release/CXX_build_database.json" NO_EXIST)
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 14 - 0
Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database/CXX/Release-Release-check.cmake

@@ -0,0 +1,14 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../../build-database-check.cmake")
+
+check_build_database("export-build-database" "build_database.json" NO_EXIST)
+check_build_database("export-build-database" "build_database_CXX.json" NO_EXIST)
+
+check_build_database("export-build-database" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+check_build_database("export-build-database" "build_database_Debug.json" JUST_DEBUG)
+check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+check_build_database("export-build-database" "build_database_CXX_Release.json" CXX_AND_RELEASE)
+check_build_database("export-build-database" "build_database_Release.json" NO_EXIST)
+check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 14 - 0
Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database/Debug-check.cmake

@@ -0,0 +1,14 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../build-database-check.cmake")
+
+check_build_database("export-build-database" "build_database.json" NO_EXIST)
+check_build_database("export-build-database" "build_database_CXX.json" NO_EXIST)
+
+check_build_database("export-build-database" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+check_build_database("export-build-database" "build_database_Debug.json" JUST_DEBUG)
+check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+check_build_database("export-build-database" "build_database_CXX_Release.json" NO_EXIST)
+check_build_database("export-build-database" "build_database_Release.json" NO_EXIST)
+check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Release/CXX_build_database.json" NO_EXIST)
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 14 - 0
Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database/Release-Release-check.cmake

@@ -0,0 +1,14 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../build-database-check.cmake")
+
+check_build_database("export-build-database" "build_database.json" NO_EXIST)
+check_build_database("export-build-database" "build_database_CXX.json" NO_EXIST)
+
+check_build_database("export-build-database" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+check_build_database("export-build-database" "build_database_Debug.json" JUST_DEBUG)
+check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+check_build_database("export-build-database" "build_database_CXX_Release.json" CXX_AND_RELEASE)
+check_build_database("export-build-database" "build_database_Release.json" JUST_RELEASE)
+check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 85 - 0
Tests/RunCMake/CXXModules/examples/export-build-database/CMakeLists.txt

@@ -0,0 +1,85 @@
+cmake_minimum_required(VERSION 3.29)
+project(cxx_modules_export_build_database CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+include("${CMAKE_SOURCE_DIR}/../export-build-database-setup.cmake")
+
+add_compile_options(-Dfrom_compile_options)
+add_compile_definitions(-Dfrom_compile_definitions)
+include_directories(from_include_directories)
+
+add_library(provide_flags INTERFACE)
+target_compile_options(provide_flags
+  INTERFACE
+    -Ddep_interface_option)
+target_compile_definitions(provide_flags
+  INTERFACE
+    dep_interface_define)
+target_include_directories(provide_flags
+  INTERFACE
+    dep_interface_include)
+
+add_library(export_build_database)
+target_sources(export_build_database
+  PRIVATE
+    lib.cxx
+  PUBLIC
+    FILE_SET modules
+      TYPE CXX_MODULES
+      BASE_DIRS
+        "${CMAKE_CURRENT_SOURCE_DIR}"
+      FILES
+        importable.cxx)
+target_compile_features(export_build_database PUBLIC cxx_std_20)
+target_link_libraries(export_build_database
+  PRIVATE
+    provide_flags)
+
+set_property(SOURCE importable.cxx APPEND
+  PROPERTY COMPILE_FLAGS "-Dfrom_source_flag")
+set_property(SOURCE importable.cxx APPEND
+  PROPERTY COMPILE_OPTIONS "-Dfrom_source_option")
+set_property(SOURCE importable.cxx APPEND
+  PROPERTY COMPILE_DEFINITIONS "from_source_define")
+
+set_property(TARGET export_build_database APPEND
+  PROPERTY COMPILE_FLAGS "-Dfrom_compile_flags")
+target_compile_options(export_build_database
+  PRIVATE
+    -Dtarget_private_option
+  INTERFACE
+    -Dtarget_interface_option
+  PUBLIC
+    -Dtarget_public_option)
+target_compile_definitions(export_build_database
+  PRIVATE
+    target_private_define
+  INTERFACE
+    target_interface_define
+  PUBLIC
+    target_public_define)
+target_include_directories(export_build_database
+  PRIVATE
+    target_private_include
+  INTERFACE
+    target_interface_include
+  PUBLIC
+    target_public_include)
+
+install(TARGETS export_build_database
+  EXPORT CXXModules
+  FILE_SET modules DESTINATION "lib/cxx/miu")
+export(EXPORT CXXModules
+  NAMESPACE CXXModules::
+  FILE "${CMAKE_CURRENT_BINARY_DIR}/export_build_database-targets.cmake")
+install(TARGETS provide_flags
+  EXPORT CXXModulesDeps)
+export(EXPORT CXXModulesDeps
+  NAMESPACE CXXModules::
+  FILE "${CMAKE_CURRENT_BINARY_DIR}/export_build_database-dep-targets.cmake")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_build_database-config.cmake"
+  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_build_database-dep-targets.cmake\")
+include(\"\${CMAKE_CURRENT_LIST_DIR}/export_build_database-targets.cmake\")
+set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
+")

+ 0 - 0
Tests/RunCMake/CXXModules/examples/export-build-database/dep_interface_include/anchor


+ 6 - 0
Tests/RunCMake/CXXModules/examples/export-build-database/importable.cxx

@@ -0,0 +1,6 @@
+export module importable;
+
+export int from_import()
+{
+  return 0;
+}

+ 6 - 0
Tests/RunCMake/CXXModules/examples/export-build-database/lib.cxx

@@ -0,0 +1,6 @@
+import importable;
+
+int f()
+{
+  return from_import();
+}

+ 0 - 0
Tests/RunCMake/CXXModules/examples/export-build-database/target_interface_include/anchor


+ 0 - 0
Tests/RunCMake/CXXModules/examples/export-build-database/target_public_include/anchor


+ 18 - 0
Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-build-check.cmake

@@ -0,0 +1,18 @@
+include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
+set(item_filter "-ifcOnly")
+
+check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
+check_build_database("export-build-database-imported" "build_database_CXX.json" NO_EXIST)
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "build_database_Debug.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/Debug/CXX_build_database.json" NO_EXIST)
+
+  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "build_database_Release.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/Release/CXX_build_database.json" NO_EXIST)
+else ()
+  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/CXX_build_database.json" NO_EXIST)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 18 - 0
Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-check.cmake

@@ -0,0 +1,18 @@
+include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
+set(item_filter "-ifcOnly")
+
+check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
+check_build_database("export-build-database-imported" "build_database_CXX.json" NO_EXIST)
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "build_database_Debug.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/Debug/CXX_build_database.json" NO_EXIST)
+
+  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "build_database_Release.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/Release/CXX_build_database.json" NO_EXIST)
+else ()
+  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/CXX_build_database.json" NO_EXIST)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 4 - 0
Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-stderr.txt

@@ -0,0 +1,4 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+  CMake's support for exporting build databases is experimental.  It is meant
+  only for experimentation and feedback to CMake developers.
+This warning is for project developers.  Use -Wno-dev to suppress it.

+ 22 - 0
Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database-check.cmake

@@ -0,0 +1,22 @@
+include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
+set(item_filter "-ifcOnly")
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database-imported" "build_database.json" ALL_MULTI)
+  check_build_database("export-build-database-imported" "build_database_CXX.json" JUST_CXX_MULTI)
+
+  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+  check_build_database("export-build-database-imported" "build_database_Debug.json" JUST_DEBUG)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" CXX_AND_RELEASE)
+  check_build_database("export-build-database-imported" "build_database_Release.json" JUST_RELEASE)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
+else ()
+  check_build_database("export-build-database-imported" "build_database.json" ALL)
+  check_build_database("export-build-database-imported" "build_database_CXX.json" JUST_CXX)
+
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 22 - 0
Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX-check.cmake

@@ -0,0 +1,22 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../build-database-check.cmake")
+set(item_filter "-ifcOnly")
+
+check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database-imported" "build_database_CXX.json" JUST_CXX_MULTI)
+
+  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+  check_build_database("export-build-database-imported" "build_database_Debug.json" JUST_DEBUG)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" CXX_AND_RELEASE)
+  check_build_database("export-build-database-imported" "build_database_Release.json" JUST_RELEASE)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
+else ()
+  check_build_database("export-build-database-imported" "build_database_CXX.json" JUST_CXX)
+
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 19 - 0
Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX/Debug-check.cmake

@@ -0,0 +1,19 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../../build-database-check.cmake")
+set(item_filter "-ifcOnly")
+
+check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
+check_build_database("export-build-database-imported" "build_database_CXX.json" NO_EXIST)
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+  check_build_database("export-build-database-imported" "build_database_Debug.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "build_database_Release.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" NO_EXIST)
+else ()
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 19 - 0
Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX/Release-Release-check.cmake

@@ -0,0 +1,19 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../../build-database-check.cmake")
+set(item_filter "-ifcOnly")
+
+check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
+check_build_database("export-build-database-imported" "build_database_CXX.json" NO_EXIST)
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+  check_build_database("export-build-database-imported" "build_database_Debug.json" JUST_DEBUG)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" CXX_AND_RELEASE)
+  check_build_database("export-build-database-imported" "build_database_Release.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
+else ()
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 19 - 0
Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/Debug-check.cmake

@@ -0,0 +1,19 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../build-database-check.cmake")
+set(item_filter "-ifcOnly")
+
+check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
+check_build_database("export-build-database-imported" "build_database_CXX.json" NO_EXIST)
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+  check_build_database("export-build-database-imported" "build_database_Debug.json" JUST_DEBUG)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "build_database_Release.json" NO_EXIST)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" NO_EXIST)
+else ()
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 19 - 0
Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/Release-check.cmake

@@ -0,0 +1,19 @@
+include("${CMAKE_CURRENT_LIST_DIR}/../build-database-check.cmake")
+set(item_filter "-ifcOnly")
+
+check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
+check_build_database("export-build-database-imported" "build_database_CXX.json" JUST_CXX)
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
+  check_build_database("export-build-database-imported" "build_database_Debug.json" JUST_DEBUG)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
+
+  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" CXX_AND_RELEASE)
+  check_build_database("export-build-database-imported" "build_database_Release.json" JUST_RELEASE)
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
+else ()
+  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
+endif ()
+
+string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")

+ 22 - 0
Tests/RunCMake/CXXModules/examples/import-modules/CMakeLists.txt

@@ -19,12 +19,25 @@ elseif (TRANSITIVE_MODULES)
   set(package_name "export_transitive_modules")
 elseif (WITH_HEADERS)
   set(package_name "export_with_headers")
+elseif (BUILD_DATABASE)
+  include("${CMAKE_SOURCE_DIR}/../export-build-database-setup.cmake")
+  set(package_name "export_build_database")
 else ()
   set(package_name "export_interfaces")
 endif ()
 set(target_name "CXXModules::${package_name}")
 
 find_package("${package_name}" REQUIRED)
+if (BUILD_DATABASE)
+  # Remove `-isystem` flags for better flag checking consistency.
+  set_property(TARGET "CXXModules::${package_name}" "CXXModules::provide_flags"
+    PROPERTY SYSTEM 0)
+  # Disable debug and runtime flag injection.
+  set_property(TARGET "CXXModules::${package_name}"
+    PROPERTY MSVC_DEBUG_INFORMATION_FORMAT "")
+  set_property(TARGET "CXXModules::${package_name}"
+    PROPERTY MSVC_RUNTIME_LIBRARY "")
+endif ()
 
 add_executable(use_import_interfaces)
 target_sources(use_import_interfaces
@@ -32,5 +45,14 @@ target_sources(use_import_interfaces
     use.cxx)
 target_compile_features(use_import_interfaces PRIVATE cxx_std_20)
 target_link_libraries(use_import_interfaces PRIVATE "${target_name}")
+if (BUILD_DATABASE AND
+    # Detect Clang targeting MSVC ABI.
+    CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
+  # Link to `libcmt.lib`. Build database tests neuter the runtime library
+  # selection to make flag matching easier. Manually perform the "link the
+  # runtime library" injected into the object files by the runtime library
+  # flag.
+  target_link_libraries(use_import_interfaces PRIVATE libcmt)
+endif ()
 
 add_test(NAME use_import_interfaces COMMAND use_import_interfaces)

+ 3 - 1
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>",
@@ -47,5 +48,6 @@
   "language": "CXX",
   "forward-modules-from-target-dirs": [],
   "linked-target-dirs": [],
-  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-bmi-install-private.dir<CONFIG_DIR>"
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-bmi-install-private.dir<CONFIG_DIR>",
+  "sources": {}
 }

+ 3 - 1
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>",
@@ -47,5 +48,6 @@
   "language": "CXX",
   "forward-modules-from-target-dirs": [],
   "linked-target-dirs": [],
-  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-bmi-install-public.dir<CONFIG_DIR>"
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-bmi-install-public.dir<CONFIG_DIR>",
+  "sources": {}
 }

+ 51 - 0
Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-private.json

@@ -0,0 +1,51 @@
+{
+  "bmi-installation": null,
+  "compiler-id": "<IGNORE>",
+  "compiler-frontend-variant": "<IGNORE>",
+  "compiler-simulate-id": "<IGNORE>",
+  "config": "<CONFIG>",
+  "cxx-modules": {
+    "CMakeFiles/ninja-compiledb-private.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
+      "bmi-only": false,
+      "destination": null,
+      "name": "internal_partitions",
+      "relative-directory": "sources",
+      "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PRIVATE"
+    },
+    "CMakeFiles/ninja-compiledb-private.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
+      "bmi-only": false,
+      "destination": null,
+      "name": "modules",
+      "relative-directory": "",
+      "source": "<SOURCE_DIR>/sources/module-part.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PRIVATE"
+    },
+    "CMakeFiles/ninja-compiledb-private.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
+      "bmi-only": false,
+      "destination": null,
+      "name": "modules",
+      "relative-directory": "",
+      "source": "<SOURCE_DIR>/sources/module.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PRIVATE"
+    }
+  },
+  "database-info": {
+    "template-path": "<BINARY_DIR>/CMakeFiles/ninja-compiledb-private.dir<CONFIG_DIR>/CXX_build_database.json.in",
+    "output": "<BINARY_DIR>/CMakeFiles/ninja-compiledb-private.dir<CONFIG_DIR>/CXX_build_database.json"
+  },
+  "dir-cur-bld": "<BINARY_DIR>",
+  "dir-cur-src": "<SOURCE_DIR>",
+  "dir-top-bld": "<BINARY_DIR>",
+  "dir-top-src": "<SOURCE_DIR>",
+  "exports": [],
+  "forward-modules-from-target-dirs": [],
+  "include-dirs": [],
+  "language": "CXX",
+  "linked-target-dirs": [],
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-compiledb-private.dir<CONFIG_DIR>",
+  "sources": {}
+}

+ 51 - 0
Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-public.json

@@ -0,0 +1,51 @@
+{
+  "bmi-installation": null,
+  "compiler-id": "<IGNORE>",
+  "compiler-frontend-variant": "<IGNORE>",
+  "compiler-simulate-id": "<IGNORE>",
+  "config": "<CONFIG>",
+  "cxx-modules": {
+    "CMakeFiles/ninja-compiledb-public.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
+      "bmi-only": false,
+      "destination": null,
+      "name": "internal_partitions",
+      "relative-directory": "sources",
+      "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PUBLIC"
+    },
+    "CMakeFiles/ninja-compiledb-public.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
+      "bmi-only": false,
+      "destination": null,
+      "name": "modules",
+      "relative-directory": "",
+      "source": "<SOURCE_DIR>/sources/module-part.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PUBLIC"
+    },
+    "CMakeFiles/ninja-compiledb-public.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
+      "bmi-only": false,
+      "destination": null,
+      "name": "modules",
+      "relative-directory": "",
+      "source": "<SOURCE_DIR>/sources/module.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PUBLIC"
+    }
+  },
+  "database-info": {
+    "template-path": "<BINARY_DIR>/CMakeFiles/ninja-compiledb-public.dir<CONFIG_DIR>/CXX_build_database.json.in",
+    "output": "<BINARY_DIR>/CMakeFiles/ninja-compiledb-public.dir<CONFIG_DIR>/CXX_build_database.json"
+  },
+  "dir-cur-bld": "<BINARY_DIR>",
+  "dir-cur-src": "<SOURCE_DIR>",
+  "dir-top-bld": "<BINARY_DIR>",
+  "dir-top-src": "<SOURCE_DIR>",
+  "exports": [],
+  "forward-modules-from-target-dirs": [],
+  "include-dirs": [],
+  "language": "CXX",
+  "linked-target-dirs": [],
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-compiledb-public.dir<CONFIG_DIR>",
+  "sources": {}
+}

+ 3 - 1
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>",
@@ -79,5 +80,6 @@
   "language": "CXX",
   "forward-modules-from-target-dirs": [],
   "linked-target-dirs": [],
-  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>"
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>",
+  "sources": {}
 }

+ 3 - 1
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>",
@@ -79,5 +80,6 @@
   "language": "CXX",
   "forward-modules-from-target-dirs": [],
   "linked-target-dirs": [],
-  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>"
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>",
+  "sources": {}
 }

+ 3 - 1
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>",
@@ -79,5 +80,6 @@
   "language": "CXX",
   "forward-modules-from-target-dirs": [],
   "linked-target-dirs": [],
-  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>"
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>",
+  "sources": {}
 }

+ 3 - 1
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>",
@@ -79,5 +80,6 @@
   "language": "CXX",
   "forward-modules-from-target-dirs": [],
   "linked-target-dirs": [],
-  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>"
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>",
+  "sources": {}
 }

+ 20 - 1
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>",
@@ -42,5 +43,23 @@
   "language": "CXX",
   "forward-modules-from-target-dirs": [],
   "linked-target-dirs": [],
-  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-file-sets-private.dir<CONFIG_DIR>"
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-file-sets-private.dir<CONFIG_DIR>",
+  "sources": {
+    "CMakeFiles/ninja-file-sets-private.dir/sources/module-impl.cxx<OBJEXT>" : {
+      "language" : "CXX",
+      "source" : "<SOURCE_DIR>/sources/module-impl.cxx"
+    },
+    "CMakeFiles/ninja-file-sets-private.dir/sources/module-internal-part-impl.cxx<OBJEXT>" : {
+      "language" : "CXX",
+      "source" : "<SOURCE_DIR>/sources/module-internal-part-impl.cxx"
+    },
+    "CMakeFiles/ninja-file-sets-private.dir/sources/module-part-impl.cxx<OBJEXT>" : {
+      "language" : "CXX",
+      "source" : "<SOURCE_DIR>/sources/module-part-impl.cxx"
+    },
+    "CMakeFiles/ninja-file-sets-private.dir/sources/module-use.cxx<OBJEXT>" : {
+      "language" : "CXX",
+      "source" : "<SOURCE_DIR>/sources/module-use.cxx"
+    }
+  }
 }

+ 20 - 1
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>",
@@ -42,5 +43,23 @@
   "language": "CXX",
   "forward-modules-from-target-dirs": [],
   "linked-target-dirs": [],
-  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-file-sets-public.dir<CONFIG_DIR>"
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-file-sets-public.dir<CONFIG_DIR>",
+  "sources": {
+    "CMakeFiles/ninja-file-sets-public.dir/sources/module-impl.cxx<OBJEXT>" : {
+      "language" : "CXX",
+      "source" : "<SOURCE_DIR>/sources/module-impl.cxx"
+    },
+    "CMakeFiles/ninja-file-sets-public.dir/sources/module-internal-part-impl.cxx<OBJEXT>" : {
+      "language" : "CXX",
+      "source" : "<SOURCE_DIR>/sources/module-internal-part-impl.cxx"
+    },
+    "CMakeFiles/ninja-file-sets-public.dir/sources/module-part-impl.cxx<OBJEXT>" : {
+      "language" : "CXX",
+      "source" : "<SOURCE_DIR>/sources/module-part-impl.cxx"
+    },
+    "CMakeFiles/ninja-file-sets-public.dir/sources/module-use.cxx<OBJEXT>" : {
+      "language" : "CXX",
+      "source" : "<SOURCE_DIR>/sources/module-use.cxx"
+    }
+  }
 }

+ 1 - 0
Tests/RunCMake/property_init/CompileSources.cmake

@@ -177,6 +177,7 @@ set(properties
 
   # Metadata
   "EXPORT_COMPILE_COMMANDS"                 "OFF"               "<SAME>"
+  "EXPORT_BUILD_DATABASE"                   "OFF"               "<SAME>"
   )
 
 if (CMAKE_HOST_APPLE) # compile-guarded in CMake

+ 1 - 0
bootstrap

@@ -306,6 +306,7 @@ CMAKE_CXX_SOURCES="\
   cmBlockCommand \
   cmBreakCommand \
   cmBuildCommand \
+  cmBuildDatabase \
   cmCMakeLanguageCommand \
   cmCMakeMinimumRequired \
   cmList \