Просмотр исходного кода

cmNinjaTargetGenerator: write out fileset information for the collator

The collator will use this to generate property settings for the
imported targets in the build and install export sets.
Ben Boeckel 3 лет назад
Родитель
Сommit
d3e2e61bcd

+ 99 - 0
Source/cmNinjaTargetGenerator.cxx

@@ -26,6 +26,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalNinjaGenerator.h"
 #include "cmGlobalNinjaGenerator.h"
+#include "cmInstallFileSetGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalNinjaGenerator.h"
 #include "cmLocalNinjaGenerator.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
@@ -1653,6 +1654,104 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
     tdi_linked_target_dirs.append(l);
     tdi_linked_target_dirs.append(l);
   }
   }
 
 
+  cmTarget* tgt = this->GeneratorTarget->Target;
+  auto all_file_sets = tgt->GetAllFileSetNames();
+  Json::Value& tdi_cxx_module_info = tdi["cxx-modules"] = Json::objectValue;
+  for (auto const& file_set_name : all_file_sets) {
+    auto* file_set = tgt->GetFileSet(file_set_name);
+    if (!file_set) {
+      this->GetMakefile()->IssueMessage(
+        MessageType::INTERNAL_ERROR,
+        cmStrCat("Target \"", tgt->GetName(),
+                 "\" is tracked to have file set \"", file_set_name,
+                 "\", but it was not found."));
+      continue;
+    }
+    auto fs_type = file_set->GetType();
+    // We only care about C++ module sources here.
+    if (fs_type != "CXX_MODULES"_s) {
+      continue;
+    }
+
+    auto fileEntries = file_set->CompileFileEntries();
+    auto directoryEntries = file_set->CompileDirectoryEntries();
+
+    auto directories = file_set->EvaluateDirectoryEntries(
+      directoryEntries, this->GeneratorTarget->LocalGenerator, config,
+      this->GeneratorTarget);
+    std::map<std::string, std::vector<std::string>> files_per_dirs;
+    for (auto const& entry : fileEntries) {
+      file_set->EvaluateFileEntry(directories, files_per_dirs, entry,
+                                  this->GeneratorTarget->LocalGenerator,
+                                  config, this->GeneratorTarget);
+    }
+
+    std::map<std::string, cmSourceFile const*> sf_map;
+    {
+      std::vector<cmSourceFile const*> objectSources;
+      this->GeneratorTarget->GetObjectSources(objectSources, config);
+      for (auto const* sf : objectSources) {
+        auto full_path = sf->GetFullPath();
+        if (full_path.empty()) {
+          this->GetMakefile()->IssueMessage(
+            MessageType::INTERNAL_ERROR,
+            cmStrCat("Target \"", tgt->GetName(),
+                     "\" has a full path-less source file."));
+          continue;
+        }
+        sf_map[full_path] = sf;
+      }
+    }
+
+    Json::Value fs_dest = Json::nullValue;
+    for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) {
+      if (auto const* fsg =
+            dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) {
+        if (fsg->GetTarget() == this->GeneratorTarget &&
+            fsg->GetFileSet() == file_set) {
+          fs_dest = fsg->GetDestination(config);
+          continue;
+        }
+      }
+    }
+
+    for (auto const& files_per_dir : files_per_dirs) {
+      for (auto const& file : files_per_dir.second) {
+        auto lookup = sf_map.find(file);
+        if (lookup == sf_map.end()) {
+          this->GetMakefile()->IssueMessage(
+            MessageType::INTERNAL_ERROR,
+            cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
+                     file,
+                     R"(" which is not in any of its "FILE_SET BASE_DIRS".)"));
+          continue;
+        }
+
+        auto const* sf = lookup->second;
+
+        if (!sf) {
+          this->GetMakefile()->IssueMessage(
+            MessageType::INTERNAL_ERROR,
+            cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
+                     file, "\" which has not been tracked properly."));
+          continue;
+        }
+
+        auto obj_path = this->GetObjectFilePath(sf, config);
+        Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
+          Json::objectValue;
+
+        tdi_module_info["source"] = file;
+        tdi_module_info["relative-directory"] = files_per_dir.first;
+        tdi_module_info["name"] = file_set->GetName();
+        tdi_module_info["type"] = file_set->GetType();
+        tdi_module_info["visibility"] =
+          std::string(cmFileSetVisibilityToName(file_set->GetVisibility()));
+        tdi_module_info["destination"] = fs_dest;
+      }
+    }
+  }
+
   std::string const tdin = this->GetTargetDependInfoPath(lang, config);
   std::string const tdin = this->GetTargetDependInfoPath(lang, config);
   cmGeneratedFileStream tdif(tdin);
   cmGeneratedFileStream tdif(tdin);
   tdif << tdi;
   tdif << tdi;

