From d3e2e61bcdb74899e7ee987c745ded8e7597fb62 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 8 Apr 2022 13:57:16 -0400 Subject: 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. --- Source/cmNinjaTargetGenerator.cxx | 99 ++++++++++++++++++++++ .../CXXModules/NinjaDependInfoFileSet-check.cmake | 34 ++++++++ .../CXXModules/NinjaDependInfoFileSet-stderr.txt | 11 +++ .../CXXModules/NinjaDependInfoFileSet.cmake | 59 +++++++++++++ Tests/RunCMake/CXXModules/RunCMakeTest.cmake | 8 ++ .../expect/NinjaDependInfoFileSet-private.json | 38 +++++++++ .../expect/NinjaDependInfoFileSet-public.json | 38 +++++++++ 7 files changed, 287 insertions(+) create mode 100644 Tests/RunCMake/CXXModules/NinjaDependInfoFileSet-check.cmake create mode 100644 Tests/RunCMake/CXXModules/NinjaDependInfoFileSet-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/NinjaDependInfoFileSet.cmake create mode 100644 Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json create mode 100644 Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index ee065c4..b561925 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -26,6 +26,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalNinjaGenerator.h" +#include "cmInstallFileSetGenerator.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" @@ -1653,6 +1654,104 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, tdi_linked_target_dirs.append(l); } + cmTarget* tgt = this->GeneratorTarget->Target; + auto all_file_sets = tgt->GetAllFileSetNames(); + Json::Value& tdi_cxx_module_info = tdi["cxx-modules"] = Json::objectValue; + for (auto const& file_set_name : all_file_sets) { + auto* file_set = tgt->GetFileSet(file_set_name); + if (!file_set) { + this->GetMakefile()->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), + "\" is tracked to have file set \"", file_set_name, + "\", but it was not found.")); + continue; + } + auto fs_type = file_set->GetType(); + // We only care about C++ module sources here. + if (fs_type != "CXX_MODULES"_s) { + continue; + } + + auto fileEntries = file_set->CompileFileEntries(); + auto directoryEntries = file_set->CompileDirectoryEntries(); + + auto directories = file_set->EvaluateDirectoryEntries( + directoryEntries, this->GeneratorTarget->LocalGenerator, config, + this->GeneratorTarget); + std::map> files_per_dirs; + for (auto const& entry : fileEntries) { + file_set->EvaluateFileEntry(directories, files_per_dirs, entry, + this->GeneratorTarget->LocalGenerator, + config, this->GeneratorTarget); + } + + std::map sf_map; + { + std::vector objectSources; + this->GeneratorTarget->GetObjectSources(objectSources, config); + for (auto const* sf : objectSources) { + auto full_path = sf->GetFullPath(); + if (full_path.empty()) { + this->GetMakefile()->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), + "\" has a full path-less source file.")); + continue; + } + sf_map[full_path] = sf; + } + } + + Json::Value fs_dest = Json::nullValue; + for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) { + if (auto const* fsg = + dynamic_cast(ig.get())) { + if (fsg->GetTarget() == this->GeneratorTarget && + fsg->GetFileSet() == file_set) { + fs_dest = fsg->GetDestination(config); + continue; + } + } + } + + for (auto const& files_per_dir : files_per_dirs) { + for (auto const& file : files_per_dir.second) { + auto lookup = sf_map.find(file); + if (lookup == sf_map.end()) { + this->GetMakefile()->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), "\" has source file \"", + file, + R"(" which is not in any of its "FILE_SET BASE_DIRS".)")); + continue; + } + + auto const* sf = lookup->second; + + if (!sf) { + this->GetMakefile()->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), "\" has source file \"", + file, "\" which has not been tracked properly.")); + continue; + } + + auto obj_path = this->GetObjectFilePath(sf, config); + Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] = + Json::objectValue; + + tdi_module_info["source"] = file; + tdi_module_info["relative-directory"] = files_per_dir.first; + tdi_module_info["name"] = file_set->GetName(); + tdi_module_info["type"] = file_set->GetType(); + tdi_module_info["visibility"] = + std::string(cmFileSetVisibilityToName(file_set->GetVisibility())); + tdi_module_info["destination"] = fs_dest; + } + } + } + std::string const tdin = this->GetTargetDependInfoPath(lang, config); cmGeneratedFileStream tdif(tdin); tdif << tdi; diff --git a/Tests/RunCMake/CXXModules/NinjaDependInfoFileSet-check.cmake b/Tests/RunCMake/CXXModules/NinjaDependInfoFileSet-check.cmake new file mode 100644 index 0000000..b9a1315 --- /dev/null +++ b/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 () diff --git a/Tests/RunCMake/CXXModules/NinjaDependInfoFileSet-stderr.txt b/Tests/RunCMake/CXXModules/NinjaDependInfoFileSet-stderr.txt new file mode 100644 index 0000000..ca430cc --- /dev/null +++ b/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. diff --git a/Tests/RunCMake/CXXModules/NinjaDependInfoFileSet.cmake b/Tests/RunCMake/CXXModules/NinjaDependInfoFileSet.cmake new file mode 100644 index 0000000..74e729e --- /dev/null +++ b/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) diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake index a4b67fd..aedaf3c 100644 --- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake +++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake @@ -74,6 +74,14 @@ run_cmake(InstallBMIIgnore) run_cmake(ExportBuildCxxModules) 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. if (NOT CMake_TEST_MODULE_COMPILATION) return () diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json new file mode 100644 index 0000000..968502c --- /dev/null +++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json @@ -0,0 +1,38 @@ +{ + "compiler-id": "", + "config": "", + "cxx-modules": { + "CMakeFiles/ninja-file-sets-private.dir/sources/module-internal-part.cxx.o": { + "destination": null, + "name": "internal_partitions", + "relative-directory": "sources", + "source": "/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": "/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": "/sources/module.cxx", + "type": "CXX_MODULES", + "visibility": "PRIVATE" + } + }, + "dir-cur-bld": "", + "dir-cur-src": "", + "dir-top-bld": "", + "dir-top-src": "", + "include-dirs": [], + "language": "CXX", + "linked-target-dirs": [], + "module-dir": "/CMakeFiles/ninja-file-sets-private.dir" +} diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json new file mode 100644 index 0000000..e836437 --- /dev/null +++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json @@ -0,0 +1,38 @@ +{ + "compiler-id": "", + "config": "", + "cxx-modules": { + "CMakeFiles/ninja-file-sets-public.dir/sources/module-internal-part.cxx.o": { + "destination": "lib/cxx/internals", + "name": "internal_partitions", + "relative-directory": "sources", + "source": "/sources/module-internal-part.cxx", + "type": "CXX_MODULES", + "visibility": "PUBLIC" + }, + "CMakeFiles/ninja-file-sets-public.dir/sources/module-part.cxx.o": { + "destination": "lib/cxx", + "name": "modules", + "relative-directory": "", + "source": "/sources/module-part.cxx", + "type": "CXX_MODULES", + "visibility": "PUBLIC" + }, + "CMakeFiles/ninja-file-sets-public.dir/sources/module.cxx.o": { + "destination": "lib/cxx", + "name": "modules", + "relative-directory": "", + "source": "/sources/module.cxx", + "type": "CXX_MODULES", + "visibility": "PUBLIC" + } + }, + "dir-cur-bld": "", + "dir-cur-src": "", + "dir-top-bld": "", + "dir-top-src": "", + "include-dirs": [], + "language": "CXX", + "linked-target-dirs": [], + "module-dir": "/CMakeFiles/ninja-file-sets-public.dir" +} -- cgit v0.12