diff options
-rw-r--r-- | Source/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 515 | ||||
-rw-r--r-- | Source/cmGeneratorTarget_Sources.cxx | 560 | ||||
-rwxr-xr-x | bootstrap | 1 |
4 files changed, 562 insertions, 515 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 5683524..8faebab 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -285,6 +285,7 @@ add_library( cmGeneratorExpression.h cmGeneratorTarget.cxx cmGeneratorTarget.h + cmGeneratorTarget_Sources.cxx cmGeneratorTarget_TargetPropertyEntry.cxx cmLinkItemGraphVisitor.cxx cmLinkItemGraphVisitor.h diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 61b93be..fb921fd 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -23,8 +23,6 @@ #include <cmext/algorithm> #include <cmext/string_view> -#include "cmsys/RegularExpression.hxx" - #include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmCryptoHash.h" @@ -49,7 +47,6 @@ #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmSourceFileLocationKind.h" -#include "cmSourceGroup.h" #include "cmStandardLevel.h" #include "cmStandardLevelResolver.h" #include "cmState.h" @@ -1520,519 +1517,7 @@ void AddLangSpecificImplicitIncludeDirectories( } } -void AddObjectEntries(cmGeneratorTarget const* headTarget, - std::string const& config, - cmGeneratorExpressionDAGChecker* dagChecker, - EvaluatedTargetPropertyEntries& entries) -{ - if (cmLinkImplementationLibraries const* impl = - headTarget->GetLinkImplementationLibraries(config, UseTo::Compile)) { - entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; - for (cmLinkImplItem const& lib : impl->Libraries) { - if (lib.Target && - lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::string uniqueName = - headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely( - lib.Target); - std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">"; - cmGeneratorExpression ge(*headTarget->Makefile->GetCMakeInstance(), - lib.Backtrace); - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex); - cge->SetEvaluateForBuildsystem(true); - - EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace); - cmExpandList(cge->Evaluate(headTarget->GetLocalGenerator(), config, - headTarget, dagChecker), - ee.Values); - if (cge->GetHadContextSensitiveCondition()) { - ee.ContextDependent = true; - } - entries.Entries.emplace_back(std::move(ee)); - } - } - } -} - -void addFileSetEntry(cmGeneratorTarget const* headTarget, - std::string const& config, - cmGeneratorExpressionDAGChecker* dagChecker, - cmFileSet const* fileSet, - EvaluatedTargetPropertyEntries& entries) -{ - auto dirCges = fileSet->CompileDirectoryEntries(); - auto dirs = fileSet->EvaluateDirectoryEntries( - dirCges, headTarget->GetLocalGenerator(), config, headTarget, dagChecker); - bool contextSensitiveDirs = false; - for (auto const& dirCge : dirCges) { - if (dirCge->GetHadContextSensitiveCondition()) { - contextSensitiveDirs = true; - break; - } - } - cmake* cm = headTarget->GetLocalGenerator()->GetCMakeInstance(); - for (auto& entryCge : fileSet->CompileFileEntries()) { - auto tpe = cmGeneratorTarget::TargetPropertyEntry::CreateFileSet( - dirs, contextSensitiveDirs, std::move(entryCge), fileSet); - entries.Entries.emplace_back( - EvaluateTargetPropertyEntry(headTarget, config, "", dagChecker, *tpe)); - EvaluatedTargetPropertyEntry const& entry = entries.Entries.back(); - for (auto const& file : entry.Values) { - auto* sf = headTarget->Makefile->GetOrCreateSource(file); - if (fileSet->GetType() == "HEADERS"_s) { - sf->SetProperty("HEADER_FILE_ONLY", "TRUE"); - } - -#ifndef CMAKE_BOOTSTRAP - std::string e; - std::string w; - auto path = sf->ResolveFullPath(&e, &w); - if (!w.empty()) { - cm->IssueMessage(MessageType::AUTHOR_WARNING, w, entry.Backtrace); - } - if (path.empty()) { - if (!e.empty()) { - cm->IssueMessage(MessageType::FATAL_ERROR, e, entry.Backtrace); - } - return; - } - bool found = false; - for (auto const& sg : headTarget->Makefile->GetSourceGroups()) { - if (sg.MatchChildrenFiles(path)) { - found = true; - break; - } - } - if (!found) { - if (fileSet->GetType() == "HEADERS"_s) { - headTarget->Makefile->GetOrCreateSourceGroup("Header Files") - ->AddGroupFile(path); - } - } -#endif - } - } -} - -void AddFileSetEntries(cmGeneratorTarget const* headTarget, - std::string const& config, - cmGeneratorExpressionDAGChecker* dagChecker, - EvaluatedTargetPropertyEntries& entries) -{ - for (auto const& entry : headTarget->Target->GetHeaderSetsEntries()) { - for (auto const& name : cmList{ entry.Value }) { - auto const* headerSet = headTarget->Target->GetFileSet(name); - addFileSetEntry(headTarget, config, dagChecker, headerSet, entries); - } - } - for (auto const& entry : headTarget->Target->GetCxxModuleSetsEntries()) { - for (auto const& name : cmList{ entry.Value }) { - auto const* cxxModuleSet = headTarget->Target->GetFileSet(name); - addFileSetEntry(headTarget, config, dagChecker, cxxModuleSet, entries); - } - } -} - -bool processSources(cmGeneratorTarget const* tgt, - EvaluatedTargetPropertyEntries& entries, - std::vector<BT<std::string>>& srcs, - std::unordered_set<std::string>& uniqueSrcs, - bool debugSources) -{ - cmMakefile* mf = tgt->Target->GetMakefile(); - - bool contextDependent = entries.HadContextSensitiveCondition; - - for (EvaluatedTargetPropertyEntry& entry : entries.Entries) { - if (entry.ContextDependent) { - contextDependent = true; - } - - cmLinkImplItem const& item = entry.LinkImplItem; - std::string const& targetName = item.AsStr(); - - for (std::string& src : entry.Values) { - cmSourceFile* sf = mf->GetOrCreateSource(src); - std::string e; - std::string w; - std::string fullPath = sf->ResolveFullPath(&e, &w); - cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance(); - if (!w.empty()) { - cm->IssueMessage(MessageType::AUTHOR_WARNING, w, entry.Backtrace); - } - if (fullPath.empty()) { - if (!e.empty()) { - cm->IssueMessage(MessageType::FATAL_ERROR, e, entry.Backtrace); - } - return contextDependent; - } - - if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src)) { - std::ostringstream err; - if (!targetName.empty()) { - err << "Target \"" << targetName - << "\" contains relative path in its INTERFACE_SOURCES:\n \"" - << src << "\""; - } else { - err << "Found relative path while evaluating sources of \"" - << tgt->GetName() << "\":\n \"" << src << "\"\n"; - } - tgt->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR, - err.str()); - return contextDependent; - } - src = fullPath; - } - std::string usedSources; - for (std::string const& src : entry.Values) { - if (uniqueSrcs.insert(src).second) { - srcs.emplace_back(src, entry.Backtrace); - if (debugSources) { - usedSources += " * " + src + "\n"; - } - } - } - if (!usedSources.empty()) { - tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage( - MessageType::LOG, - std::string("Used sources for target ") + tgt->GetName() + ":\n" + - usedSources, - entry.Backtrace); - } - } - return contextDependent; -} } - -std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( - std::string const& config) const -{ - std::vector<BT<std::string>> files; - - if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) { - // At configure-time, this method can be called as part of getting the - // LOCATION property or to export() a file to be include()d. However - // there is no cmGeneratorTarget at configure-time, so search the SOURCES - // for TARGET_OBJECTS instead for backwards compatibility with OLD - // behavior of CMP0024 and CMP0026 only. - - cmBTStringRange sourceEntries = this->Target->GetSourceEntries(); - for (auto const& entry : sourceEntries) { - cmList items{ entry.Value }; - for (auto const& item : items) { - if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") && - item.back() == '>') { - continue; - } - files.emplace_back(item); - } - } - return files; - } - - cmList debugProperties{ this->Makefile->GetDefinition( - "CMAKE_DEBUG_TARGET_PROPERTIES") }; - bool debugSources = - !this->DebugSourcesDone && cm::contains(debugProperties, "SOURCES"); - - if (this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) { - this->DebugSourcesDone = true; - } - - cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, nullptr, - this->LocalGenerator); - - 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. - EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries; - AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(), - &dagChecker, linkInterfaceSourcesEntries, - IncludeRuntimeInterface::No, UseTo::Compile); - bool contextDependentInterfaceSources = processSources( - this, linkInterfaceSourcesEntries, files, uniqueSrcs, debugSources); - - // Collect TARGET_OBJECTS of direct object link-dependencies. - bool contextDependentObjects = false; - if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) { - EvaluatedTargetPropertyEntries linkObjectsEntries; - AddObjectEntries(this, config, &dagChecker, linkObjectsEntries); - contextDependentObjects = processSources(this, linkObjectsEntries, files, - uniqueSrcs, debugSources); - // Note that for imported targets or multi-config generators supporting - // cross-config builds the paths to the object files must be per-config, - // so contextDependentObjects will be true here even if object libraries - // are specified without per-config generator expressions. - } - - // Collect this target's file sets. - EvaluatedTargetPropertyEntries fileSetEntries; - AddFileSetEntries(this, config, &dagChecker, fileSetEntries); - bool contextDependentFileSets = - processSources(this, fileSetEntries, files, uniqueSrcs, debugSources); - - // Determine if sources are context-dependent or not. - if (!contextDependentDirectSources && !contextDependentInterfaceSources && - !contextDependentObjects && !contextDependentFileSets) { - this->SourcesAreContextDependent = Tribool::False; - } else { - this->SourcesAreContextDependent = Tribool::True; - } - - return files; -} - -void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files, - const std::string& config) const -{ - std::vector<BT<cmSourceFile*>> tmp = this->GetSourceFiles(config); - files.reserve(tmp.size()); - for (BT<cmSourceFile*>& v : tmp) { - files.push_back(v.Value); - } -} - -std::vector<BT<cmSourceFile*>> cmGeneratorTarget::GetSourceFiles( - std::string const& config) const -{ - std::vector<BT<cmSourceFile*>> files; - if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) { - // Since we are still configuring not all sources may exist yet, - // so we need to avoid full source classification because that - // requires the absolute paths to all sources to be determined. - // Since this is only for compatibility with old policies that - // projects should not depend on anymore, just compute the files - // without memoizing them. - std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config); - std::set<cmSourceFile*> emitted; - for (BT<std::string> const& s : srcs) { - cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value); - if (emitted.insert(sf).second) { - files.emplace_back(sf, s.Backtrace); - } - } - return files; - } - - KindedSources const& kinded = this->GetKindedSources(config); - files.reserve(kinded.Sources.size()); - for (SourceAndKind const& si : kinded.Sources) { - files.push_back(si.Source); - } - return files; -} - -void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries( - std::vector<cmSourceFile*>& files, const std::string& config) const -{ - std::vector<BT<cmSourceFile*>> tmp = - this->GetSourceFilesWithoutObjectLibraries(config); - files.reserve(tmp.size()); - for (BT<cmSourceFile*>& v : tmp) { - files.push_back(v.Value); - } -} - -std::vector<BT<cmSourceFile*>> -cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries( - std::string const& config) const -{ - std::vector<BT<cmSourceFile*>> files; - KindedSources const& kinded = this->GetKindedSources(config); - files.reserve(kinded.Sources.size()); - for (SourceAndKind const& si : kinded.Sources) { - if (si.Source.Value->GetObjectLibrary().empty()) { - files.push_back(si.Source); - } - } - return files; -} - -cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources( - std::string const& config) const -{ - // If we already processed one configuration and found no dependency - // on configuration then always use the one result. - if (this->SourcesAreContextDependent == Tribool::False) { - return this->KindedSourcesMap.begin()->second; - } - - // Lookup any existing link implementation for this configuration. - std::string const key = cmSystemTools::UpperCase(config); - auto it = this->KindedSourcesMap.find(key); - if (it != this->KindedSourcesMap.end()) { - if (!it->second.Initialized) { - std::ostringstream e; - e << "The SOURCES of \"" << this->GetName() - << "\" use a generator expression that depends on the " - "SOURCES themselves."; - this->GlobalGenerator->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, e.str(), this->GetBacktrace()); - static KindedSources empty; - return empty; - } - return it->second; - } - - // Add an entry to the map for this configuration. - KindedSources& files = this->KindedSourcesMap[key]; - this->ComputeKindedSources(files, config); - files.Initialized = true; - return files; -} - -void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, - std::string const& config) const -{ - // Get the source file paths by string. - std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config); - - cmsys::RegularExpression header_regex(CM_HEADER_REGEX); - std::vector<cmSourceFile*> badObjLib; - - std::set<cmSourceFile*> emitted; - for (BT<std::string> const& s : srcs) { - // Create each source at most once. - cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value); - if (!emitted.insert(sf).second) { - continue; - } - - // Compute the kind (classification) of this source file. - SourceKind kind; - std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); - cmFileSet const* fs = this->GetFileSetForSource(config, sf); - if (sf->GetCustomCommand()) { - kind = SourceKindCustomCommand; - } else if (!this->Target->IsNormal() && !this->Target->IsImported() && - fs && (fs->GetType() == "CXX_MODULES"_s)) { - kind = SourceKindCxxModuleSource; - } else if (this->Target->GetType() == cmStateEnums::UTILITY || - this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY - // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 - // NOLINTNEXTLINE(bugprone-branch-clone) - ) { - 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")) { - kind = SourceKindExternalObject; - } else if (!sf->GetOrDetermineLanguage().empty()) { - kind = SourceKindObjectSource; - } else if (ext == "def") { - kind = SourceKindModuleDefinition; - if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) { - badObjLib.push_back(sf); - } - } else if (ext == "idl") { - kind = SourceKindIDL; - if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) { - badObjLib.push_back(sf); - } - } else if (ext == "resx") { - kind = SourceKindResx; - } else if (ext == "appxmanifest") { - kind = SourceKindAppManifest; - } else if (ext == "manifest") { - if (sf->GetPropertyAsBool("VS_DEPLOYMENT_CONTENT")) { - kind = SourceKindExtra; - } else { - kind = SourceKindManifest; - } - } else if (ext == "pfx") { - kind = SourceKindCertificate; - } else if (ext == "xaml") { - kind = SourceKindXaml; - } else if (header_regex.find(sf->ResolveFullPath())) { - kind = SourceKindHeader; - } else { - kind = SourceKindExtra; - } - - // Save this classified source file in the result vector. - files.Sources.push_back({ BT<cmSourceFile*>(sf, s.Backtrace), kind }); - } - - if (!badObjLib.empty()) { - std::ostringstream e; - e << "OBJECT library \"" << this->GetName() << "\" contains:\n"; - for (cmSourceFile* i : badObjLib) { - e << " " << i->GetLocation().GetName() << "\n"; - } - e << "but may contain only sources that compile, header files, and " - "other files that would not affect linking of a normal library."; - this->GlobalGenerator->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, e.str(), this->GetBacktrace()); - } -} - -std::vector<cmGeneratorTarget::AllConfigSource> const& -cmGeneratorTarget::GetAllConfigSources() const -{ - if (this->AllConfigSources.empty()) { - this->ComputeAllConfigSources(); - } - return this->AllConfigSources; -} - -void cmGeneratorTarget::ComputeAllConfigSources() const -{ - std::vector<std::string> configs = - this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); - - std::map<cmSourceFile const*, size_t> index; - - for (size_t ci = 0; ci < configs.size(); ++ci) { - KindedSources const& sources = this->GetKindedSources(configs[ci]); - for (SourceAndKind const& src : sources.Sources) { - auto mi = index.find(src.Source.Value); - if (mi == index.end()) { - AllConfigSource acs; - acs.Source = src.Source.Value; - acs.Kind = src.Kind; - this->AllConfigSources.push_back(std::move(acs)); - std::map<cmSourceFile const*, size_t>::value_type entry( - src.Source.Value, this->AllConfigSources.size() - 1); - mi = index.insert(entry).first; - } - this->AllConfigSources[mi->second].Configs.push_back(ci); - } - } -} - -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; - std::vector<AllConfigSource> const& sources = this->GetAllConfigSources(); - for (AllConfigSource const& si : sources) { - std::string const& lang = si.Source->GetOrDetermineLanguage(); - if (!lang.empty()) { - languages.emplace(lang); - } - } - return languages; -} - std::string cmGeneratorTarget::GetCompilePDBName( const std::string& config) const { diff --git a/Source/cmGeneratorTarget_Sources.cxx b/Source/cmGeneratorTarget_Sources.cxx new file mode 100644 index 0000000..de18df5 --- /dev/null +++ b/Source/cmGeneratorTarget_Sources.cxx @@ -0,0 +1,560 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +/* clang-format off */ +#include "cmGeneratorTarget.h" +/* clang-format on */ + +#include <cstddef> +#include <map> +#include <memory> +#include <set> +#include <sstream> +#include <string> +#include <type_traits> +#include <unordered_set> +#include <utility> +#include <vector> + +#include <cm/string_view> +#include <cmext/algorithm> +#include <cmext/string_view> + +#include "cmsys/RegularExpression.hxx" + +#include "cmAlgorithms.h" +#include "cmEvaluatedTargetProperty.h" +#include "cmFileSet.h" +#include "cmGeneratorExpression.h" +#include "cmGeneratorExpressionDAGChecker.h" +#include "cmGlobalGenerator.h" +#include "cmLinkItem.h" +#include "cmList.h" +#include "cmListFileCache.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmSourceFile.h" +#include "cmSourceFileLocation.h" +#include "cmSourceGroup.h" +#include "cmStateTypes.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmTarget.h" +#include "cmValue.h" +#include "cmake.h" + +namespace { +using UseTo = cmGeneratorTarget::UseTo; + +void AddObjectEntries(cmGeneratorTarget const* headTarget, + std::string const& config, + cmGeneratorExpressionDAGChecker* dagChecker, + EvaluatedTargetPropertyEntries& entries) +{ + if (cmLinkImplementationLibraries const* impl = + headTarget->GetLinkImplementationLibraries(config, UseTo::Compile)) { + entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; + for (cmLinkImplItem const& lib : impl->Libraries) { + if (lib.Target && + lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { + std::string uniqueName = + headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely( + lib.Target); + std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">"; + cmGeneratorExpression ge(*headTarget->Makefile->GetCMakeInstance(), + lib.Backtrace); + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex); + cge->SetEvaluateForBuildsystem(true); + + EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace); + cmExpandList(cge->Evaluate(headTarget->GetLocalGenerator(), config, + headTarget, dagChecker), + ee.Values); + if (cge->GetHadContextSensitiveCondition()) { + ee.ContextDependent = true; + } + entries.Entries.emplace_back(std::move(ee)); + } + } + } +} + +void addFileSetEntry(cmGeneratorTarget const* headTarget, + std::string const& config, + cmGeneratorExpressionDAGChecker* dagChecker, + cmFileSet const* fileSet, + EvaluatedTargetPropertyEntries& entries) +{ + auto dirCges = fileSet->CompileDirectoryEntries(); + auto dirs = fileSet->EvaluateDirectoryEntries( + dirCges, headTarget->GetLocalGenerator(), config, headTarget, dagChecker); + bool contextSensitiveDirs = false; + for (auto const& dirCge : dirCges) { + if (dirCge->GetHadContextSensitiveCondition()) { + contextSensitiveDirs = true; + break; + } + } + cmake* cm = headTarget->GetLocalGenerator()->GetCMakeInstance(); + for (auto& entryCge : fileSet->CompileFileEntries()) { + auto tpe = cmGeneratorTarget::TargetPropertyEntry::CreateFileSet( + dirs, contextSensitiveDirs, std::move(entryCge), fileSet); + entries.Entries.emplace_back( + EvaluateTargetPropertyEntry(headTarget, config, "", dagChecker, *tpe)); + EvaluatedTargetPropertyEntry const& entry = entries.Entries.back(); + for (auto const& file : entry.Values) { + auto* sf = headTarget->Makefile->GetOrCreateSource(file); + if (fileSet->GetType() == "HEADERS"_s) { + sf->SetProperty("HEADER_FILE_ONLY", "TRUE"); + } + +#ifndef CMAKE_BOOTSTRAP + std::string e; + std::string w; + auto path = sf->ResolveFullPath(&e, &w); + if (!w.empty()) { + cm->IssueMessage(MessageType::AUTHOR_WARNING, w, entry.Backtrace); + } + if (path.empty()) { + if (!e.empty()) { + cm->IssueMessage(MessageType::FATAL_ERROR, e, entry.Backtrace); + } + return; + } + bool found = false; + for (auto const& sg : headTarget->Makefile->GetSourceGroups()) { + if (sg.MatchChildrenFiles(path)) { + found = true; + break; + } + } + if (!found) { + if (fileSet->GetType() == "HEADERS"_s) { + headTarget->Makefile->GetOrCreateSourceGroup("Header Files") + ->AddGroupFile(path); + } + } +#endif + } + } +} + +void AddFileSetEntries(cmGeneratorTarget const* headTarget, + std::string const& config, + cmGeneratorExpressionDAGChecker* dagChecker, + EvaluatedTargetPropertyEntries& entries) +{ + for (auto const& entry : headTarget->Target->GetHeaderSetsEntries()) { + for (auto const& name : cmList{ entry.Value }) { + auto const* headerSet = headTarget->Target->GetFileSet(name); + addFileSetEntry(headTarget, config, dagChecker, headerSet, entries); + } + } + for (auto const& entry : headTarget->Target->GetCxxModuleSetsEntries()) { + for (auto const& name : cmList{ entry.Value }) { + auto const* cxxModuleSet = headTarget->Target->GetFileSet(name); + addFileSetEntry(headTarget, config, dagChecker, cxxModuleSet, entries); + } + } +} + +bool processSources(cmGeneratorTarget const* tgt, + EvaluatedTargetPropertyEntries& entries, + std::vector<BT<std::string>>& srcs, + std::unordered_set<std::string>& uniqueSrcs, + bool debugSources) +{ + cmMakefile* mf = tgt->Target->GetMakefile(); + + bool contextDependent = entries.HadContextSensitiveCondition; + + for (EvaluatedTargetPropertyEntry& entry : entries.Entries) { + if (entry.ContextDependent) { + contextDependent = true; + } + + cmLinkImplItem const& item = entry.LinkImplItem; + std::string const& targetName = item.AsStr(); + + for (std::string& src : entry.Values) { + cmSourceFile* sf = mf->GetOrCreateSource(src); + std::string e; + std::string w; + std::string fullPath = sf->ResolveFullPath(&e, &w); + cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance(); + if (!w.empty()) { + cm->IssueMessage(MessageType::AUTHOR_WARNING, w, entry.Backtrace); + } + if (fullPath.empty()) { + if (!e.empty()) { + cm->IssueMessage(MessageType::FATAL_ERROR, e, entry.Backtrace); + } + return contextDependent; + } + + if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src)) { + std::ostringstream err; + if (!targetName.empty()) { + err << "Target \"" << targetName + << "\" contains relative path in its INTERFACE_SOURCES:\n \"" + << src << "\""; + } else { + err << "Found relative path while evaluating sources of \"" + << tgt->GetName() << "\":\n \"" << src << "\"\n"; + } + tgt->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR, + err.str()); + return contextDependent; + } + src = fullPath; + } + std::string usedSources; + for (std::string const& src : entry.Values) { + if (uniqueSrcs.insert(src).second) { + srcs.emplace_back(src, entry.Backtrace); + if (debugSources) { + usedSources += " * " + src + "\n"; + } + } + } + if (!usedSources.empty()) { + tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage( + MessageType::LOG, + std::string("Used sources for target ") + tgt->GetName() + ":\n" + + usedSources, + entry.Backtrace); + } + } + return contextDependent; +} +} + +std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( + std::string const& config) const +{ + std::vector<BT<std::string>> files; + + if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) { + // At configure-time, this method can be called as part of getting the + // LOCATION property or to export() a file to be include()d. However + // there is no cmGeneratorTarget at configure-time, so search the SOURCES + // for TARGET_OBJECTS instead for backwards compatibility with OLD + // behavior of CMP0024 and CMP0026 only. + + cmBTStringRange sourceEntries = this->Target->GetSourceEntries(); + for (auto const& entry : sourceEntries) { + cmList items{ entry.Value }; + for (auto const& item : items) { + if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") && + item.back() == '>') { + continue; + } + files.emplace_back(item); + } + } + return files; + } + + cmList debugProperties{ this->Makefile->GetDefinition( + "CMAKE_DEBUG_TARGET_PROPERTIES") }; + bool debugSources = + !this->DebugSourcesDone && cm::contains(debugProperties, "SOURCES"); + + if (this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) { + this->DebugSourcesDone = true; + } + + cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, nullptr, + this->LocalGenerator); + + 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. + EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries; + AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(), + &dagChecker, linkInterfaceSourcesEntries, + IncludeRuntimeInterface::No, UseTo::Compile); + bool contextDependentInterfaceSources = processSources( + this, linkInterfaceSourcesEntries, files, uniqueSrcs, debugSources); + + // Collect TARGET_OBJECTS of direct object link-dependencies. + bool contextDependentObjects = false; + if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) { + EvaluatedTargetPropertyEntries linkObjectsEntries; + AddObjectEntries(this, config, &dagChecker, linkObjectsEntries); + contextDependentObjects = processSources(this, linkObjectsEntries, files, + uniqueSrcs, debugSources); + // Note that for imported targets or multi-config generators supporting + // cross-config builds the paths to the object files must be per-config, + // so contextDependentObjects will be true here even if object libraries + // are specified without per-config generator expressions. + } + + // Collect this target's file sets. + EvaluatedTargetPropertyEntries fileSetEntries; + AddFileSetEntries(this, config, &dagChecker, fileSetEntries); + bool contextDependentFileSets = + processSources(this, fileSetEntries, files, uniqueSrcs, debugSources); + + // Determine if sources are context-dependent or not. + if (!contextDependentDirectSources && !contextDependentInterfaceSources && + !contextDependentObjects && !contextDependentFileSets) { + this->SourcesAreContextDependent = Tribool::False; + } else { + this->SourcesAreContextDependent = Tribool::True; + } + + return files; +} + +void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files, + const std::string& config) const +{ + std::vector<BT<cmSourceFile*>> tmp = this->GetSourceFiles(config); + files.reserve(tmp.size()); + for (BT<cmSourceFile*>& v : tmp) { + files.push_back(v.Value); + } +} + +std::vector<BT<cmSourceFile*>> cmGeneratorTarget::GetSourceFiles( + std::string const& config) const +{ + std::vector<BT<cmSourceFile*>> files; + if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) { + // Since we are still configuring not all sources may exist yet, + // so we need to avoid full source classification because that + // requires the absolute paths to all sources to be determined. + // Since this is only for compatibility with old policies that + // projects should not depend on anymore, just compute the files + // without memoizing them. + std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config); + std::set<cmSourceFile*> emitted; + for (BT<std::string> const& s : srcs) { + cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value); + if (emitted.insert(sf).second) { + files.emplace_back(sf, s.Backtrace); + } + } + return files; + } + + KindedSources const& kinded = this->GetKindedSources(config); + files.reserve(kinded.Sources.size()); + for (SourceAndKind const& si : kinded.Sources) { + files.push_back(si.Source); + } + return files; +} + +void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries( + std::vector<cmSourceFile*>& files, const std::string& config) const +{ + std::vector<BT<cmSourceFile*>> tmp = + this->GetSourceFilesWithoutObjectLibraries(config); + files.reserve(tmp.size()); + for (BT<cmSourceFile*>& v : tmp) { + files.push_back(v.Value); + } +} + +std::vector<BT<cmSourceFile*>> +cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries( + std::string const& config) const +{ + std::vector<BT<cmSourceFile*>> files; + KindedSources const& kinded = this->GetKindedSources(config); + files.reserve(kinded.Sources.size()); + for (SourceAndKind const& si : kinded.Sources) { + if (si.Source.Value->GetObjectLibrary().empty()) { + files.push_back(si.Source); + } + } + return files; +} + +cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources( + std::string const& config) const +{ + // If we already processed one configuration and found no dependency + // on configuration then always use the one result. + if (this->SourcesAreContextDependent == Tribool::False) { + return this->KindedSourcesMap.begin()->second; + } + + // Lookup any existing link implementation for this configuration. + std::string const key = cmSystemTools::UpperCase(config); + auto it = this->KindedSourcesMap.find(key); + if (it != this->KindedSourcesMap.end()) { + if (!it->second.Initialized) { + std::ostringstream e; + e << "The SOURCES of \"" << this->GetName() + << "\" use a generator expression that depends on the " + "SOURCES themselves."; + this->GlobalGenerator->GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, e.str(), this->GetBacktrace()); + static KindedSources empty; + return empty; + } + return it->second; + } + + // Add an entry to the map for this configuration. + KindedSources& files = this->KindedSourcesMap[key]; + this->ComputeKindedSources(files, config); + files.Initialized = true; + return files; +} + +void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, + std::string const& config) const +{ + // Get the source file paths by string. + std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config); + + cmsys::RegularExpression header_regex(CM_HEADER_REGEX); + std::vector<cmSourceFile*> badObjLib; + + std::set<cmSourceFile*> emitted; + for (BT<std::string> const& s : srcs) { + // Create each source at most once. + cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value); + if (!emitted.insert(sf).second) { + continue; + } + + // Compute the kind (classification) of this source file. + SourceKind kind; + std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); + cmFileSet const* fs = this->GetFileSetForSource(config, sf); + if (sf->GetCustomCommand()) { + kind = SourceKindCustomCommand; + } else if (!this->Target->IsNormal() && !this->Target->IsImported() && + fs && (fs->GetType() == "CXX_MODULES"_s)) { + kind = SourceKindCxxModuleSource; + } else if (this->Target->GetType() == cmStateEnums::UTILITY || + this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) + ) { + 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")) { + kind = SourceKindExternalObject; + } else if (!sf->GetOrDetermineLanguage().empty()) { + kind = SourceKindObjectSource; + } else if (ext == "def") { + kind = SourceKindModuleDefinition; + if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) { + badObjLib.push_back(sf); + } + } else if (ext == "idl") { + kind = SourceKindIDL; + if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) { + badObjLib.push_back(sf); + } + } else if (ext == "resx") { + kind = SourceKindResx; + } else if (ext == "appxmanifest") { + kind = SourceKindAppManifest; + } else if (ext == "manifest") { + if (sf->GetPropertyAsBool("VS_DEPLOYMENT_CONTENT")) { + kind = SourceKindExtra; + } else { + kind = SourceKindManifest; + } + } else if (ext == "pfx") { + kind = SourceKindCertificate; + } else if (ext == "xaml") { + kind = SourceKindXaml; + } else if (header_regex.find(sf->ResolveFullPath())) { + kind = SourceKindHeader; + } else { + kind = SourceKindExtra; + } + + // Save this classified source file in the result vector. + files.Sources.push_back({ BT<cmSourceFile*>(sf, s.Backtrace), kind }); + } + + if (!badObjLib.empty()) { + std::ostringstream e; + e << "OBJECT library \"" << this->GetName() << "\" contains:\n"; + for (cmSourceFile* i : badObjLib) { + e << " " << i->GetLocation().GetName() << "\n"; + } + e << "but may contain only sources that compile, header files, and " + "other files that would not affect linking of a normal library."; + this->GlobalGenerator->GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, e.str(), this->GetBacktrace()); + } +} + +std::vector<cmGeneratorTarget::AllConfigSource> const& +cmGeneratorTarget::GetAllConfigSources() const +{ + if (this->AllConfigSources.empty()) { + this->ComputeAllConfigSources(); + } + return this->AllConfigSources; +} + +void cmGeneratorTarget::ComputeAllConfigSources() const +{ + std::vector<std::string> configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + + std::map<cmSourceFile const*, size_t> index; + + for (size_t ci = 0; ci < configs.size(); ++ci) { + KindedSources const& sources = this->GetKindedSources(configs[ci]); + for (SourceAndKind const& src : sources.Sources) { + auto mi = index.find(src.Source.Value); + if (mi == index.end()) { + AllConfigSource acs; + acs.Source = src.Source.Value; + acs.Kind = src.Kind; + this->AllConfigSources.push_back(std::move(acs)); + std::map<cmSourceFile const*, size_t>::value_type entry( + src.Source.Value, this->AllConfigSources.size() - 1); + mi = index.insert(entry).first; + } + this->AllConfigSources[mi->second].Configs.push_back(ci); + } + } +} + +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; + std::vector<AllConfigSource> const& sources = this->GetAllConfigSources(); + for (AllConfigSource const& si : sources) { + std::string const& lang = si.Source->GetOrDetermineLanguage(); + if (!lang.empty()) { + languages.emplace(lang); + } + } + return languages; +} @@ -381,6 +381,7 @@ CMAKE_CXX_SOURCES="\ cmGeneratorExpressionNode \ cmGeneratorExpressionParser \ cmGeneratorTarget \ + cmGeneratorTarget_Sources \ cmGeneratorTarget_TargetPropertyEntry \ cmGetCMakePropertyCommand \ cmGetDirectoryPropertyCommand \ |