diff options
-rw-r--r-- | Source/cmFileSet.cxx | 7 | ||||
-rw-r--r-- | Source/cmFileSet.h | 2 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 104 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.h | 6 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.cxx | 40 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.h | 2 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 180 | ||||
-rw-r--r-- | Source/cmTarget.h | 4 |
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; |