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.
This commit is contained in:
Ben Boeckel
2022-04-08 13:57:16 -04:00
parent ffd40c6b6e
commit d3e2e61bcd
7 changed files with 287 additions and 0 deletions

View File

@@ -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<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);
cmGeneratedFileStream tdif(tdin);
tdif << tdi;

View File

@@ -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 ()

View File

@@ -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.

View File

@@ -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)

View File

@@ -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 ()

View File

@@ -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"
}

View File

@@ -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"
}