diff options
Diffstat (limited to 'Source/cmGeneratorTarget.cxx')
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 1383 |
1 files changed, 908 insertions, 475 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 94a795e..39224d1 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -17,6 +17,8 @@ #include <cm/memory> #include <cm/string_view> +#include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/RegularExpression.hxx" @@ -51,11 +53,11 @@ class cmMessenger; template <> -const char* cmTargetPropertyComputer::GetSources<cmGeneratorTarget>( +cmProp cmTargetPropertyComputer::GetSources<cmGeneratorTarget>( cmGeneratorTarget const* tgt, cmMessenger* /* messenger */, cmListFileBacktrace const& /* context */) { - return tgt->GetSourcesProperty().c_str(); + return &tgt->GetSourcesProperty(); } template <> @@ -236,17 +238,23 @@ EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry( return ee; } -std::vector<EvaluatedTargetPropertyEntry> EvaluateTargetPropertyEntries( +struct EvaluatedTargetPropertyEntries +{ + std::vector<EvaluatedTargetPropertyEntry> Entries; + bool HadContextSensitiveCondition = false; +}; + +EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries( cmGeneratorTarget const* thisTarget, std::string const& config, std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const& in) { - std::vector<EvaluatedTargetPropertyEntry> out; - out.reserve(in.size()); + EvaluatedTargetPropertyEntries out; + out.Entries.reserve(in.size()); for (auto& entry : in) { - out.emplace_back(EvaluateTargetPropertyEntry(thisTarget, config, lang, - dagChecker, *entry)); + out.Entries.emplace_back(EvaluateTargetPropertyEntry( + thisTarget, config, lang, dagChecker, *entry)); } return out; } @@ -308,6 +316,13 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) this->SourceEntries, true); this->PolicyMap = t->GetPolicyMap(); + + // Get hard-coded linker language + if (this->Target->GetProperty("HAS_CXX")) { + this->LinkerLanguage = "CXX"; + } else { + this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE"); + } } cmGeneratorTarget::~cmGeneratorTarget() = default; @@ -346,29 +361,29 @@ const std::string& cmGeneratorTarget::GetName() const std::string cmGeneratorTarget::GetExportName() const { - const char* exportName = this->GetProperty("EXPORT_NAME"); + cmProp exportName = this->GetProperty("EXPORT_NAME"); - if (exportName && *exportName) { - if (!cmGeneratorExpression::IsValidTargetName(exportName)) { + if (exportName && !exportName->empty()) { + if (!cmGeneratorExpression::IsValidTargetName(*exportName)) { std::ostringstream e; - e << "EXPORT_NAME property \"" << exportName << "\" for \"" + e << "EXPORT_NAME property \"" << *exportName << "\" for \"" << this->GetName() << "\": is not valid."; cmSystemTools::Error(e.str()); return ""; } - return exportName; + return *exportName; } return this->GetName(); } -const char* cmGeneratorTarget::GetProperty(const std::string& prop) const +cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const { if (!cmTargetPropertyComputer::PassesWhitelist( this->GetType(), prop, this->Makefile->GetMessenger(), this->GetBacktrace())) { return nullptr; } - if (const char* result = cmTargetPropertyComputer::GetProperty( + if (cmProp result = cmTargetPropertyComputer::GetProperty( this, prop, this->Makefile->GetMessenger(), this->GetBacktrace())) { return result; } @@ -378,13 +393,16 @@ const char* cmGeneratorTarget::GetProperty(const std::string& prop) const return this->Target->GetProperty(prop); } -const char* cmGeneratorTarget::GetSafeProperty(const std::string& prop) const +std::string const& cmGeneratorTarget::GetSafeProperty( + std::string const& prop) const { - const char* ret = this->GetProperty(prop); - if (!ret) { - return ""; + cmProp ret = this->GetProperty(prop); + if (ret) { + return *ret; } - return ret; + + static std::string const s_empty; + return s_empty; } const char* cmGeneratorTarget::GetOutputTargetType( @@ -473,8 +491,8 @@ std::string cmGeneratorTarget::GetOutputName( std::string outName; for (std::string const& p : props) { - if (const char* outNameProp = this->GetProperty(p)) { - outName = outNameProp; + if (cmProp outNameProp = this->GetProperty(p)) { + outName = *outNameProp; break; } } @@ -530,18 +548,46 @@ std::string cmGeneratorTarget::GetFileSuffix( std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const { - const char* postfix = nullptr; + cmProp postfix = nullptr; + std::string frameworkPostfix; if (!config.empty()) { std::string configProp = cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX"); postfix = this->GetProperty(configProp); - // Mac application bundles and frameworks have no postfix. + + // Mac application bundles and frameworks have no regular postfix like + // libraries do. if (!this->IsImported() && postfix && (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) { postfix = nullptr; } + + // Frameworks created by multi config generators can have a special + // framework postfix. + frameworkPostfix = GetFrameworkMultiConfigPostfix(config); + if (!frameworkPostfix.empty()) { + postfix = &frameworkPostfix; + } + } + return postfix ? *postfix : std::string(); +} + +std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix( + const std::string& config) const +{ + cmProp postfix = nullptr; + if (!config.empty()) { + std::string configProp = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_", + cmSystemTools::UpperCase(config)); + postfix = this->GetProperty(configProp); + + if (!this->IsImported() && postfix && + (this->IsFrameworkOnApple() && + !GetGlobalGenerator()->IsMultiConfig())) { + postfix = nullptr; + } } - return postfix ? postfix : std::string(); + return postfix ? *postfix : std::string(); } const char* cmGeneratorTarget::GetFilePrefixInternal( @@ -574,7 +620,7 @@ const char* cmGeneratorTarget::GetFilePrefixInternal( } // Compute prefix value. - const char* targetPrefix = + cmProp targetPrefix = (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX") : this->GetProperty("PREFIX")); @@ -582,17 +628,17 @@ const char* cmGeneratorTarget::GetFilePrefixInternal( const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact); if (!language.empty() && prefixVar && *prefixVar) { std::string langPrefix = prefixVar + std::string("_") + language; - targetPrefix = this->Makefile->GetDefinition(langPrefix); + targetPrefix = this->Makefile->GetDef(langPrefix); } // if there is no prefix on the target nor specific language // use the cmake definition. if (!targetPrefix && prefixVar) { - targetPrefix = this->Makefile->GetDefinition(prefixVar); + targetPrefix = this->Makefile->GetDef(prefixVar); } } - return targetPrefix; + return targetPrefix ? targetPrefix->c_str() : nullptr; } const char* cmGeneratorTarget::GetFileSuffixInternal( std::string const& config, cmStateEnums::ArtifactType artifact, @@ -624,7 +670,7 @@ const char* cmGeneratorTarget::GetFileSuffixInternal( } // Compute suffix value. - const char* targetSuffix = + cmProp targetSuffix = (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX") : this->GetProperty("SUFFIX")); @@ -632,17 +678,17 @@ const char* cmGeneratorTarget::GetFileSuffixInternal( const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact); if (!language.empty() && suffixVar && *suffixVar) { std::string langSuffix = suffixVar + std::string("_") + language; - targetSuffix = this->Makefile->GetDefinition(langSuffix); + targetSuffix = this->Makefile->GetDef(langSuffix); } // if there is no suffix on the target nor specific language // use the cmake definition. if (!targetSuffix && suffixVar) { - targetSuffix = this->Makefile->GetDefinition(suffixVar); + targetSuffix = this->Makefile->GetDef(suffixVar); } } - return targetSuffix; + return targetSuffix ? targetSuffix->c_str() : nullptr; } void cmGeneratorTarget::ClearSourcesCache() @@ -705,9 +751,9 @@ void handleSystemIncludesDep(cmLocalGenerator* lg, std::vector<std::string>& result, bool excludeImported, std::string const& language) { - if (const char* dirs = + if (cmProp dirs = depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) { - cmExpandList(cmGeneratorExpression::Evaluate(dirs, lg, config, headTarget, + cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget, dagChecker, depTgt, language), result); } @@ -715,9 +761,8 @@ void handleSystemIncludesDep(cmLocalGenerator* lg, return; } - if (const char* dirs = - depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) { - cmExpandList(cmGeneratorExpression::Evaluate(dirs, lg, config, headTarget, + if (cmProp dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) { + cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget, dagChecker, depTgt, language), result); } @@ -773,12 +818,12 @@ const char* cmGeneratorTarget::GetFeature(const std::string& feature, if (!config.empty()) { std::string featureConfig = cmStrCat(feature, '_', cmSystemTools::UpperCase(config)); - if (const char* value = this->GetProperty(featureConfig)) { - return value; + if (cmProp value = this->GetProperty(featureConfig)) { + return value->c_str(); } } - if (const char* value = this->GetProperty(feature)) { - return value; + if (cmProp value = this->GetProperty(feature)) { + return value->c_str(); } return this->LocalGenerator->GetFeature(feature, config); } @@ -931,51 +976,12 @@ void cmGeneratorTarget::GetExternalObjects( IMPLEMENT_VISIT(SourceKindExternalObject); } -void cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& headers, - const std::string& config) const -{ - KindedSources const& kinded = this->GetKindedSources(config); - headers = kinded.ExpectedResxHeaders; -} - -void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile const*>& data, - const std::string& config) const -{ - IMPLEMENT_VISIT(SourceKindResx); -} - -void cmGeneratorTarget::GetAppManifest(std::vector<cmSourceFile const*>& data, - const std::string& config) const -{ - IMPLEMENT_VISIT(SourceKindAppManifest); -} - void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data, const std::string& config) const { IMPLEMENT_VISIT(SourceKindManifest); } -void cmGeneratorTarget::GetCertificates(std::vector<cmSourceFile const*>& data, - const std::string& config) const -{ - IMPLEMENT_VISIT(SourceKindCertificate); -} - -void cmGeneratorTarget::GetExpectedXamlHeaders(std::set<std::string>& headers, - const std::string& config) const -{ - KindedSources const& kinded = this->GetKindedSources(config); - headers = kinded.ExpectedXamlHeaders; -} - -void cmGeneratorTarget::GetExpectedXamlSources(std::set<std::string>& srcs, - const std::string& config) const -{ - KindedSources const& kinded = this->GetKindedSources(config); - srcs = kinded.ExpectedXamlSources; -} - std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const { if (!this->UtilityItemsDone) { @@ -995,12 +1001,6 @@ std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const return this->UtilityItems; } -void cmGeneratorTarget::GetXamlSources(std::vector<cmSourceFile const*>& data, - const std::string& config) const -{ - IMPLEMENT_VISIT(SourceKindXaml); -} - const std::string& cmGeneratorTarget::GetLocation( const std::string& config) const { @@ -1052,7 +1052,8 @@ const std::string& cmGeneratorTarget::GetLocationForBuild() const } // Now handle the deprecated build-time configuration location. - location = this->GetDirectory(); + std::string const noConfig; + location = this->GetDirectory(noConfig); const char* cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR"); if (cfgid && strcmp(cfgid, ".") != 0) { location += "/"; @@ -1134,8 +1135,8 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( bool& maybeInterfaceProp = i->second; // If this target itself has a non-empty property value, we are done. - const char* p = this->GetProperty(prop); - maybeInterfaceProp = p && *p; + cmProp p = this->GetProperty(prop); + maybeInterfaceProp = p && !p->empty(); // Otherwise, recurse to interface dependencies. if (!maybeInterfaceProp) { @@ -1191,7 +1192,6 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( return result; case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: // No error. We just skip cyclic references. - return result; case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: // No error. We have already seen this transitive property. return result; @@ -1202,13 +1202,16 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( cmGeneratorTarget const* headTarget = context->HeadTarget ? context->HeadTarget : this; - if (const char* p = this->GetProperty(prop)) { + if (cmProp p = this->GetProperty(prop)) { result = cmGeneratorExpressionNode::EvaluateDependentExpression( - p, context->LG, context, headTarget, &dagChecker, this); + *p, context->LG, context, headTarget, &dagChecker, this); } if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries( context->Config, headTarget, usage_requirements_only)) { + context->HadContextSensitiveCondition = + context->HadContextSensitiveCondition || + iface->HadContextSensitiveCondition; for (cmLinkItem const& lib : iface->Libraries) { // Broken code can have a target in its own link interface. // Don't follow such link interface entries so as not to create a @@ -1247,15 +1250,96 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( } namespace { +std::string AddSwiftInterfaceIncludeDirectories( + const cmGeneratorTarget* root, const cmGeneratorTarget* target, + const std::string& config, cmGeneratorExpressionDAGChecker* context) +{ + cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target, + "Swift_MODULE_DIRECTORY", nullptr, + context }; + switch (dag.Check()) { + case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: + dag.ReportError(nullptr, + "$<TARGET_PROPERTY:" + target->GetName() + + ",Swift_MODULE_DIRECTORY>"); + CM_FALLTHROUGH; + case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: + // No error. We just skip cyclic references. + case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: + // No error. We have already seen this transitive property. + return ""; + case cmGeneratorExpressionDAGChecker::DAG: + break; + } + + std::string directories; + if (const auto* interface = + target->GetLinkInterfaceLibraries(config, root, true)) { + for (const cmLinkItem& library : interface->Libraries) { + if (const cmGeneratorTarget* dependency = library.Target) { + if (cm::contains(dependency->GetAllConfigCompileLanguages(), + "Swift")) { + std::string value = + dependency->GetSafeProperty("Swift_MODULE_DIRECTORY"); + if (value.empty()) { + value = + dependency->GetLocalGenerator()->GetCurrentBinaryDirectory(); + } + + if (!directories.empty()) { + directories += ";"; + } + directories += value; + } + } + } + } + return directories; +} + +void AddSwiftImplicitIncludeDirectories( + const cmGeneratorTarget* target, const std::string& config, + EvaluatedTargetPropertyEntries& entries) +{ + if (const auto* libraries = target->GetLinkImplementationLibraries(config)) { + cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target, + "Swift_MODULE_DIRECTORY", nullptr, + nullptr }; + + for (const cmLinkImplItem& library : libraries->Libraries) { + if (const cmGeneratorTarget* dependency = library.Target) { + if (cm::contains(dependency->GetAllConfigCompileLanguages(), + "Swift")) { + EvaluatedTargetPropertyEntry entry{ library, library.Backtrace }; + + if (cmProp val = dependency->GetProperty("Swift_MODULE_DIRECTORY")) { + entry.Values.emplace_back(*val); + } else { + entry.Values.emplace_back( + dependency->GetLocalGenerator()->GetCurrentBinaryDirectory()); + } + + cmExpandList(AddSwiftInterfaceIncludeDirectories(target, dependency, + config, &dag), + entry.Values); + + entries.Entries.emplace_back(std::move(entry)); + } + } + } + } +} + void AddInterfaceEntries(cmGeneratorTarget const* headTarget, std::string const& config, std::string const& prop, std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, - std::vector<EvaluatedTargetPropertyEntry>& entries, + EvaluatedTargetPropertyEntries& entries, bool usage_requirements_only = true) { if (cmLinkImplementationLibraries const* impl = headTarget->GetLinkImplementationLibraries(config)) { + entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; for (cmLinkImplItem const& lib : impl->Libraries) { if (lib.Target) { EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace); @@ -1269,7 +1353,7 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, prop, &context, dagChecker, usage_requirements_only), ee.Values); ee.ContextDependent = context.HadContextSensitiveCondition; - entries.emplace_back(std::move(ee)); + entries.Entries.emplace_back(std::move(ee)); } } } @@ -1278,10 +1362,11 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, void AddObjectEntries(cmGeneratorTarget const* headTarget, std::string const& config, cmGeneratorExpressionDAGChecker* dagChecker, - std::vector<EvaluatedTargetPropertyEntry>& entries) + EvaluatedTargetPropertyEntries& entries) { if (cmLinkImplementationLibraries const* impl = headTarget->GetLinkImplementationLibraries(config)) { + entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; for (cmLinkImplItem const& lib : impl->Libraries) { if (lib.Target && lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { @@ -1300,23 +1385,23 @@ void AddObjectEntries(cmGeneratorTarget const* headTarget, if (cge->GetHadContextSensitiveCondition()) { ee.ContextDependent = true; } - entries.emplace_back(std::move(ee)); + entries.Entries.emplace_back(std::move(ee)); } } } } bool processSources(cmGeneratorTarget const* tgt, - std::vector<EvaluatedTargetPropertyEntry>& entries, + EvaluatedTargetPropertyEntries& entries, std::vector<BT<std::string>>& srcs, std::unordered_set<std::string>& uniqueSrcs, bool debugSources) { cmMakefile* mf = tgt->Target->GetMakefile(); - bool contextDependent = false; + bool contextDependent = entries.HadContextSensitiveCondition; - for (EvaluatedTargetPropertyEntry& entry : entries) { + for (EvaluatedTargetPropertyEntry& entry : entries.Entries) { if (entry.ContextDependent) { contextDependent = true; } @@ -1408,7 +1493,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( } bool debugSources = - !this->DebugSourcesDone && cmContains(debugProperties, "SOURCES"); + !this->DebugSourcesDone && cm::contains(debugProperties, "SOURCES"); if (this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) { this->DebugSourcesDone = true; @@ -1417,16 +1502,15 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, nullptr); - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, std::string(), &dagChecker, - this->SourceEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, std::string(), &dagChecker, this->SourceEntries); std::unordered_set<std::string> uniqueSrcs; bool contextDependentDirectSources = processSources(this, entries, files, uniqueSrcs, debugSources); // Collect INTERFACE_SOURCES of all direct link-dependencies. - std::vector<EvaluatedTargetPropertyEntry> linkInterfaceSourcesEntries; + EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries; AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(), &dagChecker, linkInterfaceSourcesEntries); std::vector<std::string>::size_type numFilesBefore = files.size(); @@ -1437,7 +1521,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( bool contextDependentObjects = false; std::vector<std::string>::size_type numFilesBefore2 = files.size(); if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) { - std::vector<EvaluatedTargetPropertyEntry> linkObjectsEntries; + EvaluatedTargetPropertyEntries linkObjectsEntries; AddObjectEntries(this, config, &dagChecker, linkObjectsEntries); contextDependentObjects = processSources(this, linkObjectsEntries, files, uniqueSrcs, debugSources); @@ -1573,10 +1657,14 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); if (sf->GetCustomCommand()) { kind = SourceKindCustomCommand; + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) } else if (this->Target->GetType() == cmStateEnums::UTILITY) { kind = SourceKindExtra; } else if (this->IsSourceFilePartOfUnityBatch(sf->ResolveFullPath())) { kind = SourceKindUnityBatched; + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) } else if (sf->GetPropertyAsBool("HEADER_FILE_ONLY")) { kind = SourceKindHeader; } else if (sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { @@ -1595,14 +1683,6 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, } } else if (ext == "resx") { kind = SourceKindResx; - // Build and save the name of the corresponding .h file - // This relationship will be used later when building the project files. - // Both names would have been auto generated from Visual Studio - // where the user supplied the file name and Visual Studio - // appended the suffix. - std::string resx = sf->ResolveFullPath(); - std::string hFileName = resx.substr(0, resx.find_last_of('.')) + ".h"; - files.ExpectedResxHeaders.insert(hFileName); } else if (ext == "appxmanifest") { kind = SourceKindAppManifest; } else if (ext == "manifest") { @@ -1611,16 +1691,6 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, kind = SourceKindCertificate; } else if (ext == "xaml") { kind = SourceKindXaml; - // Build and save the name of the corresponding .h and .cpp file - // This relationship will be used later when building the project files. - // Both names would have been auto generated from Visual Studio - // where the user supplied the file name and Visual Studio - // appended the suffix. - std::string xaml = sf->ResolveFullPath(); - std::string hFileName = xaml + ".h"; - std::string cppFileName = xaml + ".cpp"; - files.ExpectedXamlHeaders.insert(hFileName); - files.ExpectedXamlSources.insert(cppFileName); } else if (header_regex.find(sf->ResolveFullPath())) { kind = SourceKindHeader; } else { @@ -1678,6 +1748,18 @@ void cmGeneratorTarget::ComputeAllConfigSources() const } } +std::vector<cmGeneratorTarget::AllConfigSource> +cmGeneratorTarget::GetAllConfigSources(SourceKind kind) const +{ + std::vector<AllConfigSource> result; + for (AllConfigSource const& source : this->GetAllConfigSources()) { + if (source.Kind == kind) { + result.push_back(source); + } + } + return result; +} + std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const { std::set<std::string> languages; @@ -1703,14 +1785,14 @@ std::string cmGeneratorTarget::GetCompilePDBName( // Check for a per-configuration output directory target property. std::string configUpper = cmSystemTools::UpperCase(config); std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper); - const char* config_name = this->GetProperty(configProp); - if (config_name && *config_name) { - return prefix + config_name + ".pdb"; + cmProp config_name = this->GetProperty(configProp); + if (config_name && !config_name->empty()) { + return prefix + *config_name + ".pdb"; } - const char* name = this->GetProperty("COMPILE_PDB_NAME"); - if (name && *name) { - return prefix + name + ".pdb"; + cmProp name = this->GetProperty("COMPILE_PDB_NAME"); + if (name && !name->empty()) { + return prefix + *name + ".pdb"; } return ""; @@ -1892,10 +1974,9 @@ bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir( if (this->GetType() != cmStateEnums::SHARED_LIBRARY) { return false; } - const char* install_name = this->GetProperty("INSTALL_NAME_DIR"); + cmProp install_name = this->GetProperty("INSTALL_NAME_DIR"); bool use_install_name = this->MacOSXUseInstallNameDir(); - if (install_name && use_install_name && - std::string(install_name) == "@rpath") { + if (install_name && use_install_name && *install_name == "@rpath") { install_name_is_rpath = true; } else if (install_name && use_install_name) { return false; @@ -1908,7 +1989,7 @@ bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir( if (cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config)) { if (!info->NoSOName && !info->SOName.empty()) { - if (info->SOName.find("@rpath/") == 0) { + if (cmHasLiteralPrefix(info->SOName, "@rpath/")) { install_name_is_rpath = true; } } else { @@ -1951,7 +2032,7 @@ bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const return false; } - const char* macosx_rpath_str = this->GetProperty("MACOSX_RPATH"); + cmProp macosx_rpath_str = this->GetProperty("MACOSX_RPATH"); if (macosx_rpath_str) { return this->GetPropertyAsBool("MACOSX_RPATH"); } @@ -1968,10 +2049,10 @@ bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const bool cmGeneratorTarget::MacOSXUseInstallNameDir() const { - const char* build_with_install_name = + cmProp build_with_install_name = this->GetProperty("BUILD_WITH_INSTALL_NAME_DIR"); if (build_with_install_name) { - return cmIsOn(build_with_install_name); + return cmIsOn(*build_with_install_name); } cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068(); @@ -2025,7 +2106,7 @@ std::string cmGeneratorTarget::GetSOName(const std::string& config) const return cmSystemTools::GetFilenameName(info->Location); } // Use the soname given if any. - if (info->SOName.find("@rpath/") == 0) { + if (cmHasLiteralPrefix(info->SOName, "@rpath/")) { return info->SOName.substr(6); } return info->SOName; @@ -2053,11 +2134,8 @@ std::string cmGeneratorTarget::GetAppBundleDirectory( { std::string fpath = cmStrCat( this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact), '.'); - const char* ext = this->GetProperty("BUNDLE_EXTENSION"); - if (!ext) { - ext = "app"; - } - fpath += ext; + cmProp ext = this->GetProperty("BUNDLE_EXTENSION"); + fpath += (ext ? *ext : "app"); if (shouldAddContentLevel(level) && !this->Makefile->PlatformIsAppleEmbedded()) { fpath += "/Contents"; @@ -2079,8 +2157,10 @@ std::string cmGeneratorTarget::GetCFBundleDirectory( { std::string fpath = cmStrCat( this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.'); - const char* ext = this->GetProperty("BUNDLE_EXTENSION"); - if (!ext) { + std::string ext; + if (cmProp p = this->GetProperty("BUNDLE_EXTENSION")) { + ext = *p; + } else { if (this->IsXCTestOnApple()) { ext = "xctest"; } else { @@ -2103,11 +2183,8 @@ std::string cmGeneratorTarget::GetFrameworkDirectory( { std::string fpath = cmStrCat( this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.'); - const char* ext = this->GetProperty("BUNDLE_EXTENSION"); - if (!ext) { - ext = "framework"; - } - fpath += ext; + cmProp ext = this->GetProperty("BUNDLE_EXTENSION"); + fpath += (ext ? *ext : "framework"); if (shouldAddFullLevel(level) && !this->Makefile->PlatformIsAppleEmbedded()) { fpath += "/Versions/"; @@ -2158,11 +2235,11 @@ std::string cmGeneratorTarget::GetInstallNameDirForInstallTree( { if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { std::string dir; - const char* install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); + cmProp install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) { - if (install_name_dir && *install_name_dir) { - dir = install_name_dir; + if (install_name_dir && !install_name_dir->empty()) { + dir = *install_name_dir; cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix); dir = cmGeneratorExpression::Evaluate(dir, this->LocalGenerator, config); @@ -2207,8 +2284,8 @@ const std::string* cmGeneratorTarget::GetExportMacro() const if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::MODULE_LIBRARY || this->IsExecutableWithExports()) { - if (const char* custom_export_name = this->GetProperty("DEFINE_SYMBOL")) { - this->ExportMacro = custom_export_name; + if (cmProp custom_export_name = this->GetProperty("DEFINE_SYMBOL")) { + this->ExportMacro = *custom_export_name; } else { std::string in = cmStrCat(this->GetName(), "_EXPORTS"); this->ExportMacro = cmSystemTools::MakeCidentifier(in); @@ -2224,11 +2301,12 @@ public: cmTargetCollectLinkLanguages(cmGeneratorTarget const* target, std::string config, std::unordered_set<std::string>& languages, - cmGeneratorTarget const* head) + cmGeneratorTarget const* head, bool secondPass) : Config(std::move(config)) , Languages(languages) , HeadTarget(head) , Target(target) + , SecondPass(secondPass) { this->Visited.insert(target); } @@ -2270,11 +2348,14 @@ public: if (!this->Visited.insert(item.Target).second) { return; } - cmLinkInterface const* iface = - item.Target->GetLinkInterface(this->Config, this->HeadTarget); + cmLinkInterface const* iface = item.Target->GetLinkInterface( + this->Config, this->HeadTarget, this->SecondPass); if (!iface) { return; } + if (iface->HadLinkLanguageSensitiveCondition) { + this->HadLinkLanguageSensitiveCondition = true; + } for (std::string const& language : iface->Languages) { this->Languages.insert(language); @@ -2285,12 +2366,19 @@ public: } } + bool GetHadLinkLanguageSensitiveCondition() + { + return HadLinkLanguageSensitiveCondition; + } + private: std::string Config; std::unordered_set<std::string>& Languages; cmGeneratorTarget const* HeadTarget; const cmGeneratorTarget* Target; std::set<cmGeneratorTarget const*> Visited; + bool SecondPass; + bool HadLinkLanguageSensitiveCondition = false; }; cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure( @@ -2321,7 +2409,7 @@ public: { this->GG = this->Target->GetLocalGenerator()->GetGlobalGenerator(); } - void Consider(const char* lang) + void Consider(const std::string& lang) { int preference = this->GG->GetLinkerPreference(lang); if (preference > this->Preference) { @@ -2354,40 +2442,36 @@ public: } }; -void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, - LinkClosure& lc) const +bool cmGeneratorTarget::ComputeLinkClosure(const std::string& config, + LinkClosure& lc, + bool secondPass) const { // Get languages built in this target. std::unordered_set<std::string> languages; - cmLinkImplementation const* impl = this->GetLinkImplementation(config); + cmLinkImplementation const* impl = + this->GetLinkImplementation(config, secondPass); assert(impl); - for (std::string const& li : impl->Languages) { - languages.insert(li); - } + languages.insert(impl->Languages.cbegin(), impl->Languages.cend()); // Add interface languages from linked targets. - cmTargetCollectLinkLanguages cll(this, config, languages, this); + // cmTargetCollectLinkLanguages cll(this, config, languages, this, + // secondPass); + cmTargetCollectLinkLanguages cll(this, config, languages, this, secondPass); for (cmLinkImplItem const& lib : impl->Libraries) { cll.Visit(lib); } // Store the transitive closure of languages. - for (std::string const& lang : languages) { - lc.Languages.push_back(lang); - } + cm::append(lc.Languages, languages); // Choose the language whose linker should be used. - if (this->GetProperty("HAS_CXX")) { - lc.LinkerLanguage = "CXX"; - } else if (const char* linkerLang = this->GetProperty("LINKER_LANGUAGE")) { - lc.LinkerLanguage = linkerLang; - } else { + if (secondPass || lc.LinkerLanguage.empty()) { // Find the language with the highest preference value. cmTargetSelectLinker tsl(this); // First select from the languages compiled directly in this target. for (std::string const& l : impl->Languages) { - tsl.Consider(l.c_str()); + tsl.Consider(l); } // Now consider languages that propagate from linked targets. @@ -2395,12 +2479,50 @@ void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, std::string propagates = "CMAKE_" + lang + "_LINKER_PREFERENCE_PROPAGATES"; if (this->Makefile->IsOn(propagates)) { - tsl.Consider(lang.c_str()); + tsl.Consider(lang); } } lc.LinkerLanguage = tsl.Choose(); } + + return impl->HadLinkLanguageSensitiveCondition || + cll.GetHadLinkLanguageSensitiveCondition(); +} + +void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, + LinkClosure& lc) const +{ + bool secondPass = false; + + { + LinkClosure linkClosure; + linkClosure.LinkerLanguage = this->LinkerLanguage; + + // Get languages built in this target. + secondPass = this->ComputeLinkClosure(config, linkClosure, false); + this->LinkerLanguage = linkClosure.LinkerLanguage; + if (!secondPass) { + lc = std::move(linkClosure); + } + } + + if (secondPass) { + LinkClosure linkClosure; + + this->ComputeLinkClosure(config, linkClosure, secondPass); + lc = std::move(linkClosure); + + // linker language must not be changed between the two passes + if (this->LinkerLanguage != lc.LinkerLanguage) { + std::ostringstream e; + e << "Evaluation of $<LINK_LANGUAGE:...> or $<LINK_LAND_AND_ID:...> " + "changes\nthe linker language for target \"" + << this->GetName() << "\" (from '" << this->LinkerLanguage << "' to '" + << lc.LinkerLanguage << "') which is invalid."; + cmSystemTools::Error(e.str()); + } + } } void cmGeneratorTarget::GetFullNameComponents( @@ -2450,9 +2572,9 @@ std::string cmGeneratorTarget::GetEffectiveFolderName() const return effectiveFolder; } - const char* targetFolder = this->GetProperty("FOLDER"); + cmProp targetFolder = this->GetProperty("FOLDER"); if (targetFolder) { - effectiveFolder += targetFolder; + effectiveFolder += *targetFolder; } return effectiveFolder; @@ -2529,7 +2651,8 @@ void cmGeneratorTarget::ComputeModuleDefinitionInfo( info.DefFileGenerated = false; #endif if (info.DefFileGenerated) { - info.DefFile = this->ObjectDirectory /* has slash */ + "exports.def"; + info.DefFile = + this->GetObjectDirectory(config) /* has slash */ + "exports.def"; } else if (!info.Sources.empty()) { info.DefFile = info.Sources.front()->GetFullPath(); } @@ -2643,7 +2766,7 @@ cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target) for (cmSourceFile* sf : sources) { const std::set<cmGeneratorTarget const*> tgts = this->GlobalGenerator->GetFilenameTargetDepends(sf); - if (cmContains(tgts, this->GeneratorTarget)) { + if (cm::contains(tgts, this->GeneratorTarget)) { std::ostringstream e; e << "Evaluation output file\n \"" << sf->ResolveFullPath() << "\"\ndepends on the sources of a target it is used in. This " @@ -2676,8 +2799,8 @@ void cmTargetTraceDependencies::Trace() this->CurrentEntry = &this->GeneratorTarget->SourceDepends[sf]; // Queue dependencies added explicitly by the user. - if (const char* additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) { - std::vector<std::string> objDeps = cmExpandedList(additionalDeps); + if (cmProp additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) { + std::vector<std::string> objDeps = cmExpandedList(*additionalDeps); for (std::string& objDep : objDeps) { if (cmSystemTools::FileIsFullPath(objDep)) { objDep = cmSystemTools::CollapseFullPath(objDep); @@ -2908,7 +3031,7 @@ std::string cmGeneratorTarget::GetCompilePDBDirectory( void cmGeneratorTarget::GetAppleArchs(const std::string& config, std::vector<std::string>& archVec) const { - const char* archs = nullptr; + cmProp archs = nullptr; if (!config.empty()) { std::string defVarName = cmStrCat("OSX_ARCHITECTURES_", cmSystemTools::UpperCase(config)); @@ -2918,7 +3041,110 @@ void cmGeneratorTarget::GetAppleArchs(const std::string& config, archs = this->GetProperty("OSX_ARCHITECTURES"); } if (archs) { - cmExpandList(std::string(archs), archVec); + cmExpandList(*archs, archVec); + } +} + +void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const +{ + struct CudaArchitecture + { + std::string name; + bool real{ true }; + bool virtual_{ true }; + }; + std::vector<CudaArchitecture> architectures; + + { + std::vector<std::string> options; + cmExpandList(this->GetSafeProperty("CUDA_ARCHITECTURES"), options); + + if (options.empty()) { + switch (this->GetPolicyStatusCMP0104()) { + case cmPolicies::WARN: + if (!this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile()) { + this->Makefile->IssueMessage( + MessageType::AUTHOR_WARNING, + cmPolicies::GetPolicyWarning(cmPolicies::CMP0104) + + "\nCUDA_ARCHITECTURES is empty for target \"" + + this->GetName() + "\"."); + } + CM_FALLTHROUGH; + case cmPolicies::OLD: + break; + default: + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "CUDA_ARCHITECTURES is empty for target \"" + this->GetName() + + "\"."); + } + } + + for (std::string& option : options) { + CudaArchitecture architecture; + + // Architecture name is up to the first specifier. + std::size_t pos = option.find_first_of('-'); + architecture.name = option.substr(0, pos); + + if (pos != std::string::npos) { + cm::string_view specifier{ option.c_str() + pos + 1, + option.length() - pos - 1 }; + + if (specifier == "real") { + architecture.real = true; + architecture.virtual_ = false; + } else if (specifier == "virtual") { + architecture.real = false; + architecture.virtual_ = true; + } else { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "Uknown CUDA architecture specifier \"" + std::string(specifier) + + "\"."); + } + } + + architectures.emplace_back(architecture); + } + } + + std::string const& compiler = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID"); + + if (compiler == "NVIDIA") { + for (CudaArchitecture& architecture : architectures) { + flags += + " --generate-code=arch=compute_" + architecture.name + ",code=["; + + if (architecture.virtual_) { + flags += "compute_" + architecture.name; + + if (architecture.real) { + flags += ","; + } + } + + if (architecture.real) { + flags += "sm_" + architecture.name; + } + + flags += "]"; + } + } else if (compiler == "Clang") { + for (CudaArchitecture& architecture : architectures) { + flags += " --cuda-gpu-arch=sm_" + architecture.name; + + if (!architecture.real) { + Makefile->IssueMessage( + MessageType::WARNING, + "Clang doesn't support disabling CUDA real code generation."); + } + + if (!architecture.virtual_) { + flags += " --no-cuda-include-ptx=sm_" + architecture.name; + } + } } } @@ -2966,13 +3192,13 @@ std::string cmGeneratorTarget::GetCreateRuleVariable( } namespace { -void processIncludeDirectories( - cmGeneratorTarget const* tgt, - std::vector<EvaluatedTargetPropertyEntry>& entries, - std::vector<BT<std::string>>& includes, - std::unordered_set<std::string>& uniqueIncludes, bool debugIncludes) +void processIncludeDirectories(cmGeneratorTarget const* tgt, + EvaluatedTargetPropertyEntries& entries, + std::vector<BT<std::string>>& includes, + std::unordered_set<std::string>& uniqueIncludes, + bool debugIncludes) { - for (EvaluatedTargetPropertyEntry& entry : entries) { + for (EvaluatedTargetPropertyEntry& entry : entries.Entries) { cmLinkImplItem const& item = entry.LinkImplItem; std::string const& targetName = item.AsStr(); bool const fromImported = item.Target && item.Target->IsImported(); @@ -3087,15 +3313,18 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( } bool debugIncludes = !this->DebugIncludesDone && - cmContains(debugProperties, "INCLUDE_DIRECTORIES"); + cm::contains(debugProperties, "INCLUDE_DIRECTORIES"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugIncludesDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, lang, &dagChecker, - this->IncludeDirectoriesEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, lang, &dagChecker, this->IncludeDirectoriesEntries); + + if (lang == "Swift") { + AddSwiftImplicitIncludeDirectories(this, config, entries); + } AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang, &dagChecker, entries); @@ -3117,7 +3346,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( EvaluatedTargetPropertyEntry ee(lib, cmListFileBacktrace()); ee.Values.emplace_back(std::move(libDir)); - entries.emplace_back(std::move(ee)); + entries.Entries.emplace_back(std::move(ee)); } } @@ -3134,22 +3363,38 @@ enum class OptionsParse }; namespace { +const auto DL_BEGIN = "<DEVICE_LINK>"_s; +const auto DL_END = "</DEVICE_LINK>"_s; + void processOptions(cmGeneratorTarget const* tgt, - std::vector<EvaluatedTargetPropertyEntry> const& entries, + EvaluatedTargetPropertyEntries const& entries, std::vector<BT<std::string>>& options, std::unordered_set<std::string>& uniqueOptions, - bool debugOptions, const char* logName, OptionsParse parse) + bool debugOptions, const char* logName, OptionsParse parse, + bool processDeviceOptions = false) { - for (EvaluatedTargetPropertyEntry const& entry : entries) { + bool splitOption = !processDeviceOptions; + for (EvaluatedTargetPropertyEntry const& entry : entries.Entries) { std::string usedOptions; for (std::string const& opt : entry.Values) { + if (processDeviceOptions && (opt == DL_BEGIN || opt == DL_END)) { + options.emplace_back(opt, entry.Backtrace); + splitOption = opt == DL_BEGIN; + continue; + } + if (uniqueOptions.insert(opt).second) { if (parse == OptionsParse::Shell && cmHasLiteralPrefix(opt, "SHELL:")) { - std::vector<std::string> tmp; - cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp); - for (std::string& o : tmp) { - options.emplace_back(std::move(o), entry.Backtrace); + if (splitOption) { + std::vector<std::string> tmp; + cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp); + for (std::string& o : tmp) { + options.emplace_back(std::move(o), entry.Backtrace); + } + } else { + options.emplace_back(std::string(opt.c_str() + 6), + entry.Backtrace); } } else { options.emplace_back(opt, entry.Backtrace); @@ -3168,6 +3413,63 @@ void processOptions(cmGeneratorTarget const* tgt, } } } + +std::vector<BT<std::string>> wrapOptions( + std::vector<std::string>& options, const cmListFileBacktrace& bt, + const std::vector<std::string>& wrapperFlag, const std::string& wrapperSep, + bool concatFlagAndArgs) +{ + std::vector<BT<std::string>> result; + + if (options.empty()) { + return result; + } + + if (wrapperFlag.empty() || cmHasLiteralPrefix(options.front(), "LINKER:")) { + // nothing specified or LINKER wrapper, insert elements as is + result.reserve(options.size()); + for (std::string& o : options) { + result.emplace_back(std::move(o), bt); + } + } else { + if (!wrapperSep.empty()) { + if (concatFlagAndArgs) { + // insert flag elements except last one + for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) { + result.emplace_back(*i, bt); + } + // concatenate last flag element and all list values + // in one option + result.emplace_back(wrapperFlag.back() + cmJoin(options, wrapperSep), + bt); + } else { + for (std::string const& i : wrapperFlag) { + result.emplace_back(i, bt); + } + // concatenate all list values in one option + result.emplace_back(cmJoin(options, wrapperSep), bt); + } + } else { + // prefix each element of list with wrapper + if (concatFlagAndArgs) { + std::transform(options.begin(), options.end(), options.begin(), + [&wrapperFlag](std::string const& o) -> std::string { + return wrapperFlag.back() + o; + }); + } + for (std::string& o : options) { + for (auto i = wrapperFlag.begin(), + e = concatFlagAndArgs ? wrapperFlag.end() - 1 + : wrapperFlag.end(); + i != e; ++i) { + result.emplace_back(*i, bt); + } + result.emplace_back(std::move(o), bt); + } + } + } + return result; +} } void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result, @@ -3198,15 +3500,14 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions( } bool debugOptions = !this->DebugCompileOptionsDone && - cmContains(debugProperties, "COMPILE_OPTIONS"); + cm::contains(debugProperties, "COMPILE_OPTIONS"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugCompileOptionsDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, language, &dagChecker, - this->CompileOptionsEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, language, &dagChecker, this->CompileOptionsEntries); AddInterfaceEntries(this, config, "INTERFACE_COMPILE_OPTIONS", language, &dagChecker, entries); @@ -3244,15 +3545,14 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures( } bool debugFeatures = !this->DebugCompileFeaturesDone && - cmContains(debugProperties, "COMPILE_FEATURES"); + cm::contains(debugProperties, "COMPILE_FEATURES"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugCompileFeaturesDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, std::string(), &dagChecker, - this->CompileFeaturesEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, std::string(), &dagChecker, this->CompileFeaturesEntries); AddInterfaceEntries(this, config, "INTERFACE_COMPILE_FEATURES", std::string(), &dagChecker, entries); @@ -3292,15 +3592,14 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( } bool debugDefines = !this->DebugCompileDefinitionsDone && - cmContains(debugProperties, "COMPILE_DEFINITIONS"); + cm::contains(debugProperties, "COMPILE_DEFINITIONS"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugCompileDefinitionsDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, language, &dagChecker, - this->CompileDefinitionsEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, language, &dagChecker, this->CompileDefinitionsEntries); AddInterfaceEntries(this, config, "INTERFACE_COMPILE_DEFINITIONS", language, &dagChecker, entries); @@ -3308,7 +3607,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( if (!config.empty()) { std::string configPropName = "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - const char* configProp = this->GetProperty(configPropName); + cmProp configProp = this->GetProperty(configPropName); if (configProp) { switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0043)) { case cmPolicies::WARN: { @@ -3319,8 +3618,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( } case cmPolicies::OLD: { std::unique_ptr<TargetPropertyEntry> entry = - CreateTargetPropertyEntry(configProp); - entries.emplace_back(EvaluateTargetPropertyEntry( + CreateTargetPropertyEntry(*configProp); + entries.Entries.emplace_back(EvaluateTargetPropertyEntry( this, config, language, &dagChecker, *entry)); } break; case cmPolicies::NEW: @@ -3360,9 +3659,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( this->DebugPrecompileHeadersDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, language, &dagChecker, - this->PrecompileHeadersEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, language, &dagChecker, this->PrecompileHeadersEntries); AddInterfaceEntries(this, config, "INTERFACE_PRECOMPILE_HEADERS", language, &dagChecker, entries); @@ -3375,7 +3673,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( } std::string cmGeneratorTarget::GetPchHeader(const std::string& config, - const std::string& language) const + const std::string& language, + const std::string& arch) const { if (language != "C" && language != "CXX" && language != "OBJC" && language != "OBJCXX") { @@ -3386,11 +3685,11 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, return std::string(); } const cmGeneratorTarget* generatorTarget = this; - const char* pchReuseFrom = + cmProp pchReuseFrom = generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); const auto inserted = - this->PchHeaders.insert(std::make_pair(language + config, "")); + this->PchHeaders.insert(std::make_pair(language + config + arch, "")); if (inserted.second) { const std::vector<BT<std::string>> headers = this->GetPrecompileHeaders(config, language); @@ -3401,7 +3700,7 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, if (pchReuseFrom) { generatorTarget = - this->GetGlobalGenerator()->FindGeneratorTarget(pchReuseFrom); + this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom); } filename = cmStrCat( @@ -3422,7 +3721,8 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, } filename = - cmStrCat(filename, "/cmake_pch", languageToExtension.at(language)); + cmStrCat(filename, "/cmake_pch", arch.empty() ? "" : cmStrCat("_", arch), + languageToExtension.at(language)); const std::string filename_tmp = cmStrCat(filename, ".tmp"); if (!pchReuseFrom) { @@ -3481,27 +3781,28 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, } std::string cmGeneratorTarget::GetPchSource(const std::string& config, - const std::string& language) const + const std::string& language, + const std::string& arch) const { if (language != "C" && language != "CXX" && language != "OBJC" && language != "OBJCXX") { return std::string(); } const auto inserted = - this->PchSources.insert(std::make_pair(language + config, "")); + this->PchSources.insert(std::make_pair(language + config + arch, "")); if (inserted.second) { - const std::string pchHeader = this->GetPchHeader(config, language); + const std::string pchHeader = this->GetPchHeader(config, language, arch); if (pchHeader.empty()) { return std::string(); } std::string& filename = inserted.first->second; const cmGeneratorTarget* generatorTarget = this; - const char* pchReuseFrom = + cmProp pchReuseFrom = generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); if (pchReuseFrom) { generatorTarget = - this->GetGlobalGenerator()->FindGeneratorTarget(pchReuseFrom); + this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom); } filename = @@ -3517,13 +3818,15 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config, { "OBJCXX", ".objcxx.hxx.mm" } }; - filename += languageToExtension.at(language); + filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch), + languageToExtension.at(language)); } else { const std::map<std::string, std::string> languageToExtension = { { "C", ".c" }, { "CXX", ".cxx" }, { "OBJC", ".m" }, { "OBJCXX", ".mm" } }; - filename += languageToExtension.at(language); + filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch), + languageToExtension.at(language)); } const std::string filename_tmp = cmStrCat(filename, ".tmp"); @@ -3540,16 +3843,17 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config, } std::string cmGeneratorTarget::GetPchFileObject(const std::string& config, - const std::string& language) + const std::string& language, + const std::string& arch) { if (language != "C" && language != "CXX" && language != "OBJC" && language != "OBJCXX") { return std::string(); } const auto inserted = - this->PchObjectFiles.insert(std::make_pair(language + config, "")); + this->PchObjectFiles.insert(std::make_pair(language + config + arch, "")); if (inserted.second) { - const std::string pchSource = this->GetPchSource(config, language); + const std::string pchSource = this->GetPchSource(config, language, arch); if (pchSource.empty()) { return std::string(); } @@ -3559,15 +3863,20 @@ std::string cmGeneratorTarget::GetPchFileObject(const std::string& config, pchSource, false, cmSourceFileLocationKind::Known); filename = cmStrCat(this->ObjectDirectory, this->GetObjectName(pchSf)); + if (this->GetGlobalGenerator()->IsMultiConfig()) { + cmSystemTools::ReplaceString( + filename, this->GetGlobalGenerator()->GetCMakeCFGIntDir(), config); + } } return inserted.first->second; } std::string cmGeneratorTarget::GetPchFile(const std::string& config, - const std::string& language) + const std::string& language, + const std::string& arch) { const auto inserted = - this->PchFiles.insert(std::make_pair(language + config, "")); + this->PchFiles.insert(std::make_pair(language + config + arch, "")); if (inserted.second) { std::string& pchFile = inserted.first->second; @@ -3587,20 +3896,20 @@ std::string cmGeneratorTarget::GetPchFile(const std::string& config, }; cmGeneratorTarget* generatorTarget = this; - const char* pchReuseFrom = + cmProp pchReuseFrom = generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); if (pchReuseFrom) { generatorTarget = - this->GetGlobalGenerator()->FindGeneratorTarget(pchReuseFrom); + this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom); } const std::string pchFileObject = - generatorTarget->GetPchFileObject(config, language); + generatorTarget->GetPchFileObject(config, language, arch); if (!pchExtension.empty()) { pchFile = replaceExtension(pchFileObject, pchExtension); } } else { - pchFile = this->GetPchHeader(config, language); + pchFile = this->GetPchHeader(config, language, arch); pchFile += pchExtension; } } @@ -3608,19 +3917,27 @@ std::string cmGeneratorTarget::GetPchFile(const std::string& config, } std::string cmGeneratorTarget::GetPchCreateCompileOptions( - const std::string& config, const std::string& language) + const std::string& config, const std::string& language, + const std::string& arch) { const auto inserted = this->PchCreateCompileOptions.insert( - std::make_pair(language + config, "")); + std::make_pair(language + config + arch, "")); if (inserted.second) { std::string& createOptionList = inserted.first->second; + if (this->GetPropertyAsBool("PCH_WARN_INVALID")) { + createOptionList = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH")); + } + const std::string createOptVar = cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_CREATE_PCH"); - createOptionList = this->Makefile->GetSafeDefinition(createOptVar); - const std::string pchHeader = this->GetPchHeader(config, language); - const std::string pchFile = this->GetPchFile(config, language); + createOptionList = cmStrCat( + createOptionList, ";", this->Makefile->GetSafeDefinition(createOptVar)); + + const std::string pchHeader = this->GetPchHeader(config, language, arch); + const std::string pchFile = this->GetPchFile(config, language, arch); cmSystemTools::ReplaceString(createOptionList, "<PCH_HEADER>", pchHeader); cmSystemTools::ReplaceString(createOptionList, "<PCH_FILE>", pchFile); @@ -3629,19 +3946,33 @@ std::string cmGeneratorTarget::GetPchCreateCompileOptions( } std::string cmGeneratorTarget::GetPchUseCompileOptions( - const std::string& config, const std::string& language) + const std::string& config, const std::string& language, + const std::string& arch) { - const auto inserted = - this->PchUseCompileOptions.insert(std::make_pair(language + config, "")); + const auto inserted = this->PchUseCompileOptions.insert( + std::make_pair(language + config + arch, "")); if (inserted.second) { std::string& useOptionList = inserted.first->second; + if (this->GetPropertyAsBool("PCH_WARN_INVALID")) { + useOptionList = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH")); + } + const std::string useOptVar = - cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_USE_PCH"); - useOptionList = this->Makefile->GetSafeDefinition(useOptVar); + cmStrCat(language, "_COMPILE_OPTIONS_USE_PCH"); + + std::string const& useOptionListProperty = + this->GetSafeProperty(useOptVar); - const std::string pchHeader = this->GetPchHeader(config, language); - const std::string pchFile = this->GetPchFile(config, language); + useOptionList = cmStrCat( + useOptionList, ";", + useOptionListProperty.empty() + ? this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", useOptVar)) + : useOptionListProperty); + + const std::string pchHeader = this->GetPchHeader(config, language, arch); + const std::string pchFile = this->GetPchFile(config, language, arch); cmSystemTools::ReplaceString(useOptionList, "<PCH_HEADER>", pchHeader); cmSystemTools::ReplaceString(useOptionList, "<PCH_FILE>", pchFile); @@ -3670,6 +4001,12 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result, const std::string& config, const std::string& language) const { + if (this->IsDeviceLink() && + this->GetPolicyStatusCMP0105() != cmPolicies::NEW) { + // link options are not propagated to the device link step + return; + } + std::vector<BT<std::string>> tmp = this->GetLinkOptions(config, language); result.reserve(tmp.size()); for (BT<std::string>& v : tmp) { @@ -3693,31 +4030,80 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( cmExpandList(debugProp, debugProperties); } - bool debugOptions = - !this->DebugLinkOptionsDone && cmContains(debugProperties, "LINK_OPTIONS"); + bool debugOptions = !this->DebugLinkOptionsDone && + cm::contains(debugProperties, "LINK_OPTIONS"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugLinkOptionsDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, language, &dagChecker, - this->LinkOptionsEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, language, &dagChecker, this->LinkOptionsEntries); AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language, &dagChecker, entries, this->GetPolicyStatusCMP0099() != cmPolicies::NEW); processOptions(this, entries, result, uniqueOptions, debugOptions, - "link options", OptionsParse::Shell); + "link options", OptionsParse::Shell, this->IsDeviceLink()); + + if (this->IsDeviceLink()) { + // wrap host link options + const std::string wrapper(this->Makefile->GetSafeDefinition( + "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG")); + std::vector<std::string> wrapperFlag = cmExpandedList(wrapper); + const std::string wrapperSep(this->Makefile->GetSafeDefinition( + "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP")); + bool concatFlagAndArgs = true; + if (!wrapperFlag.empty() && wrapperFlag.back() == " ") { + concatFlagAndArgs = false; + wrapperFlag.pop_back(); + } + + auto it = result.begin(); + while (it != result.end()) { + if (it->Value == DL_BEGIN) { + // device link options, no treatment + it = result.erase(it); + it = std::find_if(it, result.end(), [](const BT<std::string>& item) { + return item.Value == DL_END; + }); + if (it != result.end()) { + it = result.erase(it); + } + } else { + // host link options must be wrapped + std::vector<std::string> options; + cmSystemTools::ParseUnixCommandLine(it->Value.c_str(), options); + auto hostOptions = wrapOptions(options, it->Backtrace, wrapperFlag, + wrapperSep, concatFlagAndArgs); + it = result.erase(it); + // some compilers (like gcc 4.8 or Intel 19.0 or XLC 16) do not respect + // C++11 standard: 'std::vector::insert()' do not returns an iterator, + // so need to recompute the iterator after insertion. + if (it == result.end()) { + cm::append(result, hostOptions); + it = result.end(); + } else { + auto index = it - result.begin(); + result.insert(it, hostOptions.begin(), hostOptions.end()); + it = result.begin() + index + hostOptions.size(); + } + } + } + } // Last step: replace "LINKER:" prefixed elements by // actual linker wrapper const std::string wrapper(this->Makefile->GetSafeDefinition( - "CMAKE_" + language + "_LINKER_WRAPPER_FLAG")); + "CMAKE_" + language + + (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG" + : "_LINKER_WRAPPER_FLAG"))); std::vector<std::string> wrapperFlag = cmExpandedList(wrapper); const std::string wrapperSep(this->Makefile->GetSafeDefinition( - "CMAKE_" + language + "_LINKER_WRAPPER_FLAG_SEP")); + "CMAKE_" + language + + (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP" + : "_LINKER_WRAPPER_FLAG_SEP"))); bool concatFlagAndArgs = true; if (!wrapperFlag.empty() && wrapperFlag.back() == " ") { concatFlagAndArgs = false; @@ -3763,51 +4149,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( return result; } - std::vector<BT<std::string>> options; - if (wrapperFlag.empty()) { - // nothing specified, insert elements as is - options.reserve(linkerOptions.size()); - for (std::string& o : linkerOptions) { - options.emplace_back(std::move(o), bt); - } - } else { - if (!wrapperSep.empty()) { - if (concatFlagAndArgs) { - // insert flag elements except last one - for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) { - options.emplace_back(*i, bt); - } - // concatenate last flag element and all LINKER list values - // in one option - options.emplace_back( - wrapperFlag.back() + cmJoin(linkerOptions, wrapperSep), bt); - } else { - for (std::string const& i : wrapperFlag) { - options.emplace_back(i, bt); - } - // concatenate all LINKER list values in one option - options.emplace_back(cmJoin(linkerOptions, wrapperSep), bt); - } - } else { - // prefix each element of LINKER list with wrapper - if (concatFlagAndArgs) { - std::transform(linkerOptions.begin(), linkerOptions.end(), - linkerOptions.begin(), - [&wrapperFlag](std::string const& o) -> std::string { - return wrapperFlag.back() + o; - }); - } - for (std::string& o : linkerOptions) { - for (auto i = wrapperFlag.begin(), - e = concatFlagAndArgs ? wrapperFlag.end() - 1 - : wrapperFlag.end(); - i != e; ++i) { - options.emplace_back(*i, bt); - } - options.emplace_back(std::move(o), bt); - } - } - } + std::vector<BT<std::string>> options = wrapOptions( + linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs); result.insert(entry, options.begin(), options.end()); } return result; @@ -3834,14 +4177,14 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS", nullptr, nullptr); - std::vector<EvaluatedTargetPropertyEntry> entries; - if (const char* linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) { - std::vector<std::string> options = cmExpandedList(linkOptions); + EvaluatedTargetPropertyEntries entries; + if (cmProp linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) { + std::vector<std::string> options = cmExpandedList(*linkOptions); for (const auto& option : options) { std::unique_ptr<TargetPropertyEntry> entry = CreateTargetPropertyEntry(option); - entries.emplace_back(EvaluateTargetPropertyEntry(this, config, language, - &dagChecker, *entry)); + entries.Entries.emplace_back(EvaluateTargetPropertyEntry( + this, config, language, &dagChecker, *entry)); } } processOptions(this, entries, result, uniqueOptions, false, @@ -3852,12 +4195,12 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( namespace { void processLinkDirectories(cmGeneratorTarget const* tgt, - std::vector<EvaluatedTargetPropertyEntry>& entries, + EvaluatedTargetPropertyEntries& entries, std::vector<BT<std::string>>& directories, std::unordered_set<std::string>& uniqueDirectories, bool debugDirectories) { - for (EvaluatedTargetPropertyEntry& entry : entries) { + for (EvaluatedTargetPropertyEntry& entry : entries.Entries) { cmLinkImplItem const& item = entry.LinkImplItem; std::string const& targetName = item.AsStr(); @@ -3950,15 +4293,14 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( } bool debugDirectories = !this->DebugLinkDirectoriesDone && - cmContains(debugProperties, "LINK_DIRECTORIES"); + cm::contains(debugProperties, "LINK_DIRECTORIES"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugLinkDirectoriesDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, language, &dagChecker, - this->LinkDirectoriesEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, language, &dagChecker, this->LinkDirectoriesEntries); AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language, &dagChecker, entries, @@ -3989,14 +4331,14 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr, nullptr); - std::vector<EvaluatedTargetPropertyEntry> entries; - if (const char* linkDepends = this->GetProperty("LINK_DEPENDS")) { - std::vector<std::string> depends = cmExpandedList(linkDepends); + EvaluatedTargetPropertyEntries entries; + if (cmProp linkDepends = this->GetProperty("LINK_DEPENDS")) { + std::vector<std::string> depends = cmExpandedList(*linkDepends); for (const auto& depend : depends) { std::unique_ptr<TargetPropertyEntry> entry = CreateTargetPropertyEntry(depend); - entries.emplace_back(EvaluateTargetPropertyEntry(this, config, language, - &dagChecker, *entry)); + entries.Entries.emplace_back(EvaluateTargetPropertyEntry( + this, config, language, &dagChecker, *entry)); } } AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language, @@ -4151,8 +4493,8 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames( } // Check for library version properties. - const char* version = this->GetProperty("VERSION"); - const char* soversion = this->GetProperty("SOVERSION"); + cmProp version = this->GetProperty("VERSION"); + cmProp soversion = this->GetProperty("SOVERSION"); if (!this->HasSOName(config) || this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") || this->IsFrameworkOnApple()) { @@ -4187,17 +4529,18 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames( targetNames.Real += this->GetFrameworkVersion(); targetNames.Real += "/"; } - targetNames.Real += targetNames.Base; - targetNames.SharedObject = targetNames.Real; + targetNames.Real += targetNames.Base + suffix; + targetNames.SharedObject = targetNames.Real + suffix; } else { // The library's soname. this->ComputeVersionedName(targetNames.SharedObject, prefix, targetNames.Base, suffix, targetNames.Output, - soversion); + (soversion ? soversion->c_str() : nullptr)); // The library's real name on disk. this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base, - suffix, targetNames.Output, version); + suffix, targetNames.Output, + (version ? version->c_str() : nullptr)); } // The import library name. @@ -4230,10 +4573,13 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames( // This versioning is supported only for executables and then only // when the platform supports symbolic links. #if defined(_WIN32) && !defined(__CYGWIN__) - const char* version = 0; + const char* version = nullptr; #else // Check for executable version properties. - const char* version = this->GetProperty("VERSION"); + const char* version = nullptr; + if (cmProp p = this->GetProperty("VERSION")) { + version = p->c_str(); + } if (this->GetType() != cmStateEnums::EXECUTABLE || this->Makefile->IsOn("XCODE")) { version = nullptr; @@ -4363,15 +4709,23 @@ void cmGeneratorTarget::GetFullNameInternal( outBase += this->GetOutputName(config, artifact); // Append the per-configuration postfix. - outBase += configPostfix; + // When using Xcode, the postfix should be part of the suffix rather than + // the base, because the suffix ends up being used in Xcode's + // EXECUTABLE_SUFFIX attribute. + if (this->IsFrameworkOnApple() && + GetGlobalGenerator()->GetName() == "Xcode") { + targetSuffix = configPostfix.c_str(); + } else { + outBase += configPostfix; + } // Name shared libraries with their version number on some platforms. - if (const char* soversion = this->GetProperty("SOVERSION")) { + if (cmProp soversion = this->GetProperty("SOVERSION")) { if (this->GetType() == cmStateEnums::SHARED_LIBRARY && !isImportedLibraryArtifact && this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) { outBase += "-"; - outBase += soversion; + outBase += *soversion; } } @@ -4402,8 +4756,8 @@ std::string cmGeneratorTarget::GetPDBOutputName( props.emplace_back("PDB_NAME"); for (std::string const& p : props) { - if (const char* outName = this->GetProperty(p)) { - base = outName; + if (cmProp outName = this->GetProperty(p)) { + base = *outName; break; } } @@ -4429,8 +4783,8 @@ std::string cmGeneratorTarget::GetPDBName(const std::string& config) const props.emplace_back("PDB_NAME"); for (std::string const& p : props) { - if (const char* outName = this->GetProperty(p)) { - base = outName; + if (cmProp outName = this->GetProperty(p)) { + base = *outName; break; } } @@ -4502,16 +4856,16 @@ cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const } else { // Handle the MACOSX_PACKAGE_LOCATION property on source files that // were not listed in one of the other lists. - if (const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) { - flags.MacFolder = location; + if (cmProp location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) { + flags.MacFolder = location->c_str(); const bool stripResources = this->GlobalGenerator->ShouldStripResourcePath(this->Makefile); - if (strcmp(location, "Resources") == 0) { + if (*location == "Resources") { flags.Type = cmGeneratorTarget::SourceFileTypeResource; if (stripResources) { flags.MacFolder = ""; } - } else if (cmHasLiteralPrefix(location, "Resources/")) { + } else if (cmHasLiteralPrefix(*location, "Resources/")) { flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource; if (stripResources) { flags.MacFolder += strlen("Resources/"); @@ -4532,8 +4886,8 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const this->SourceFileFlagsConstructed = true; // Process public headers to mark the source files. - if (const char* files = this->GetProperty("PUBLIC_HEADER")) { - std::vector<std::string> relFiles = cmExpandedList(files); + if (cmProp files = this->GetProperty("PUBLIC_HEADER")) { + std::vector<std::string> relFiles = cmExpandedList(*files); for (std::string const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { SourceFileFlags& flags = this->SourceFlagsMap[sf]; @@ -4545,8 +4899,8 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const // Process private headers after public headers so that they take // precedence if a file is listed in both. - if (const char* files = this->GetProperty("PRIVATE_HEADER")) { - std::vector<std::string> relFiles = cmExpandedList(files); + if (cmProp files = this->GetProperty("PRIVATE_HEADER")) { + std::vector<std::string> relFiles = cmExpandedList(*files); for (std::string const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { SourceFileFlags& flags = this->SourceFlagsMap[sf]; @@ -4557,8 +4911,8 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const } // Mark sources listed as resources. - if (const char* files = this->GetProperty("RESOURCE")) { - std::vector<std::string> relFiles = cmExpandedList(files); + if (cmProp files = this->GetProperty("RESOURCE")) { + std::vector<std::string> relFiles = cmExpandedList(*files); for (std::string const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { SourceFileFlags& flags = this->SourceFlagsMap[sf]; @@ -4585,9 +4939,9 @@ cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const this->GetLinkImplementationClosure(config); for (cmGeneratorTarget const* li : deps) { #define CM_READ_COMPATIBLE_INTERFACE(X, x) \ - if (const char* prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \ + if (cmProp prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \ std::vector<std::string> props; \ - cmExpandList(prop, props); \ + cmExpandList(*prop, props); \ compat.Props##x.insert(props.begin(), props.end()); \ } CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool) @@ -4695,12 +5049,12 @@ void checkPropertyConsistency(cmGeneratorTarget const* depender, const std::string& config, CompatibleType t, PropertyType* /*unused*/) { - const char* prop = dependee->GetProperty(propName); + cmProp prop = dependee->GetProperty(propName); if (!prop) { return; } - std::vector<std::string> props = cmExpandedList(prop); + std::vector<std::string> props = cmExpandedList(*prop); std::string pdir = cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/"); @@ -4854,7 +5208,8 @@ void cmGeneratorTarget::CheckPropertyCompatibility( std::ostringstream e; e << "Property \"" << prop << "\" appears in both the " << propsString << " property in the dependencies of target \"" << this->GetName() - << "\". This is not allowed. A property may only require compatibility " + << "\". This is not allowed. A property may only require " + "compatibility " "in a boolean interpretation, a numeric minimum, a numeric maximum " "or a " "string interpretation, but not a mixture."; @@ -4929,8 +5284,9 @@ bool getTypedProperty<bool>(cmGeneratorTarget const* tgt, return tgt->GetPropertyAsBool(prop); } - const char* value = tgt->GetProperty(prop); - return cmIsOn(genexInterpreter->Evaluate(value, prop)); + cmProp value = tgt->GetProperty(prop); + return cmIsOn( + genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop)); } template <> @@ -4938,13 +5294,14 @@ const char* getTypedProperty<const char*>( cmGeneratorTarget const* tgt, const std::string& prop, cmGeneratorExpressionInterpreter* genexInterpreter) { - const char* value = tgt->GetProperty(prop); + cmProp value = tgt->GetProperty(prop); if (genexInterpreter == nullptr) { - return value; + return value ? value->c_str() : nullptr; } - return genexInterpreter->Evaluate(value, prop).c_str(); + return genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop) + .c_str(); } template <> @@ -4952,13 +5309,13 @@ std::string getTypedProperty<std::string>( cmGeneratorTarget const* tgt, const std::string& prop, cmGeneratorExpressionInterpreter* genexInterpreter) { - const char* value = tgt->GetProperty(prop); + cmProp value = tgt->GetProperty(prop); if (genexInterpreter == nullptr) { - return valueAsString(value); + return valueAsString(value ? value->c_str() : nullptr); } - return genexInterpreter->Evaluate(value, prop); + return genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop); } template <typename PropertyType> @@ -5103,7 +5460,7 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, PropertyType propContent = getTypedProperty<PropertyType>(tgt, p); std::vector<std::string> headPropKeys = tgt->GetPropertyKeys(); - const bool explicitlySet = cmContains(headPropKeys, p); + const bool explicitlySet = cm::contains(headPropKeys, p); const bool impliedByUse = tgt->IsNullImpliedByLinkLibraries(p); assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet)); @@ -5143,7 +5500,7 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, std::vector<std::string> propKeys = theTarget->GetPropertyKeys(); - const bool ifaceIsSet = cmContains(propKeys, interfaceProperty); + const bool ifaceIsSet = cm::contains(propKeys, interfaceProperty); PropertyType ifacePropContent = getTypedProperty<PropertyType>( theTarget, interfaceProperty, genexInterpreter.get()); @@ -5236,6 +5593,13 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, return propContent; } +bool cmGeneratorTarget::SetDeviceLink(bool deviceLink) +{ + bool previous = this->DeviceLink; + this->DeviceLink = deviceLink; + return previous; +} + bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty( const std::string& p, const std::string& config) const { @@ -5322,13 +5686,13 @@ void cmGeneratorTarget::GetTargetVersion(const std::string& property, assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY); - if (const char* version = this->GetProperty(property)) { + if (cmProp version = this->GetProperty(property)) { // Try to parse the version number and store the results that were // successfully parsed. int parsed_major; int parsed_minor; int parsed_patch; - switch (sscanf(version, "%d.%d.%d", &parsed_major, &parsed_minor, + switch (sscanf(version->c_str(), "%d.%d.%d", &parsed_major, &parsed_minor, &parsed_patch)) { case 3: patch = parsed_patch; @@ -5345,6 +5709,25 @@ void cmGeneratorTarget::GetTargetVersion(const std::string& property, } } +std::string cmGeneratorTarget::GetRuntimeLinkLibrary( + std::string const& lang, std::string const& config) const +{ + // This is activated by the presence of a default selection whether or + // not it is overridden by a property. + cmProp runtimeLibraryDefault = this->Makefile->GetDef( + cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT")); + if (!runtimeLibraryDefault || runtimeLibraryDefault->empty()) { + return std::string(); + } + cmProp runtimeLibraryValue = + this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY")); + if (!runtimeLibraryValue) { + runtimeLibraryValue = runtimeLibraryDefault; + } + return cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate( + *runtimeLibraryValue, this->LocalGenerator, config, this)); +} + std::string cmGeneratorTarget::GetFortranModuleDirectory( std::string const& working_dir) const { @@ -5362,8 +5745,8 @@ std::string cmGeneratorTarget::CreateFortranModuleDirectory( { std::string mod_dir; std::string target_mod_dir; - if (const char* prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) { - target_mod_dir = prop; + if (cmProp prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) { + target_mod_dir = *prop; } else { std::string const& default_mod_dir = this->LocalGenerator->GetCurrentBinaryDirectory(); @@ -5394,11 +5777,11 @@ std::string cmGeneratorTarget::GetFrameworkVersion() const { assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY); - if (const char* fversion = this->GetProperty("FRAMEWORK_VERSION")) { - return fversion; + if (cmProp fversion = this->GetProperty("FRAMEWORK_VERSION")) { + return *fversion; } - if (const char* tversion = this->GetProperty("VERSION")) { - return tversion; + if (cmProp tversion = this->GetProperty("VERSION")) { + return *tversion; } return "A"; } @@ -5434,8 +5817,8 @@ void cmGeneratorTarget::ReportPropertyOrigin( cmExpandList(debugProp, debugProperties); } - bool debugOrigin = - !this->DebugCompatiblePropertiesDone[p] && cmContains(debugProperties, p); + bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] && + cm::contains(debugProperties, p); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugCompatiblePropertiesDone[p] = true; @@ -5491,31 +5874,44 @@ void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names, void cmGeneratorTarget::ExpandLinkItems( std::string const& prop, std::string const& value, std::string const& config, cmGeneratorTarget const* headTarget, bool usage_requirements_only, - std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition) const + std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition, + bool& hadContextSensitiveCondition, + bool& hadLinkLanguageSensitiveCondition) const { // Keep this logic in sync with ComputeLinkImplementationLibraries. cmGeneratorExpression ge; cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr); - // The $<LINK_ONLY> expression may be in a link interface to specify private - // link dependencies that are otherwise excluded from usage requirements. + // The $<LINK_ONLY> expression may be in a link interface to specify + // private link dependencies that are otherwise excluded from usage + // requirements. if (usage_requirements_only) { dagChecker.SetTransitivePropertiesOnly(); } std::vector<std::string> libs; std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); - cmExpandList( - cge->Evaluate(this->LocalGenerator, config, headTarget, &dagChecker, this), - libs); + cmExpandList(cge->Evaluate(this->LocalGenerator, config, headTarget, + &dagChecker, this, headTarget->LinkerLanguage), + libs); this->LookupLinkItems(libs, cge->GetBacktrace(), items); hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition(); + hadContextSensitiveCondition = cge->GetHadContextSensitiveCondition(); + hadLinkLanguageSensitiveCondition = + cge->GetHadLinkLanguageSensitiveCondition(); } cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( const std::string& config, cmGeneratorTarget const* head) const { + return this->GetLinkInterface(config, head, false); +} + +cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( + const std::string& config, cmGeneratorTarget const* head, + bool secondPass) const +{ // Imported targets have their own link interface. if (this->IsImported()) { - return this->GetImportLinkInterface(config, head, false); + return this->GetImportLinkInterface(config, head, false, secondPass); } // Link interfaces are not supported for executables that do not @@ -5528,6 +5924,10 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( // Lookup any existing link interface for this configuration. cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config); + if (secondPass) { + hm.erase(head); + } + // If the link interface does not depend on the head target // then return the one we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { @@ -5542,7 +5942,7 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( if (!iface.AllDone) { iface.AllDone = true; if (iface.Exists) { - this->ComputeLinkInterface(config, iface, head); + this->ComputeLinkInterface(config, iface, head, secondPass); } } @@ -5553,6 +5953,13 @@ void cmGeneratorTarget::ComputeLinkInterface( const std::string& config, cmOptionalLinkInterface& iface, cmGeneratorTarget const* headTarget) const { + this->ComputeLinkInterface(config, iface, headTarget, false); +} + +void cmGeneratorTarget::ComputeLinkInterface( + const std::string& config, cmOptionalLinkInterface& iface, + cmGeneratorTarget const* headTarget, bool secondPass) const +{ if (iface.Explicit) { if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::STATIC_LIBRARY || @@ -5564,7 +5971,8 @@ void cmGeneratorTarget::ComputeLinkInterface( emitted.insert(lib); } if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - cmLinkImplementation const* impl = this->GetLinkImplementation(config); + cmLinkImplementation const* impl = + this->GetLinkImplementation(config, secondPass); for (cmLinkImplItem const& lib : impl->Libraries) { if (emitted.insert(lib).second) { if (lib.Target) { @@ -5574,9 +5982,9 @@ void cmGeneratorTarget::ComputeLinkInterface( } } else { // TODO: Recognize shared library file names. Perhaps this - // should be moved to cmComputeLinkInformation, but that creates - // a chicken-and-egg problem since this list is needed for its - // construction. + // should be moved to cmComputeLinkInformation, but that + // creates a chicken-and-egg problem since this list is needed + // for its construction. } } } @@ -5594,7 +6002,7 @@ void cmGeneratorTarget::ComputeLinkInterface( if (this->LinkLanguagePropagatesToDependents()) { // Targets using this archive need its language runtime libraries. if (cmLinkImplementation const* impl = - this->GetLinkImplementation(config)) { + this->GetLinkImplementation(config, secondPass)) { iface.Languages = impl->Languages; } } @@ -5611,11 +6019,11 @@ void cmGeneratorTarget::ComputeLinkInterface( // How many repetitions are needed if this library has cyclic // dependencies? std::string propName = cmStrCat("LINK_INTERFACE_MULTIPLICITY", suffix); - if (const char* config_reps = this->GetProperty(propName)) { - sscanf(config_reps, "%u", &iface.Multiplicity); - } else if (const char* reps = + if (cmProp config_reps = this->GetProperty(propName)) { + sscanf(config_reps->c_str(), "%u", &iface.Multiplicity); + } else if (cmProp reps = this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) { - sscanf(reps, "%u", &iface.Multiplicity); + sscanf(reps->c_str(), "%u", &iface.Multiplicity); } } } @@ -5637,7 +6045,6 @@ const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries( } // Lookup any existing link interface for this configuration. - std::string CONFIG = cmSystemTools::UpperCase(config); cmHeadToLinkInterfaceMap& hm = (usage_requirements_only ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) @@ -5766,21 +6173,21 @@ bool cmGeneratorTarget::ComputeOutputDir(const std::string& config, } // Select an output directory. - if (const char* config_outdir = this->GetProperty(configProp)) { + if (cmProp config_outdir = this->GetProperty(configProp)) { // Use the user-specified per-configuration output directory. - out = cmGeneratorExpression::Evaluate(config_outdir, this->LocalGenerator, + out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator, config); // Skip per-configuration subdirectory. conf.clear(); - } else if (const char* outdir = this->GetProperty(propertyName)) { + } else if (cmProp outdir = this->GetProperty(propertyName)) { // Use the user-specified output directory. out = - cmGeneratorExpression::Evaluate(outdir, this->LocalGenerator, config); + cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config); // Skip per-configuration subdirectory if the value contained a // generator expression. - if (out != outdir) { + if (out != *outdir) { conf.clear(); } } else if (this->GetType() == cmStateEnums::EXECUTABLE) { @@ -5842,21 +6249,21 @@ bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind, } // Select an output directory. - if (const char* config_outdir = this->GetProperty(configProp)) { + if (cmProp config_outdir = this->GetProperty(configProp)) { // Use the user-specified per-configuration output directory. - out = cmGeneratorExpression::Evaluate(config_outdir, this->LocalGenerator, + out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator, config); // Skip per-configuration subdirectory. conf.clear(); - } else if (const char* outdir = this->GetProperty(propertyName)) { + } else if (cmProp outdir = this->GetProperty(propertyName)) { // Use the user-specified output directory. out = - cmGeneratorExpression::Evaluate(outdir, this->LocalGenerator, config); + cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config); // Skip per-configuration subdirectory if the value contained a // generator expression. - if (out != outdir) { + if (out != *outdir) { conf.clear(); } } @@ -5902,12 +6309,13 @@ bool cmGeneratorTarget::GetRPATH(const std::string& config, const std::string& prop, std::string& rpath) const { - const char* value = this->GetProperty(prop); + cmProp value = this->GetProperty(prop); if (!value) { return false; } - rpath = cmGeneratorExpression::Evaluate(value, this->LocalGenerator, config); + rpath = + cmGeneratorExpression::Evaluate(*value, this->LocalGenerator, config); return true; } @@ -5926,7 +6334,7 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // An explicit list of interface libraries may be set for shared // libraries and executables that export symbols. - const char* explicitLibraries = nullptr; + cmProp explicitLibraries = nullptr; std::string linkIfaceProp; bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD && this->GetPolicyStatusCMP0022() != cmPolicies::WARN); @@ -5955,10 +6363,10 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( !this->PolicyWarnedCMP0022) { // Compare the explicitly set old link interface properties to the // preferred new link interface property one and warn if different. - const char* newExplicitLibraries = + cmProp newExplicitLibraries = this->GetProperty("INTERFACE_LINK_LIBRARIES"); if (newExplicitLibraries && - strcmp(newExplicitLibraries, explicitLibraries) != 0) { + (*newExplicitLibraries != *explicitLibraries)) { std::ostringstream w; /* clang-format off */ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n" @@ -5967,9 +6375,9 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( linkIfaceProp << " properties." "\n" "INTERFACE_LINK_LIBRARIES:\n" - " " << newExplicitLibraries << "\n" << + " " << *newExplicitLibraries << "\n" << linkIfaceProp << ":\n" - " " << explicitLibraries << "\n"; + " " << *explicitLibraries << "\n"; /* clang-format on */ this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING, w.str()); this->PolicyWarnedCMP0022 = true; @@ -5988,9 +6396,11 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( if (explicitLibraries) { // The interface libraries have been explicitly set. - this->ExpandLinkItems(linkIfaceProp, explicitLibraries, config, headTarget, - usage_requirements_only, iface.Libraries, - iface.HadHeadSensitiveCondition); + this->ExpandLinkItems(linkIfaceProp, *explicitLibraries, config, + headTarget, usage_requirements_only, iface.Libraries, + iface.HadHeadSensitiveCondition, + iface.HadContextSensitiveCondition, + iface.HadLinkLanguageSensitiveCondition); } else if (!cmp0022NEW) // If CMP0022 is NEW then the plain tll signature sets the // INTERFACE_LINK_LIBRARIES, so if we get here then the project @@ -6008,11 +6418,15 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // preferred new link interface property and warn if different. std::vector<cmLinkItem> ifaceLibs; static const std::string newProp = "INTERFACE_LINK_LIBRARIES"; - if (const char* newExplicitLibraries = this->GetProperty(newProp)) { + if (cmProp newExplicitLibraries = this->GetProperty(newProp)) { bool hadHeadSensitiveConditionDummy = false; - this->ExpandLinkItems(newProp, newExplicitLibraries, config, + bool hadContextSensitiveConditionDummy = false; + bool hadLinkLanguageSensitiveConditionDummy = false; + this->ExpandLinkItems(newProp, *newExplicitLibraries, config, headTarget, usage_requirements_only, ifaceLibs, - hadHeadSensitiveConditionDummy); + hadHeadSensitiveConditionDummy, + hadContextSensitiveConditionDummy, + hadLinkLanguageSensitiveConditionDummy); } if (ifaceLibs != iface.Libraries) { std::string oldLibraries = cmJoin(impl->Libraries, ";"); @@ -6049,19 +6463,22 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( const std::string& config, cmGeneratorTarget const* headTarget, - bool usage_requirements_only) const + bool usage_requirements_only, bool secondPass) const { cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config); if (!info) { return nullptr; } - std::string CONFIG = cmSystemTools::UpperCase(config); cmHeadToLinkInterfaceMap& hm = (usage_requirements_only ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) : this->GetHeadToLinkInterfaceMap(config)); + if (secondPass) { + hm.erase(headTarget); + } + // If the link interface does not depend on the head target // then return the one we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { @@ -6075,7 +6492,9 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( cmExpandList(info->Languages, iface.Languages); this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config, headTarget, usage_requirements_only, iface.Libraries, - iface.HadHeadSensitiveCondition); + iface.HadHeadSensitiveCondition, + iface.HadContextSensitiveCondition, + iface.HadLinkLanguageSensitiveCondition); std::vector<std::string> deps = cmExpandedList(info->SharedDeps); this->LookupLinkItems(deps, cmListFileBacktrace(), iface.SharedDeps); } @@ -6131,17 +6550,17 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, // Initialize members. info.NoSOName = false; - const char* loc = nullptr; - const char* imp = nullptr; + cmProp loc = nullptr; + cmProp imp = nullptr; std::string suffix; - if (!this->Target->GetMappedConfig(desired_config, &loc, &imp, suffix)) { + if (!this->Target->GetMappedConfig(desired_config, loc, imp, suffix)) { return; } // Get the link interface. { std::string linkProp = "INTERFACE_LINK_LIBRARIES"; - const char* propertyLibs = this->GetProperty(linkProp); + cmProp propertyLibs = this->GetProperty(linkProp); if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { if (!propertyLibs) { @@ -6156,12 +6575,12 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, } if (propertyLibs) { info.LibrariesProp = linkProp; - info.Libraries = propertyLibs; + info.Libraries = *propertyLibs; } } if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) { if (loc) { - info.LibName = loc; + info.LibName = *loc; } return; } @@ -6171,47 +6590,46 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, // Get the location. if (loc) { - info.Location = loc; + info.Location = *loc; } else { std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix); - if (const char* config_location = this->GetProperty(impProp)) { - info.Location = config_location; - } else if (const char* location = this->GetProperty("IMPORTED_LOCATION")) { - info.Location = location; + if (cmProp config_location = this->GetProperty(impProp)) { + info.Location = *config_location; + } else if (cmProp location = this->GetProperty("IMPORTED_LOCATION")) { + info.Location = *location; } } // Get the soname. if (this->GetType() == cmStateEnums::SHARED_LIBRARY) { std::string soProp = cmStrCat("IMPORTED_SONAME", suffix); - if (const char* config_soname = this->GetProperty(soProp)) { - info.SOName = config_soname; - } else if (const char* soname = this->GetProperty("IMPORTED_SONAME")) { - info.SOName = soname; + if (cmProp config_soname = this->GetProperty(soProp)) { + info.SOName = *config_soname; + } else if (cmProp soname = this->GetProperty("IMPORTED_SONAME")) { + info.SOName = *soname; } } // Get the "no-soname" mark. if (this->GetType() == cmStateEnums::SHARED_LIBRARY) { std::string soProp = cmStrCat("IMPORTED_NO_SONAME", suffix); - if (const char* config_no_soname = this->GetProperty(soProp)) { - info.NoSOName = cmIsOn(config_no_soname); - } else if (const char* no_soname = - this->GetProperty("IMPORTED_NO_SONAME")) { - info.NoSOName = cmIsOn(no_soname); + if (cmProp config_no_soname = this->GetProperty(soProp)) { + info.NoSOName = cmIsOn(*config_no_soname); + } else if (cmProp no_soname = this->GetProperty("IMPORTED_NO_SONAME")) { + info.NoSOName = cmIsOn(*no_soname); } } // Get the import library. if (imp) { - info.ImportLibrary = imp; + info.ImportLibrary = *imp; } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->IsExecutableWithExports()) { std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix); - if (const char* config_implib = this->GetProperty(impProp)) { - info.ImportLibrary = config_implib; - } else if (const char* implib = this->GetProperty("IMPORTED_IMPLIB")) { - info.ImportLibrary = implib; + if (cmProp config_implib = this->GetProperty(impProp)) { + info.ImportLibrary = *config_implib; + } else if (cmProp implib = this->GetProperty("IMPORTED_IMPLIB")) { + info.ImportLibrary = *implib; } } @@ -6219,11 +6637,11 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, { std::string linkProp = cmStrCat("IMPORTED_LINK_DEPENDENT_LIBRARIES", suffix); - if (const char* config_libs = this->GetProperty(linkProp)) { - info.SharedDeps = config_libs; - } else if (const char* libs = + if (cmProp config_libs = this->GetProperty(linkProp)) { + info.SharedDeps = *config_libs; + } else if (cmProp libs = this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) { - info.SharedDeps = libs; + info.SharedDeps = *libs; } } @@ -6231,21 +6649,21 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, if (this->LinkLanguagePropagatesToDependents()) { std::string linkProp = cmStrCat("IMPORTED_LINK_INTERFACE_LANGUAGES", suffix); - if (const char* config_libs = this->GetProperty(linkProp)) { - info.Languages = config_libs; - } else if (const char* libs = + if (cmProp config_libs = this->GetProperty(linkProp)) { + info.Languages = *config_libs; + } else if (cmProp libs = this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) { - info.Languages = libs; + info.Languages = *libs; } } // Get information if target is managed assembly. { std::string linkProp = "IMPORTED_COMMON_LANGUAGE_RUNTIME"; - if (auto pc = this->GetProperty(linkProp + suffix)) { - info.Managed = this->CheckManagedType(pc); - } else if (auto p = this->GetProperty(linkProp)) { - info.Managed = this->CheckManagedType(p); + if (cmProp pc = this->GetProperty(linkProp + suffix)) { + info.Managed = this->CheckManagedType(*pc); + } else if (cmProp p = this->GetProperty(linkProp)) { + info.Managed = this->CheckManagedType(*p); } } @@ -6253,11 +6671,11 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, if (this->GetType() == cmStateEnums::STATIC_LIBRARY) { std::string linkProp = cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix); - if (const char* config_reps = this->GetProperty(linkProp)) { - sscanf(config_reps, "%u", &info.Multiplicity); - } else if (const char* reps = + if (cmProp config_reps = this->GetProperty(linkProp)) { + sscanf(config_reps->c_str(), "%u", &info.Multiplicity); + } else if (cmProp reps = this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) { - sscanf(reps, "%u", &info.Multiplicity); + sscanf(reps->c_str(), "%u", &info.Multiplicity); } } } @@ -6265,28 +6683,36 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceMap( const std::string& config) const { - std::string CONFIG = cmSystemTools::UpperCase(config); - return this->LinkInterfaceMap[CONFIG]; + return this->LinkInterfaceMap[cmSystemTools::UpperCase(config)]; } cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap( const std::string& config) const { - std::string CONFIG = cmSystemTools::UpperCase(config); - return this->LinkInterfaceUsageRequirementsOnlyMap[CONFIG]; + return this + ->LinkInterfaceUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)]; } const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( const std::string& config) const { + return this->GetLinkImplementation(config, false); +} + +const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( + const std::string& config, bool secondPass) const +{ // There is no link implementation for imported targets. if (this->IsImported()) { return nullptr; } - std::string CONFIG = cmSystemTools::UpperCase(config); - cmOptionalLinkImplementation& impl = this->LinkImplMap[CONFIG][this]; + cmOptionalLinkImplementation& impl = + this->LinkImplMap[cmSystemTools::UpperCase(config)][this]; + if (secondPass) { + impl = cmOptionalLinkImplementation(); + } if (!impl.LibrariesDone) { impl.LibrariesDone = true; this->ComputeLinkImplementationLibraries(config, impl, this); @@ -6425,15 +6851,15 @@ std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const bool cmGeneratorTarget::IsDeprecated() const { - const char* deprecation = this->GetProperty("DEPRECATION"); - return deprecation && *deprecation; + cmProp deprecation = this->GetProperty("DEPRECATION"); + return deprecation && !deprecation->empty(); } std::string cmGeneratorTarget::GetDeprecation() const { // find DEPRECATION property - if (const char* deprecation = this->GetProperty("DEPRECATION")) { - return deprecation; + if (cmProp deprecation = this->GetProperty("DEPRECATION")) { + return *deprecation; } return std::string(); } @@ -6490,9 +6916,9 @@ bool cmGeneratorTarget::IsCSharpOnly() const std::set<std::string> languages = this->GetAllConfigCompileLanguages(); // Consider an explicit linker language property, but *not* the // computed linker language that may depend on linked targets. - const char* linkLang = this->GetProperty("LINKER_LANGUAGE"); - if (linkLang && *linkLang) { - languages.insert(linkLang); + cmProp linkLang = this->GetProperty("LINKER_LANGUAGE"); + if (linkLang && !linkLang->empty()) { + languages.insert(*linkLang); } return languages.size() == 1 && languages.count("CSharp") > 0; } @@ -6542,8 +6968,8 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal( } // Populate the link implementation libraries for this configuration. - std::string CONFIG = cmSystemTools::UpperCase(config); - HeadToLinkImplementationMap& hm = this->LinkImplMap[CONFIG]; + HeadToLinkImplementationMap& hm = + this->LinkImplMap[cmSystemTools::UpperCase(config)]; // If the link implementation does not depend on the head target // then return the one we computed first. @@ -6562,7 +6988,7 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal( bool cmGeneratorTarget::IsNullImpliedByLinkLibraries( const std::string& p) const { - return cmContains(this->LinkImplicitNullProperties, p); + return cm::contains(this->LinkImplicitNullProperties, p); } void cmGeneratorTarget::ComputeLinkImplementationLibraries( @@ -6584,11 +7010,18 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( cmGeneratorExpression ge(*btIt); std::unique_ptr<cmCompiledGeneratorExpression> const cge = ge.Parse(*le); std::string const& evaluated = - cge->Evaluate(this->LocalGenerator, config, head, &dagChecker); + cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr, + this->LinkerLanguage); cmExpandList(evaluated, llibs); if (cge->GetHadHeadSensitiveCondition()) { impl.HadHeadSensitiveCondition = true; } + if (cge->GetHadContextSensitiveCondition()) { + impl.HadContextSensitiveCondition = true; + } + if (cge->GetHadLinkLanguageSensitiveCondition()) { + impl.HadLinkLanguageSensitiveCondition = true; + } for (std::string const& lib : llibs) { if (this->IsLinkLookupScope(lib, lg)) { @@ -6866,8 +7299,8 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType( } // Check for explicitly set clr target property. - if (auto* clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) { - return this->CheckManagedType(clr); + if (cmProp clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) { + return this->CheckManagedType(*clr); } // C# targets are always managed. This language specific check |