+ 34 - 0
Tests/RunCMake/CXXModules/NinjaDependInfoFileSet-check.cmake

@@ -0,0 +1,34 @@
+include("${CMAKE_CURRENT_LIST_DIR}/check-json.cmake")
+
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(have_file 0)
+  foreach (config IN ITEMS Release Debug RelWithDebInfo MinSizeRel)
+    if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/ninja-file-sets-public.dir/${config}/CXXDependInfo.json")
+      continue ()
+    endif ()
+    set(have_file 1)
+
+    set(CMAKE_BUILD_TYPE "${config}")
+
+    file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/ninja-file-sets-public.dir/${config}/CXXDependInfo.json" actual_contents)
+    file(READ "${CMAKE_CURRENT_LIST_DIR}/expect/NinjaDependInfoFileSet-public.json" expect_contents)
+    check_json("${actual_contents}" "${expect_contents}")
+
+    file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/ninja-file-sets-private.dir/${config}/CXXDependInfo.json" actual_contents)
+    file(READ "${CMAKE_CURRENT_LIST_DIR}/expect/NinjaDependInfoFileSet-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 ()
+  file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/ninja-file-sets-public.dir/CXXDependInfo.json" actual_contents)
+  file(READ "${CMAKE_CURRENT_LIST_DIR}/expect/NinjaDependInfoFileSet-public.json" expect_contents)
+  check_json("${actual_contents}" "${expect_contents}")
+
+  file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/ninja-file-sets-private.dir/CXXDependInfo.json" actual_contents)
+  file(READ "${CMAKE_CURRENT_LIST_DIR}/expect/NinjaDependInfoFileSet-private.json" expect_contents)
+  check_json("${actual_contents}" "${expect_contents}")
+endif ()

+ 11 - 0
Tests/RunCMake/CXXModules/NinjaDependInfoFileSet-stderr.txt

@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at NinjaDependInfoFileSet.cmake:14 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.

+ 59 - 0
Tests/RunCMake/CXXModules/NinjaDependInfoFileSet.cmake

@@ -0,0 +1,59 @@
+# Fake out that we have dyndep; we only need to generate, not actually build
+# here.
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "")
+
+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-file-sets-public)
+target_sources(ninja-file-sets-public
+  PRIVATE
+    sources/module-impl.cxx
+    sources/module-internal-part-impl.cxx
+    sources/module-part-impl.cxx
+    sources/module-use.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-file-sets-public
+  PRIVATE
+    cxx_std_20)
+
+install(TARGETS ninja-file-sets-public
+  FILE_SET modules
+    DESTINATION "lib/cxx"
+    COMPONENT "modules"
+  FILE_SET internal_partitions
+    DESTINATION "lib/cxx/internals"
+    COMPONENT "modules-internal")
+
+add_library(ninja-file-sets-private)
+target_sources(ninja-file-sets-private
+  PRIVATE
+    sources/module-impl.cxx
+    sources/module-internal-part-impl.cxx
+    sources/module-part-impl.cxx
+    sources/module-use.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-file-sets-private
+  PRIVATE
+    cxx_std_20)

