summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/cmFileSet.cxx7
-rw-r--r--Source/cmFileSet.h2
-rw-r--r--Source/cmGeneratorTarget.cxx104
-rw-r--r--Source/cmGeneratorTarget.h6
-rw-r--r--Source/cmGlobalGenerator.cxx40
-rw-r--r--Source/cmGlobalGenerator.h2
-rw-r--r--Source/cmTarget.cxx180
-rw-r--r--Source/cmTarget.h4
8 files changed, 344 insertions, 1 deletions
diff --git a/Source/cmFileSet.cxx b/Source/cmFileSet.cxx
index 48a2570..bcf7fba 100644
--- a/Source/cmFileSet.cxx
+++ b/Source/cmFileSet.cxx
@@ -7,6 +7,7 @@
#include <utility>
#include <vector>
+#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
@@ -88,6 +89,12 @@ cmFileSet::cmFileSet(cmake& cmakeInstance, std::string name, std::string type,
{
}
+void cmFileSet::CopyEntries(cmFileSet const* fs)
+{
+ cm::append(this->DirectoryEntries, fs->DirectoryEntries);
+ cm::append(this->FileEntries, fs->FileEntries);
+}
+
void cmFileSet::ClearDirectoryEntries()
{
this->DirectoryEntries.clear();
diff --git a/Source/cmFileSet.h b/Source/cmFileSet.h
index 54d430c..c508e2b 100644
--- a/Source/cmFileSet.h
+++ b/Source/cmFileSet.h
@@ -41,6 +41,8 @@ public:
const std::string& GetType() const { return this->Type; }
cmFileSetVisibility GetVisibility() const { return this->Visibility; }
+ void CopyEntries(cmFileSet const* fs);
+
void ClearDirectoryEntries();
void AddDirectoryEntry(BT<std::string> directories);
const std::vector<BT<std::string>>& GetDirectoryEntries() const
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index c15db5b..70f51b0 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -27,7 +27,9 @@
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
+#include "cmCryptoHash.h"
#include "cmCustomCommandGenerator.h"
+#include "cmCxxModuleUsageEffects.h"
#include "cmEvaluatedTargetProperty.h"
#include "cmExperimental.h"
#include "cmFileSet.h"
@@ -52,6 +54,7 @@
#include "cmStandardLevelResolver.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
+#include "cmSyntheticTargetCache.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetLinkLibraryType.h"
@@ -8230,6 +8233,96 @@ void ComputeLinkImplTransitive(cmGeneratorTarget const* self,
}
}
+bool cmGeneratorTarget::DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
+ std::string const& config)
+{
+ cmOptionalLinkImplementation impl;
+ this->ComputeLinkImplementationLibraries(config, impl, this,
+ LinkInterfaceFor::Link);
+
+ cmCxxModuleUsageEffects usage(this);
+
+ auto& SyntheticDeps = this->Configs[config].SyntheticDeps;
+
+ for (auto const& entry : impl.Libraries) {
+ auto const* gt = entry.Target;
+ if (!gt || !gt->IsImported()) {
+ continue;
+ }
+
+ if (gt->HaveCxx20ModuleSources()) {
+ auto hasher = cmCryptoHash::New("SHA3_512");
+ constexpr size_t HASH_TRUNCATION = 12;
+ auto dirhash = hasher->HashString(
+ gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
+ std::string safeName = gt->GetName();
+ cmSystemTools::ReplaceString(safeName, ":", "_");
+ auto targetIdent =
+ hasher->HashString(cmStrCat("@d_", dirhash, "@u_", usage.GetHash()));
+ std::string targetName =
+ cmStrCat(safeName, "@synth_", targetIdent.substr(0, HASH_TRUNCATION));
+
+ // Check the cache to see if this instance of the imported target has
+ // already been created.
+ auto cached = cache.CxxModuleTargets.find(targetName);
+ cmGeneratorTarget const* synthDep = nullptr;
+ if (cached == cache.CxxModuleTargets.end()) {
+ auto const* model = gt->Target;
+ auto* mf = gt->Makefile;
+ auto* lg = gt->GetLocalGenerator();
+ auto* tgt = mf->AddSynthesizedTarget(cmStateEnums::INTERFACE_LIBRARY,
+ targetName);
+
+ // Copy relevant information from the existing IMPORTED target.
+
+ // Copy policies to the target.
+ tgt->CopyPolicyStatuses(model);
+
+ // Copy file sets.
+ {
+ auto fsNames = model->GetAllFileSetNames();
+ for (auto const& fsName : fsNames) {
+ auto const* fs = model->GetFileSet(fsName);
+ if (!fs) {
+ mf->IssueMessage(MessageType::INTERNAL_ERROR,
+ cmStrCat("Failed to find file set named '",
+ fsName, "' on target '",
+ tgt->GetName(), '\''));
+ continue;
+ }
+ auto* newFs = tgt
+ ->GetOrCreateFileSet(fs->GetName(), fs->GetType(),
+ fs->GetVisibility())
+ .first;
+ newFs->CopyEntries(fs);
+ }
+ }
+
+ // Copy imported C++ module properties.
+ tgt->CopyImportedCxxModulesEntries(model);
+
+ // Copy other properties which may affect the C++ module BMI
+ // generation.
+ tgt->CopyImportedCxxModulesProperties(model);
+
+ // Apply usage requirements to the target.
+ usage.ApplyToTarget(tgt);
+
+ // Create the generator target and attach it to the local generator.
+ auto gtp = cm::make_unique<cmGeneratorTarget>(tgt, lg);
+ synthDep = gtp.get();
+ lg->AddGeneratorTarget(std::move(gtp));
+ } else {
+ synthDep = cached->second;
+ }
+
+ SyntheticDeps[gt].push_back(synthDep);
+ }
+ }
+
+ return true;
+}
+
void cmGeneratorTarget::ComputeLinkImplementationLibraries(
const std::string& config, cmOptionalLinkImplementation& impl,
cmGeneratorTarget const* head, LinkInterfaceFor implFor) const
@@ -8237,6 +8330,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
cmLocalGenerator const* lg = this->LocalGenerator;
cmMakefile const* mf = lg->GetMakefile();
cmBTStringRange entryRange = this->Target->GetLinkImplementationEntries();
+ auto const& synthTargetsForConfig = this->Configs[config].SyntheticDeps;
// Collect libraries directly linked in this configuration.
for (auto const& entry : entryRange) {
// Keep this logic in sync with ExpandLinkItems.
@@ -8326,7 +8420,15 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
// The entry is meant for this configuration.
cmLinkItem item =
this->ResolveLinkItem(BT<std::string>(name, entry.Backtrace), lg);
- if (!item.Target) {
+ if (item.Target) {
+ auto depsForTarget = synthTargetsForConfig.find(item.Target);
+ if (depsForTarget != synthTargetsForConfig.end()) {
+ for (auto const* depForTarget : depsForTarget->second) {
+ cmLinkItem synthItem(depForTarget, item.Cross, item.Backtrace);
+ impl.Libraries.emplace_back(std::move(synthItem), false);
+ }
+ }
+ } else {
// Report explicitly linked object files separately.
std::string const& maybeObj = item.AsStr();
if (cmSystemTools::FileIsFullPath(maybeObj)) {
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 3adf5b8..f347133 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -31,6 +31,7 @@ class cmGlobalGenerator;
class cmLocalGenerator;
class cmMakefile;
class cmSourceFile;
+struct cmSyntheticTargetCache;
class cmTarget;
struct cmGeneratorExpressionContext;
@@ -932,6 +933,9 @@ public:
std::string GetImportedXcFrameworkPath(const std::string& config) const;
+ bool DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
+ std::string const& config);
+
private:
void AddSourceCommon(const std::string& src, bool before = false);
@@ -1307,6 +1311,8 @@ private:
{
bool BuiltFileSetCache = false;
std::map<std::string, cmFileSet const*> FileSetCache;
+ std::map<cmGeneratorTarget const*, std::vector<cmGeneratorTarget const*>>
+ SyntheticDeps;
};
mutable std::map<std::string, InfoByConfig> Configs;
};
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 9af6e9b..d5099ee 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -55,6 +55,7 @@
#include "cmStateDirectory.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
+#include "cmSyntheticTargetCache.h"
#include "cmSystemTools.h"
#include "cmValue.h"
#include "cmVersion.h"
@@ -1560,6 +1561,17 @@ bool cmGlobalGenerator::Compute()
}
#endif
+ // Iterate through all targets and set up C++20 module targets.
+ // Create target templates for each imported target with C++20 modules.
+ // INTERFACE library with BMI-generating rules and a collation step?
+ // Maybe INTERFACE libraries with modules files should just do BMI-only?
+ // Make `add_dependencies(imported_target
+ // $<$<TARGET_NAME_IF_EXISTS:uses_imported>:synth1>
+ // $<$<TARGET_NAME_IF_EXISTS:other_uses_imported>:synth2>)`
+ if (!this->DiscoverSyntheticTargets()) {
+ return false;
+ }
+
// Add generator specific helper commands
for (const auto& localGen : this->LocalGenerators) {
localGen->AddHelperCommands();
@@ -1784,6 +1796,34 @@ void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
entry->second = index++;
}
+bool cmGlobalGenerator::DiscoverSyntheticTargets()
+{
+ cmSyntheticTargetCache cache;
+
+ for (auto const& gen : this->LocalGenerators) {
+ // Because DiscoverSyntheticTargets() adds generator targets, we need to
+ // cache the existing list of generator targets before starting.
+ std::vector<cmGeneratorTarget*> genTargets;
+ genTargets.reserve(gen->GetGeneratorTargets().size());
+ for (auto const& tgt : gen->GetGeneratorTargets()) {
+ genTargets.push_back(tgt.get());
+ }
+
+ for (auto* tgt : genTargets) {
+ std::vector<std::string> const& configs =
+ tgt->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ for (auto const& config : configs) {
+ if (!tgt->DiscoverSyntheticTargets(cache, config)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
bool cmGlobalGenerator::AddHeaderSetVerification()
{
for (auto const& gen : this->LocalGenerators) {
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 563ebb6..6d29dc1 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -662,6 +662,8 @@ protected:
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
+ bool DiscoverSyntheticTargets();
+
bool AddHeaderSetVerification();
bool AddAutomaticSources();
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 7d4b497..ace93e8 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -1748,6 +1748,186 @@ cmBTStringRange cmTarget::GetLinkInterfaceDirectExcludeEntries() const
return cmMakeRange(this->impl->InterfaceLinkLibrariesDirectExclude.Entries);
}
+void cmTarget::CopyPolicyStatuses(cmTarget const* tgt)
+{
+ // Normal targets cannot be the target of a copy.
+ assert(!this->IsNormal());
+ // Imported targets cannot be the target of a copy.
+ assert(!this->IsImported());
+ // Only imported targets can be the source of a copy.
+ assert(tgt->IsImported());
+
+ this->impl->PolicyMap = tgt->impl->PolicyMap;
+}
+
+void cmTarget::CopyImportedCxxModulesEntries(cmTarget const* tgt)
+{
+ // Normal targets cannot be the target of a copy.
+ assert(!this->IsNormal());
+ // Imported targets cannot be the target of a copy.
+ assert(!this->IsImported());
+ // Only imported targets can be the source of a copy.
+ assert(tgt->IsImported());
+
+ this->impl->IncludeDirectories.Entries.clear();
+ this->impl->IncludeDirectories.CopyFromEntries(
+ cmMakeRange(tgt->impl->ImportedCxxModulesIncludeDirectories.Entries));
+ this->impl->CompileDefinitions.Entries.clear();
+ this->impl->CompileDefinitions.CopyFromEntries(
+ cmMakeRange(tgt->impl->ImportedCxxModulesCompileDefinitions.Entries));
+ this->impl->CompileFeatures.Entries.clear();
+ this->impl->CompileFeatures.CopyFromEntries(
+ cmMakeRange(tgt->impl->ImportedCxxModulesCompileFeatures.Entries));
+ this->impl->CompileOptions.Entries.clear();
+ this->impl->CompileOptions.CopyFromEntries(
+ cmMakeRange(tgt->impl->ImportedCxxModulesCompileOptions.Entries));
+ this->impl->LinkLibraries.Entries.clear();
+ this->impl->LinkLibraries.CopyFromEntries(
+ cmMakeRange(tgt->impl->LinkLibraries.Entries));
+
+ // Copy the C++ module fileset entries from `tgt`'s `INTERFACE` to this
+ // target's `PRIVATE`.
+ this->impl->CxxModulesFileSets.SelfEntries.Entries.clear();
+ this->impl->CxxModulesFileSets.SelfEntries.Entries =
+ tgt->impl->CxxModulesFileSets.InterfaceEntries.Entries;
+}
+
+void cmTarget::CopyImportedCxxModulesProperties(cmTarget const* tgt)
+{
+ // Normal targets cannot be the target of a copy.
+ assert(!this->IsNormal());
+ // Imported targets cannot be the target of a copy.
+ assert(!this->IsImported());
+ // Only imported targets can be the source of a copy.
+ assert(tgt->IsImported());
+
+ // The list of properties that are relevant here include:
+ // - compilation-specific properties for any language or platform
+ // - compilation-specific properties for C++
+ // - build graph-specific properties that affect compilation
+ // - IDE metadata properties
+ // - static analysis properties
+
+ static const std::string propertiesToCopy[] = {
+ // Compilation properties
+ "DEFINE_SYMBOL",
+ "DEPRECATION",
+ "NO_SYSTEM_FROM_IMPORTED",
+ "POSITION_INDEPENDENT_CODE",
+ "VISIBILITY_INLINES_HIDDEN",
+ // -- Platforms
+ // ---- Android
+ "ANDROID_API",
+ "ANDROID_API_MIN",
+ "ANDROID_ARCH",
+ "ANDROID_STL_TYPE",
+ // ---- macOS
+ "OSX_ARCHITECTURES",
+ // ---- Windows
+ "MSVC_DEBUG_INFORMATION_FORMAT",
+ "MSVC_RUNTIME_LIBRARY",
+ "VS_PLATFORM_TOOLSET",
+ // ---- OpenWatcom
+ "WATCOM_RUNTIME_LIBRARY",
+ // -- Language
+ // ---- C++
+ "CXX_COMPILER_LAUNCHER",
+ "CXX_STANDARD",
+ "CXX_STANDARD_REQUIRED",
+ "CXX_EXTENSIONS",
+ "CXX_VISIBILITY_PRESET",
+
+ // Static analysis
+ "CXX_CLANG_TIDY",
+ "CXX_CLANG_TIDY_EXPORT_FIXES_DIR",
+ "CXX_CPPLINT",
+ "CXX_CPPCHECK",
+ "CXX_INCLUDE_WHAT_YOU_USE",
+
+ // Build graph properties
+ "EXCLUDE_FROM_ALL",
+ "EXCLUDE_FROM_DEFAULT_BUILD",
+ "OPTIMIZE_DEPENDENCIES",
+ // -- Ninja
+ "JOB_POOL_COMPILE",
+ // -- Visual Studio
+ "VS_NO_COMPILE_BATCHING",
+ "VS_PROJECT_IMPORT",
+
+ // Metadata
+ "EchoString",
+ "EXPORT_COMPILE_COMMANDS",
+ "FOLDER",
+ "LABELS",
+ "PROJECT_LABEL",
+ "SYSTEM",
+ };
+
+ auto copyProperty = [this, tgt](std::string const& prop) -> cmValue {
+ cmValue value = tgt->GetProperty(prop);
+ // Always set the property; it may have been explicitly unset.
+ this->SetProperty(prop, value);
+ return value;
+ };
+
+ for (auto const& prop : propertiesToCopy) {
+ copyProperty(prop);
+ }
+
+ static const cm::static_string_view perConfigPropertiesToCopy[] = {
+ "EXCLUDE_FROM_DEFAULT_BUILD_"_s,
+ "IMPORTED_CXX_MODULES_"_s,
+ "MAP_IMPORTED_CONFIG_"_s,
+ "OSX_ARCHITECTURES_"_s,
+ };
+
+ std::vector<std::string> configNames =
+ this->impl->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+ for (std::string const& configName : configNames) {
+ std::string configUpper = cmSystemTools::UpperCase(configName);
+ for (auto const& perConfigProp : perConfigPropertiesToCopy) {
+ copyProperty(cmStrCat(perConfigProp, configUpper));
+ }
+ }
+
+ if (this->GetGlobalGenerator()->IsXcode()) {
+ cmValue xcodeGenerateScheme = copyProperty("XCODE_GENERATE_SCHEME");
+
+ // TODO: Make sure these show up on the imported target in the first place
+ // XCODE_ATTRIBUTE_???
+
+ if (xcodeGenerateScheme.IsOn()) {
+#ifdef __APPLE__
+ static const std::string xcodeSchemePropertiesToCopy[] = {
+ // FIXME: Do all of these apply? Do they matter?
+ "XCODE_SCHEME_ADDRESS_SANITIZER",
+ "XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN",
+ "XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER",
+ "XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS",
+ "XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE",
+ "XCODE_SCHEME_ENABLE_GPU_API_VALIDATION",
+ "XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION",
+ "XCODE_SCHEME_GUARD_MALLOC",
+ "XCODE_SCHEME_LAUNCH_CONFIGURATION",
+ "XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP",
+ "XCODE_SCHEME_MALLOC_GUARD_EDGES",
+ "XCODE_SCHEME_MALLOC_SCRIBBLE",
+ "XCODE_SCHEME_MALLOC_STACK",
+ "XCODE_SCHEME_THREAD_SANITIZER",
+ "XCODE_SCHEME_THREAD_SANITIZER_STOP",
+ "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER",
+ "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP",
+ "XCODE_SCHEME_ZOMBIE_OBJECTS",
+ };
+
+ for (auto const& xcodeProperty : xcodeSchemePropertiesToCopy) {
+ copyProperty(xcodeProperty);
+ }
+#endif
+ }
+ }
+}
+
cmBTStringRange cmTarget::GetHeaderSetsEntries() const
{
return cmMakeRange(this->impl->HeadersFileSets.SelfEntries.Entries);
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index dae997f..b77ea0c 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -291,6 +291,10 @@ public:
cmBTStringRange GetLinkInterfaceDirectEntries() const;
cmBTStringRange GetLinkInterfaceDirectExcludeEntries() const;
+ void CopyPolicyStatuses(cmTarget const* tgt);
+ void CopyImportedCxxModulesEntries(cmTarget const* tgt);
+ void CopyImportedCxxModulesProperties(cmTarget const* tgt);
+
cmBTStringRange GetHeaderSetsEntries() const;
cmBTStringRange GetCxxModuleSetsEntries() const;