mirror of
https://github.com/Kitware/CMake.git
synced 2026-02-25 00:59:19 -06:00
cmDyndepCollation: factor out metadata writing for dyndep
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -17,6 +19,7 @@
|
||||
#include "cmExportBuildFileGenerator.h"
|
||||
#include "cmExportSet.h"
|
||||
#include "cmFileSet.h"
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmGeneratorExpression.h" // IWYU pragma: keep
|
||||
#include "cmGeneratorTarget.h"
|
||||
#include "cmGlobalGenerator.h"
|
||||
@@ -26,6 +29,8 @@
|
||||
#include "cmInstallGenerator.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmOutputConverter.h"
|
||||
#include "cmScanDepFormat.h"
|
||||
#include "cmSourceFile.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
@@ -261,10 +266,56 @@ void cmDyndepCollation::AddCollationInformation(
|
||||
tdi["config"] = config;
|
||||
}
|
||||
|
||||
std::unique_ptr<cmCxxModuleExportInfo> cmDyndepCollation::ParseExportInfo(
|
||||
Json::Value const& tdi)
|
||||
struct CxxModuleFileSet
|
||||
{
|
||||
auto export_info = cm::make_unique<cmCxxModuleExportInfo>();
|
||||
std::string Name;
|
||||
std::string RelativeDirectory;
|
||||
std::string SourcePath;
|
||||
std::string Type;
|
||||
cmFileSetVisibility Visibility;
|
||||
cm::optional<std::string> Destination;
|
||||
};
|
||||
|
||||
struct CxxModuleBmiInstall
|
||||
{
|
||||
std::string Component;
|
||||
std::string Destination;
|
||||
bool ExcludeFromAll;
|
||||
bool Optional;
|
||||
std::string Permissions;
|
||||
std::string MessageLevel;
|
||||
std::string ScriptLocation;
|
||||
};
|
||||
|
||||
struct CxxModuleExport
|
||||
{
|
||||
std::string Name;
|
||||
std::string Destination;
|
||||
std::string Prefix;
|
||||
std::string CxxModuleInfoDir;
|
||||
std::string Namespace;
|
||||
bool Install;
|
||||
};
|
||||
|
||||
struct cmCxxModuleExportInfo
|
||||
{
|
||||
std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
|
||||
cm::optional<CxxModuleBmiInstall> BmiInstallation;
|
||||
std::vector<CxxModuleExport> Exports;
|
||||
std::string Config;
|
||||
};
|
||||
|
||||
void cmCxxModuleExportInfoDeleter::operator()(cmCxxModuleExportInfo* ei) const
|
||||
{
|
||||
delete ei;
|
||||
}
|
||||
|
||||
std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>
|
||||
cmDyndepCollation::ParseExportInfo(Json::Value const& tdi)
|
||||
{
|
||||
auto export_info =
|
||||
std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>(
|
||||
new cmCxxModuleExportInfo);
|
||||
|
||||
export_info->Config = tdi["config"].asString();
|
||||
if (export_info->Config.empty()) {
|
||||
@@ -320,3 +371,282 @@ std::unique_ptr<cmCxxModuleExportInfo> cmDyndepCollation::ParseExportInfo(
|
||||
|
||||
return export_info;
|
||||
}
|
||||
|
||||
bool cmDyndepCollation::WriteDyndepMetadata(
|
||||
std::string const& lang, std::vector<cmScanDepInfo> const& objects,
|
||||
cmCxxModuleExportInfo const& export_info,
|
||||
cmDyndepMetadataCallbacks const& cb)
|
||||
{
|
||||
// Only C++ supports any of the file-set or BMI installation considered
|
||||
// below.
|
||||
if (lang != "CXX"_s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
// Prepare the export information blocks.
|
||||
std::string const config_upper =
|
||||
cmSystemTools::UpperCase(export_info.Config);
|
||||
std::vector<
|
||||
std::pair<std::unique_ptr<cmGeneratedFileStream>, CxxModuleExport const*>>
|
||||
exports;
|
||||
for (auto const& exp : export_info.Exports) {
|
||||
std::unique_ptr<cmGeneratedFileStream> properties;
|
||||
|
||||
std::string const export_dir =
|
||||
cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
|
||||
std::string const property_file_path = cmStrCat(
|
||||
export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake");
|
||||
properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
|
||||
|
||||
// Set up the preamble.
|
||||
*properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
|
||||
<< "\"\n"
|
||||
<< " PROPERTY IMPORTED_CXX_MODULES_" << config_upper << '\n';
|
||||
|
||||
exports.emplace_back(std::move(properties), &exp);
|
||||
}
|
||||
|
||||
std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
|
||||
if (export_info.BmiInstallation) {
|
||||
bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
|
||||
export_info.BmiInstallation->ScriptLocation);
|
||||
}
|
||||
|
||||
auto cmEscape = [](cm::string_view str) {
|
||||
return cmOutputConverter::EscapeForCMake(
|
||||
str, cmOutputConverter::WrapQuotes::NoWrap);
|
||||
};
|
||||
auto install_destination =
|
||||
[&cmEscape](std::string const& dest) -> std::pair<bool, std::string> {
|
||||
if (cmSystemTools::FileIsFullPath(dest)) {
|
||||
return std::make_pair(true, cmEscape(dest));
|
||||
}
|
||||
return std::make_pair(false,
|
||||
cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest)));
|
||||
};
|
||||
|
||||
// public/private requirement tracking.
|
||||
std::set<std::string> private_modules;
|
||||
std::map<std::string, std::set<std::string>> public_source_requires;
|
||||
|
||||
for (cmScanDepInfo const& object : objects) {
|
||||
// Convert to forward slashes.
|
||||
auto output_path = object.PrimaryOutput;
|
||||
#ifdef _WIN32
|
||||
cmSystemTools::ConvertToUnixSlashes(output_path);
|
||||
#endif
|
||||
// Find the fileset for this object.
|
||||
auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
|
||||
bool const has_provides = !object.Provides.empty();
|
||||
if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
|
||||
// If it provides anything, it should have a `CXX_MODULES` or
|
||||
// `CXX_MODULE_INTERNAL_PARTITIONS` type and be present.
|
||||
if (has_provides) {
|
||||
// Take the first module provided to provide context.
|
||||
auto const& provides = object.Provides[0];
|
||||
char const* ok_types = "`CXX_MODULES`";
|
||||
if (provides.LogicalName.find(':') != std::string::npos) {
|
||||
ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
|
||||
"it is not `export`ed)";
|
||||
}
|
||||
cmSystemTools::Error(cmStrCat(
|
||||
"Output ", object.PrimaryOutput, " provides the `",
|
||||
provides.LogicalName,
|
||||
"` module but it is not found in a `FILE_SET` of type ", ok_types));
|
||||
result = false;
|
||||
}
|
||||
|
||||
// This object file does not provide anything, so nothing more needs to
|
||||
// be done.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const& file_set = fileset_info_itr->second;
|
||||
|
||||
// Verify the fileset type for the object.
|
||||
if (file_set.Type == "CXX_MODULES"_s) {
|
||||
if (!has_provides) {
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("Output ", object.PrimaryOutput,
|
||||
" is of type `CXX_MODULES` but does not provide a module"));
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
} else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) {
|
||||
if (!has_provides) {
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("Source ", file_set.SourcePath,
|
||||
" is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
|
||||
"provide a module"));
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
auto const& provides = object.Provides[0];
|
||||
if (provides.LogicalName.find(':') == std::string::npos) {
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("Source ", file_set.SourcePath,
|
||||
" is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
|
||||
"provide a module partition"));
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
} else if (file_set.Type == "CXX_MODULE_HEADERS"_s) {
|
||||
// TODO.
|
||||
} else {
|
||||
if (has_provides) {
|
||||
auto const& provides = object.Provides[0];
|
||||
char const* ok_types = "`CXX_MODULES`";
|
||||
if (provides.LogicalName.find(':') != std::string::npos) {
|
||||
ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
|
||||
"it is not `export`ed)";
|
||||
}
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("Source ", file_set.SourcePath, " provides the `",
|
||||
provides.LogicalName, "` C++ module but is of type `",
|
||||
file_set.Type, "` module but must be of type ", ok_types));
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Not a C++ module; ignore.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) {
|
||||
// Nothing needs to be conveyed about non-`PUBLIC` modules.
|
||||
for (auto const& p : object.Provides) {
|
||||
private_modules.insert(p.LogicalName);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// The module is public. Record what it directly requires.
|
||||
{
|
||||
auto& reqs = public_source_requires[file_set.SourcePath];
|
||||
for (auto const& r : object.Requires) {
|
||||
reqs.insert(r.LogicalName);
|
||||
}
|
||||
}
|
||||
|
||||
// Write out properties and install rules for any exports.
|
||||
for (auto const& p : object.Provides) {
|
||||
bool bmi_dest_is_abs = false;
|
||||
std::string bmi_destination;
|
||||
if (export_info.BmiInstallation) {
|
||||
auto dest =
|
||||
install_destination(export_info.BmiInstallation->Destination);
|
||||
bmi_dest_is_abs = dest.first;
|
||||
bmi_destination = cmStrCat(dest.second, '/');
|
||||
}
|
||||
|
||||
std::string install_bmi_path;
|
||||
std::string build_bmi_path;
|
||||
auto m = cb.ModuleFile(p.LogicalName);
|
||||
if (m) {
|
||||
install_bmi_path = cmStrCat(
|
||||
bmi_destination, cmEscape(cmSystemTools::GetFilenameName(*m)));
|
||||
build_bmi_path = cmEscape(*m);
|
||||
}
|
||||
|
||||
for (auto const& exp : exports) {
|
||||
std::string iface_source;
|
||||
if (exp.second->Install && file_set.Destination) {
|
||||
auto dest = install_destination(*file_set.Destination);
|
||||
iface_source = cmStrCat(
|
||||
dest.second, '/', cmEscape(file_set.RelativeDirectory),
|
||||
cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
|
||||
} else {
|
||||
iface_source = cmEscape(file_set.SourcePath);
|
||||
}
|
||||
|
||||
std::string bmi_path;
|
||||
if (exp.second->Install && export_info.BmiInstallation) {
|
||||
bmi_path = install_bmi_path;
|
||||
} else if (!exp.second->Install) {
|
||||
bmi_path = build_bmi_path;
|
||||
}
|
||||
|
||||
if (iface_source.empty()) {
|
||||
// No destination for the C++ module source; ignore this property
|
||||
// value.
|
||||
continue;
|
||||
}
|
||||
|
||||
*exp.first << " \"" << cmEscape(p.LogicalName) << '='
|
||||
<< iface_source;
|
||||
if (!bmi_path.empty()) {
|
||||
*exp.first << ',' << bmi_path;
|
||||
}
|
||||
*exp.first << "\"\n";
|
||||
}
|
||||
|
||||
if (bmi_install_script) {
|
||||
auto const& bmi_install = *export_info.BmiInstallation;
|
||||
|
||||
*bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \""
|
||||
<< cmEscape(bmi_install.Component) << '\"';
|
||||
if (!bmi_install.ExcludeFromAll) {
|
||||
*bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT";
|
||||
}
|
||||
*bmi_install_script << ")\n";
|
||||
*bmi_install_script << " file(INSTALL\n"
|
||||
" DESTINATION \"";
|
||||
if (!bmi_dest_is_abs) {
|
||||
*bmi_install_script << "${CMAKE_INSTALL_PREFIX}/";
|
||||
}
|
||||
*bmi_install_script << cmEscape(bmi_install.Destination)
|
||||
<< "\"\n"
|
||||
" TYPE FILE\n";
|
||||
if (bmi_install.Optional) {
|
||||
*bmi_install_script << " OPTIONAL\n";
|
||||
}
|
||||
if (!bmi_install.MessageLevel.empty()) {
|
||||
*bmi_install_script << " " << bmi_install.MessageLevel << "\n";
|
||||
}
|
||||
if (!bmi_install.Permissions.empty()) {
|
||||
*bmi_install_script << " PERMISSIONS" << bmi_install.Permissions
|
||||
<< "\n";
|
||||
}
|
||||
*bmi_install_script << " FILES \"" << *m << "\")\n";
|
||||
if (bmi_dest_is_abs) {
|
||||
*bmi_install_script
|
||||
<< " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
|
||||
" \""
|
||||
<< cmEscape(cmSystemTools::GetFilenameName(*m))
|
||||
<< "\")\n"
|
||||
" if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
|
||||
" message(WARNING\n"
|
||||
" \"ABSOLUTE path INSTALL DESTINATION : "
|
||||
"${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
|
||||
" endif ()\n"
|
||||
" if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
|
||||
" message(FATAL_ERROR\n"
|
||||
" \"ABSOLUTE path INSTALL DESTINATION forbidden (by "
|
||||
"caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
|
||||
" endif ()\n";
|
||||
}
|
||||
*bmi_install_script << "endif ()\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add trailing parenthesis for the `set_property` call.
|
||||
for (auto const& exp : exports) {
|
||||
*exp.first << ")\n";
|
||||
}
|
||||
|
||||
// Check that public sources only require public modules.
|
||||
for (auto const& pub_reqs : public_source_requires) {
|
||||
for (auto const& req : pub_reqs.second) {
|
||||
if (private_modules.count(req)) {
|
||||
cmSystemTools::Error(cmStrCat(
|
||||
"Public C++ module source `", pub_reqs.first, "` requires the `",
|
||||
req, "` C++ module which is provided by a private source"));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -5,16 +5,14 @@
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
#include "cmFileSet.h"
|
||||
|
||||
class cmGeneratorTarget;
|
||||
struct cmScanDepInfo;
|
||||
class cmSourceFile;
|
||||
|
||||
namespace Json {
|
||||
@@ -27,43 +25,15 @@ struct cmDyndepGeneratorCallbacks
|
||||
ObjectFilePath;
|
||||
};
|
||||
|
||||
struct CxxModuleFileSet
|
||||
struct cmDyndepMetadataCallbacks
|
||||
{
|
||||
std::string Name;
|
||||
std::string RelativeDirectory;
|
||||
std::string SourcePath;
|
||||
std::string Type;
|
||||
cmFileSetVisibility Visibility;
|
||||
cm::optional<std::string> Destination;
|
||||
std::function<cm::optional<std::string>(std::string const& name)> ModuleFile;
|
||||
};
|
||||
|
||||
struct CxxModuleBmiInstall
|
||||
struct cmCxxModuleExportInfo;
|
||||
struct cmCxxModuleExportInfoDeleter
|
||||
{
|
||||
std::string Component;
|
||||
std::string Destination;
|
||||
bool ExcludeFromAll;
|
||||
bool Optional;
|
||||
std::string Permissions;
|
||||
std::string MessageLevel;
|
||||
std::string ScriptLocation;
|
||||
};
|
||||
|
||||
struct CxxModuleExport
|
||||
{
|
||||
std::string Name;
|
||||
std::string Destination;
|
||||
std::string Prefix;
|
||||
std::string CxxModuleInfoDir;
|
||||
std::string Namespace;
|
||||
bool Install;
|
||||
};
|
||||
|
||||
struct cmCxxModuleExportInfo
|
||||
{
|
||||
std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
|
||||
cm::optional<CxxModuleBmiInstall> BmiInstallation;
|
||||
std::vector<CxxModuleExport> Exports;
|
||||
std::string Config;
|
||||
void operator()(cmCxxModuleExportInfo* ei) const;
|
||||
};
|
||||
|
||||
struct cmDyndepCollation
|
||||
@@ -73,6 +43,10 @@ struct cmDyndepCollation
|
||||
std::string const& config,
|
||||
cmDyndepGeneratorCallbacks const& cb);
|
||||
|
||||
static std::unique_ptr<cmCxxModuleExportInfo> ParseExportInfo(
|
||||
Json::Value const& tdi);
|
||||
static std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>
|
||||
ParseExportInfo(Json::Value const& tdi);
|
||||
static bool WriteDyndepMetadata(std::string const& lang,
|
||||
std::vector<cmScanDepInfo> const& objects,
|
||||
cmCxxModuleExportInfo const& export_info,
|
||||
cmDyndepMetadataCallbacks const& cb);
|
||||
};
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include "cmCxxModuleMapper.h"
|
||||
#include "cmDyndepCollation.h"
|
||||
#include "cmFileSet.h"
|
||||
#include "cmFortranParser.h"
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmGeneratorExpressionEvaluationFile.h"
|
||||
@@ -2711,279 +2710,18 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
|
||||
cmGeneratedFileStream tmf(target_mods_file);
|
||||
tmf << target_module_info;
|
||||
|
||||
bool result = true;
|
||||
|
||||
// Fortran doesn't support any of the file-set or BMI installation considered
|
||||
// below.
|
||||
if (arg_lang != "Fortran"_s) {
|
||||
// Prepare the export information blocks.
|
||||
std::string const config_upper =
|
||||
cmSystemTools::UpperCase(export_info.Config);
|
||||
std::vector<std::pair<std::unique_ptr<cmGeneratedFileStream>,
|
||||
CxxModuleExport const*>>
|
||||
exports;
|
||||
for (auto const& exp : export_info.Exports) {
|
||||
std::unique_ptr<cmGeneratedFileStream> properties;
|
||||
|
||||
std::string const export_dir =
|
||||
cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
|
||||
std::string const property_file_path = cmStrCat(
|
||||
export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake");
|
||||
properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
|
||||
|
||||
// Set up the preamble.
|
||||
*properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
|
||||
<< "\"\n"
|
||||
<< " PROPERTY IMPORTED_CXX_MODULES_" << config_upper
|
||||
<< '\n';
|
||||
|
||||
exports.emplace_back(std::move(properties), &exp);
|
||||
cmDyndepMetadataCallbacks cb;
|
||||
cb.ModuleFile =
|
||||
[mod_files](std::string const& name) -> cm::optional<std::string> {
|
||||
auto m = mod_files.find(name);
|
||||
if (m != mod_files.end()) {
|
||||
return m->second;
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
|
||||
if (export_info.BmiInstallation) {
|
||||
bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
|
||||
export_info.BmiInstallation->ScriptLocation);
|
||||
}
|
||||
|
||||
auto cmEscape = [](cm::string_view str) {
|
||||
return cmOutputConverter::EscapeForCMake(
|
||||
str, cmOutputConverter::WrapQuotes::NoWrap);
|
||||
};
|
||||
auto install_destination =
|
||||
[&cmEscape](std::string const& dest) -> std::pair<bool, std::string> {
|
||||
if (cmSystemTools::FileIsFullPath(dest)) {
|
||||
return std::make_pair(true, cmEscape(dest));
|
||||
}
|
||||
return std::make_pair(false,
|
||||
cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest)));
|
||||
};
|
||||
|
||||
// public/private requirement tracking.
|
||||
std::set<std::string> private_modules;
|
||||
std::map<std::string, std::set<std::string>> public_source_requires;
|
||||
|
||||
for (cmScanDepInfo const& object : objects) {
|
||||
// Convert to forward slashes.
|
||||
auto output_path = object.PrimaryOutput;
|
||||
# ifdef _WIN32
|
||||
cmSystemTools::ConvertToUnixSlashes(output_path);
|
||||
# endif
|
||||
// Find the fileset for this object.
|
||||
auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
|
||||
bool const has_provides = !object.Provides.empty();
|
||||
if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
|
||||
// If it provides anything, it should have a `CXX_MODULES` or
|
||||
// `CXX_MODULE_INTERNAL_PARTITIONS` type and be present.
|
||||
if (has_provides) {
|
||||
// Take the first module provided to provide context.
|
||||
auto const& provides = object.Provides[0];
|
||||
char const* ok_types = "`CXX_MODULES`";
|
||||
if (provides.LogicalName.find(':') != std::string::npos) {
|
||||
ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
|
||||
"it is not `export`ed)";
|
||||
}
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("Output ", object.PrimaryOutput, " provides the `",
|
||||
provides.LogicalName,
|
||||
"` module but it is not found in a `FILE_SET` of type ",
|
||||
ok_types));
|
||||
result = false;
|
||||
}
|
||||
|
||||
// This object file does not provide anything, so nothing more needs to
|
||||
// be done.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const& file_set = fileset_info_itr->second;
|
||||
|
||||
// Verify the fileset type for the object.
|
||||
if (file_set.Type == "CXX_MODULES"_s) {
|
||||
if (!has_provides) {
|
||||
cmSystemTools::Error(cmStrCat(
|
||||
"Output ", object.PrimaryOutput,
|
||||
" is of type `CXX_MODULES` but does not provide a module"));
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
} else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) {
|
||||
if (!has_provides) {
|
||||
cmSystemTools::Error(cmStrCat(
|
||||
"Source ", file_set.SourcePath,
|
||||
" is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
|
||||
"provide a module"));
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
auto const& provides = object.Provides[0];
|
||||
if (provides.LogicalName.find(':') == std::string::npos) {
|
||||
cmSystemTools::Error(cmStrCat(
|
||||
"Source ", file_set.SourcePath,
|
||||
" is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
|
||||
"provide a module partition"));
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
} else if (file_set.Type == "CXX_MODULE_HEADERS"_s) {
|
||||
// TODO.
|
||||
} else {
|
||||
if (has_provides) {
|
||||
auto const& provides = object.Provides[0];
|
||||
char const* ok_types = "`CXX_MODULES`";
|
||||
if (provides.LogicalName.find(':') != std::string::npos) {
|
||||
ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
|
||||
"it is not `export`ed)";
|
||||
}
|
||||
cmSystemTools::Error(cmStrCat(
|
||||
"Source ", file_set.SourcePath, " provides the `",
|
||||
provides.LogicalName, "` C++ module but is of type `",
|
||||
file_set.Type, "` module but must be of type ", ok_types));
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Not a C++ module; ignore.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) {
|
||||
// Nothing needs to be conveyed about non-`PUBLIC` modules.
|
||||
for (auto const& p : object.Provides) {
|
||||
private_modules.insert(p.LogicalName);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// The module is public. Record what it directly requires.
|
||||
{
|
||||
auto& reqs = public_source_requires[file_set.SourcePath];
|
||||
for (auto const& r : object.Requires) {
|
||||
reqs.insert(r.LogicalName);
|
||||
}
|
||||
}
|
||||
|
||||
// Write out properties and install rules for any exports.
|
||||
for (auto const& p : object.Provides) {
|
||||
bool bmi_dest_is_abs = false;
|
||||
std::string bmi_destination;
|
||||
if (export_info.BmiInstallation) {
|
||||
auto dest =
|
||||
install_destination(export_info.BmiInstallation->Destination);
|
||||
bmi_dest_is_abs = dest.first;
|
||||
bmi_destination = cmStrCat(dest.second, '/');
|
||||
}
|
||||
|
||||
std::string install_bmi_path;
|
||||
std::string build_bmi_path;
|
||||
auto m = mod_files.find(p.LogicalName);
|
||||
if (m != mod_files.end()) {
|
||||
install_bmi_path =
|
||||
cmStrCat(bmi_destination,
|
||||
cmEscape(cmSystemTools::GetFilenameName(m->second)));
|
||||
build_bmi_path = cmEscape(m->second);
|
||||
}
|
||||
|
||||
for (auto const& exp : exports) {
|
||||
std::string iface_source;
|
||||
if (exp.second->Install && file_set.Destination) {
|
||||
auto dest = install_destination(*file_set.Destination);
|
||||
iface_source = cmStrCat(
|
||||
dest.second, '/', cmEscape(file_set.RelativeDirectory),
|
||||
cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
|
||||
} else {
|
||||
iface_source = cmEscape(file_set.SourcePath);
|
||||
}
|
||||
|
||||
std::string bmi_path;
|
||||
if (exp.second->Install && export_info.BmiInstallation) {
|
||||
bmi_path = install_bmi_path;
|
||||
} else if (!exp.second->Install) {
|
||||
bmi_path = build_bmi_path;
|
||||
}
|
||||
|
||||
if (iface_source.empty()) {
|
||||
// No destination for the C++ module source; ignore this property
|
||||
// value.
|
||||
continue;
|
||||
}
|
||||
|
||||
*exp.first << " \"" << cmEscape(p.LogicalName) << '='
|
||||
<< iface_source;
|
||||
if (!bmi_path.empty()) {
|
||||
*exp.first << ',' << bmi_path;
|
||||
}
|
||||
*exp.first << "\"\n";
|
||||
}
|
||||
|
||||
if (bmi_install_script) {
|
||||
auto const& bmi_install = *export_info.BmiInstallation;
|
||||
|
||||
*bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \""
|
||||
<< cmEscape(bmi_install.Component) << '\"';
|
||||
if (!bmi_install.ExcludeFromAll) {
|
||||
*bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT";
|
||||
}
|
||||
*bmi_install_script << ")\n";
|
||||
*bmi_install_script << " file(INSTALL\n"
|
||||
" DESTINATION \"";
|
||||
if (!bmi_dest_is_abs) {
|
||||
*bmi_install_script << "${CMAKE_INSTALL_PREFIX}/";
|
||||
}
|
||||
*bmi_install_script << cmEscape(bmi_install.Destination)
|
||||
<< "\"\n"
|
||||
" TYPE FILE\n";
|
||||
if (bmi_install.Optional) {
|
||||
*bmi_install_script << " OPTIONAL\n";
|
||||
}
|
||||
if (!bmi_install.MessageLevel.empty()) {
|
||||
*bmi_install_script << " " << bmi_install.MessageLevel << "\n";
|
||||
}
|
||||
if (!bmi_install.Permissions.empty()) {
|
||||
*bmi_install_script << " PERMISSIONS" << bmi_install.Permissions
|
||||
<< "\n";
|
||||
}
|
||||
*bmi_install_script << " FILES \"" << m->second << "\")\n";
|
||||
if (bmi_dest_is_abs) {
|
||||
*bmi_install_script
|
||||
<< " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
|
||||
" \""
|
||||
<< cmEscape(cmSystemTools::GetFilenameName(m->second))
|
||||
<< "\")\n"
|
||||
" if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
|
||||
" message(WARNING\n"
|
||||
" \"ABSOLUTE path INSTALL DESTINATION : "
|
||||
"${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
|
||||
" endif ()\n"
|
||||
" if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
|
||||
" message(FATAL_ERROR\n"
|
||||
" \"ABSOLUTE path INSTALL DESTINATION forbidden (by "
|
||||
"caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
|
||||
" endif ()\n";
|
||||
}
|
||||
*bmi_install_script << "endif ()\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add trailing parenthesis for the `set_property` call.
|
||||
for (auto const& exp : exports) {
|
||||
*exp.first << ")\n";
|
||||
}
|
||||
|
||||
// Check that public sources only require public modules.
|
||||
for (auto const& pub_reqs : public_source_requires) {
|
||||
for (auto const& req : pub_reqs.second) {
|
||||
if (private_modules.count(req)) {
|
||||
cmSystemTools::Error(cmStrCat(
|
||||
"Public C++ module source `", pub_reqs.first, "` requires the `",
|
||||
req, "` C++ module which is provided by a private source"));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return cmDyndepCollation::WriteDyndepMetadata(arg_lang, objects, export_info,
|
||||
cb);
|
||||
}
|
||||
|
||||
int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
|
||||
|
||||
Reference in New Issue
Block a user