+ 8 - 0
Tests/RunCMake/CXXModules/RunCMakeTest.cmake

@@ -74,6 +74,14 @@ run_cmake(InstallBMIIgnore)
 run_cmake(ExportBuildCxxModules)
 run_cmake(ExportBuildCxxModules)
 run_cmake(ExportInstallCxxModules)
 run_cmake(ExportInstallCxxModules)
 
 
+# Generator-specific tests.
+if (RunCMake_GENERATOR MATCHES "Ninja")
+  run_cmake(NinjaDependInfoFileSet)
+else ()
+  message(FATAL_ERROR
+    "Please add 'DependInfo' tests for the '${RunCMake_GENERATOR}' generator.")
+endif ()
+
 # Actual compilation tests.
 # Actual compilation tests.
 if (NOT CMake_TEST_MODULE_COMPILATION)
 if (NOT CMake_TEST_MODULE_COMPILATION)
   return ()
   return ()

+ 38 - 0
Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json

@@ -0,0 +1,38 @@
+{
+  "compiler-id": "<IGNORE>",
+  "config": "<CONFIG>",
+  "cxx-modules": {
+    "CMakeFiles/ninja-file-sets-private.dir/sources/module-internal-part.cxx.o": {
+      "destination": null,
+      "name": "internal_partitions",
+      "relative-directory": "sources",
+      "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PRIVATE"
+    },
+    "CMakeFiles/ninja-file-sets-private.dir/sources/module-part.cxx.o": {
+      "destination": null,
+      "name": "modules",
+      "relative-directory": "",
+      "source": "<SOURCE_DIR>/sources/module-part.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PRIVATE"
+    },
+    "CMakeFiles/ninja-file-sets-private.dir/sources/module.cxx.o": {
+      "destination": null,
+      "name": "modules",
+      "relative-directory": "",
+      "source": "<SOURCE_DIR>/sources/module.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PRIVATE"
+    }
+  },
+  "dir-cur-bld": "<BINARY_DIR>",
+  "dir-cur-src": "<SOURCE_DIR>",
+  "dir-top-bld": "<BINARY_DIR>",
+  "dir-top-src": "<SOURCE_DIR>",
+  "include-dirs": [],
+  "language": "CXX",
+  "linked-target-dirs": [],
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-file-sets-private.dir"
+}

+ 38 - 0
Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json

@@ -0,0 +1,38 @@
+{
+  "compiler-id": "<IGNORE>",
+  "config": "<CONFIG>",
+  "cxx-modules": {
+    "CMakeFiles/ninja-file-sets-public.dir/<CONFIG_DIR>sources/module-internal-part.cxx.o": {
+      "destination": "lib/cxx/internals",
+      "name": "internal_partitions",
+      "relative-directory": "sources",
+      "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PUBLIC"
+    },
+    "CMakeFiles/ninja-file-sets-public.dir/<CONFIG_DIR>sources/module-part.cxx.o": {
+      "destination": "lib/cxx",
+      "name": "modules",
+      "relative-directory": "",
+      "source": "<SOURCE_DIR>/sources/module-part.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PUBLIC"
+    },
+    "CMakeFiles/ninja-file-sets-public.dir/<CONFIG_DIR>sources/module.cxx.o": {
+      "destination": "lib/cxx",
+      "name": "modules",
+      "relative-directory": "",
+      "source": "<SOURCE_DIR>/sources/module.cxx",
+      "type": "CXX_MODULES",
+      "visibility": "PUBLIC"
+    }
+  },
+  "dir-cur-bld": "<BINARY_DIR>",
+  "dir-cur-src": "<SOURCE_DIR>",
+  "dir-top-bld": "<BINARY_DIR>",
+  "dir-top-src": "<SOURCE_DIR>",
+  "include-dirs": [],
+  "language": "CXX",
+  "linked-target-dirs": [],
+  "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-file-sets-public.dir"
+}