mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
File sets currently have issues with files containing semicolons;
particularly, names get mangled differently in different contexts. This
can result in failing to find a file's file set. Prior to dee8799d16
(FileSet management: Introduce dedicated classes for generation,
2026-02-16, v4.4.0-rc1~691^2), we guarded against this, but the
aforementioned commit introduced code that would try to use the found
fileset object without checking if it was valid. Add the missing checks
so that we do not crash trying to dereference a null pointer. Also,
refactor `cmGeneratorTarget::GetSourceFilePaths` to avoid unnecessary
work.
Fixes: #27924
576 lines
20 KiB
C++
576 lines
20 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
|
/* clang-format off */
|
|
#include "cmGeneratorTarget.h"
|
|
/* clang-format on */
|
|
|
|
#include "cmConfigure.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstddef>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <unordered_set>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <cm/string_view>
|
|
#include <cmext/algorithm>
|
|
|
|
#include "cmsys/RegularExpression.hxx"
|
|
|
|
#include "cmEvaluatedTargetProperty.h"
|
|
#include "cmFileSetMetadata.h"
|
|
#include "cmGenExContext.h"
|
|
#include "cmGeneratorExpression.h"
|
|
#include "cmGeneratorExpressionDAGChecker.h"
|
|
#include "cmGeneratorFileSet.h"
|
|
#include "cmGeneratorFileSets.h"
|
|
#include "cmGlobalGenerator.h"
|
|
#include "cmLinkItem.h"
|
|
#include "cmList.h"
|
|
#include "cmListFileCache.h"
|
|
#include "cmLocalGenerator.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmMessageType.h"
|
|
#include "cmPolicies.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,
|
|
cm::GenEx::Context const& context,
|
|
cmGeneratorExpressionDAGChecker* dagChecker,
|
|
cm::EvaluatedTargetPropertyEntries& entries)
|
|
{
|
|
if (cmLinkImplementationLibraries const* impl =
|
|
headTarget->GetLinkImplementationLibraries(context.Config,
|
|
UseTo::Link)) {
|
|
entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition;
|
|
for (cmLinkItem const& lib : impl->Libraries) {
|
|
if (lib.Target &&
|
|
lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
|
|
std::string uniqueName =
|
|
headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
|
|
lib.Target);
|
|
std::string genex =
|
|
cmStrCat("$<TARGET_OBJECTS:", std::move(uniqueName), '>');
|
|
cmGeneratorExpression ge(*headTarget->Makefile->GetCMakeInstance(),
|
|
lib.Backtrace);
|
|
std::unique_ptr<cmCompiledGeneratorExpression> cge =
|
|
ge.Parse(std::move(genex));
|
|
cge->SetEvaluateForBuildsystem(true);
|
|
|
|
cm::EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
|
|
cmExpandList(cge->Evaluate(context, dagChecker, headTarget),
|
|
ee.Values);
|
|
if (cge->GetHadContextSensitiveCondition()) {
|
|
ee.ContextDependent = true;
|
|
}
|
|
entries.Entries.emplace_back(std::move(ee));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AddFileSetEntries(cmGeneratorTarget const* headTarget,
|
|
cmGeneratorFileSets const* fileSets,
|
|
cm::GenEx::Context const& context,
|
|
cmGeneratorExpressionDAGChecker* dagChecker,
|
|
cm::EvaluatedTargetPropertyEntries& entries)
|
|
{
|
|
auto sources = fileSets->GetSources(context, headTarget, dagChecker);
|
|
entries =
|
|
EvaluateTargetPropertyEntries(headTarget, context, dagChecker, sources);
|
|
}
|
|
|
|
bool processSources(cmGeneratorTarget const* tgt, std::string const& config,
|
|
cm::EvaluatedTargetPropertyEntries& entries,
|
|
std::vector<BT<std::string>>& srcs,
|
|
std::unordered_set<std::string>& uniqueSrcs,
|
|
bool debugSources,
|
|
std::function<void(cmSourceFile*)> postProcess = {})
|
|
{
|
|
cmMakefile* mf = tgt->Target->GetMakefile();
|
|
|
|
bool contextDependent = entries.HadContextSensitiveCondition;
|
|
|
|
for (cm::EvaluatedTargetPropertyEntry& entry : entries.Entries) {
|
|
if (entry.ContextDependent) {
|
|
contextDependent = true;
|
|
}
|
|
|
|
cmLinkItem const& item = entry.LinkItem;
|
|
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);
|
|
cmLocalGenerator const* const lg = tgt->GetLocalGenerator();
|
|
if (!w.empty()) {
|
|
lg->IssuePolicyWarning(cmPolicies::CMP0115, {}, w, entry.Backtrace);
|
|
}
|
|
if (fullPath.empty()) {
|
|
if (!e.empty()) {
|
|
lg->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;
|
|
|
|
if (postProcess) {
|
|
postProcess(sf);
|
|
}
|
|
}
|
|
std::string usedSources;
|
|
for (std::string const& src : entry.Values) {
|
|
if (uniqueSrcs.insert(src).second) {
|
|
srcs.emplace_back(src, entry.Backtrace);
|
|
if (debugSources) {
|
|
usedSources += cmStrCat(" * ", src, '\n');
|
|
}
|
|
} else {
|
|
auto const& fileSets =
|
|
tgt->GetGeneratorFileSets()->GetAllFileSetsForSource(config, src);
|
|
if (fileSets.empty()) {
|
|
continue;
|
|
}
|
|
auto fileMustBeUnique = [&fileSets]() -> bool {
|
|
return std::none_of(
|
|
fileSets.begin(), fileSets.end(),
|
|
[](cmGeneratorFileSet const* fileSet) {
|
|
return cm::FileSetMetadata::GetAttributes(fileSet->GetType())
|
|
.contains(cm::FileSetMetadata::FileSetAttributes::
|
|
FilesInMultipleFileSets);
|
|
});
|
|
};
|
|
if (fileMustBeUnique()) {
|
|
auto const* fileSet = *fileSets.begin();
|
|
switch (tgt->GetPolicyStatusCMP0211()) {
|
|
case cmPolicies::WARN:
|
|
tgt->GetLocalGenerator()->IssuePolicyWarning(
|
|
cmPolicies::CMP0211, {},
|
|
cmStrCat("In target \"", tgt->GetName(), "\" the file\n ",
|
|
src, "\nalready belongs to file set \"",
|
|
fileSet->GetName(), "\"."));
|
|
CM_FALLTHROUGH;
|
|
case cmPolicies::OLD:
|
|
break;
|
|
default:
|
|
tgt->GetLocalGenerator()->IssueMessage(
|
|
MessageType::FATAL_ERROR,
|
|
cmStrCat("In target \"", tgt->GetName(), "\" the file\n ",
|
|
src, "\nalready belongs to file set \"",
|
|
fileSet->GetName(), "\"."));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!usedSources.empty()) {
|
|
tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
|
|
MessageType::LOG,
|
|
cmStrCat("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;
|
|
|
|
cmList debugProperties{ this->Makefile->GetDefinition(
|
|
"CMAKE_DEBUG_TARGET_PROPERTIES") };
|
|
bool debugSources =
|
|
!this->DebugSourcesDone && cm::contains(debugProperties, "SOURCES");
|
|
|
|
this->DebugSourcesDone = true;
|
|
|
|
cm::GenEx::Context context(this->LocalGenerator, config,
|
|
/*language=*/std::string());
|
|
|
|
cmGeneratorExpressionDAGChecker dagChecker{
|
|
this, "SOURCES", nullptr, nullptr, context,
|
|
};
|
|
|
|
cm::EvaluatedTargetPropertyEntries entries =
|
|
cm::EvaluateTargetPropertyEntries(this, context, &dagChecker,
|
|
this->SourceEntries);
|
|
|
|
std::unordered_set<std::string> uniqueSrcs;
|
|
bool contextDependentDirectSources =
|
|
processSources(this, config, entries, files, uniqueSrcs, debugSources);
|
|
|
|
// Collect INTERFACE_SOURCES of all direct link-dependencies.
|
|
cm::EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries;
|
|
cm::AddInterfaceEntries(this, "INTERFACE_SOURCES", context, &dagChecker,
|
|
linkInterfaceSourcesEntries,
|
|
cm::IncludeRuntimeInterface::No, UseTo::Compile);
|
|
bool contextDependentInterfaceSources =
|
|
processSources(this, config, linkInterfaceSourcesEntries, files,
|
|
uniqueSrcs, debugSources);
|
|
|
|
// Collect TARGET_OBJECTS of direct object link-dependencies.
|
|
bool contextDependentObjects = false;
|
|
if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
|
|
cm::EvaluatedTargetPropertyEntries linkObjectsEntries;
|
|
AddObjectEntries(this, context, &dagChecker, linkObjectsEntries);
|
|
contextDependentObjects = processSources(this, config, 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.
|
|
cmGeneratorExpressionDAGChecker fsDagChecker{
|
|
this, "SOURCES", nullptr, nullptr, context,
|
|
};
|
|
|
|
cm::EvaluatedTargetPropertyEntries fileSetEntries;
|
|
AddFileSetEntries(this, this->FileSets.get(), context, &fsDagChecker,
|
|
fileSetEntries);
|
|
auto processFileSetEntry = [this, &config](cmSourceFile* sf) {
|
|
cmGeneratorFileSet const* fileSet = this->GetFileSetForSource(config, sf);
|
|
if (fileSet && fileSet->GetType() == cm::FileSetMetadata::HEADERS) {
|
|
sf->SetProperty("HEADER_FILE_ONLY", "TRUE");
|
|
#if !defined(CMAKE_BOOTSTRAP)
|
|
cmMakefile* mf = this->Target->GetMakefile();
|
|
std::string const& path = sf->GetFullPath();
|
|
bool found = false;
|
|
for (auto const& sg : mf->GetSourceGroups()) {
|
|
if (sg->MatchChildrenFiles(path)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
mf->GetOrCreateSourceGroup("Header Files")->AddGroupFile(path);
|
|
}
|
|
#endif
|
|
}
|
|
};
|
|
bool contextDependentFileSets =
|
|
processSources(this, config, fileSetEntries, files, uniqueSrcs,
|
|
debugSources, processFileSetEntry);
|
|
|
|
// Collect file sets INTERFACE_SOURCES of all direct link-dependencies.
|
|
cm::EvaluatedTargetPropertyEntries linkInterfaceFileSetsEntries;
|
|
cm::AddInterfaceFileSetsEntries(this, cm::FileSetMetadata::SOURCES,
|
|
"INTERFACE_SOURCES", context, &fsDagChecker,
|
|
linkInterfaceFileSetsEntries);
|
|
bool contextDependentInterfaceFileSets =
|
|
processSources(this, config, linkInterfaceFileSetsEntries, files,
|
|
uniqueSrcs, debugSources);
|
|
|
|
// Determine if sources are context-dependent or not.
|
|
if (!contextDependentDirectSources && !contextDependentInterfaceSources &&
|
|
!contextDependentObjects && !contextDependentFileSets &&
|
|
!contextDependentInterfaceFileSets) {
|
|
this->SourcesAreContextDependent = Tribool::False;
|
|
} else {
|
|
this->SourcesAreContextDependent = Tribool::True;
|
|
}
|
|
|
|
return files;
|
|
}
|
|
|
|
void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
|
|
std::string const& 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;
|
|
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, std::string const& 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;
|
|
|
|
cmValue const rustMainCrateRootProp =
|
|
this->GetProperty("Rust_MAIN_CRATE_ROOT");
|
|
cmSourceFile const* rustMainCrateRootSf = rustMainCrateRootProp
|
|
? this->Makefile->GetOrCreateSource(rustMainCrateRootProp)
|
|
: nullptr;
|
|
|
|
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());
|
|
cmGeneratorFileSet const* fs = this->GetFileSetForSource(config, sf);
|
|
if (sf->GetCustomCommand()) {
|
|
kind = SourceKindCustomCommand;
|
|
} else if (!this->Target->IsNormal() && !this->Target->IsImported() &&
|
|
fs && (fs->GetType() == cm::FileSetMetadata::CXX_MODULES)) {
|
|
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()) {
|
|
if (sf->GetOrDetermineLanguage() == "Rust") {
|
|
// NOLINTNEXTLINE(bugprone-branch-clone)
|
|
if (this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
|
|
// There is no main crate root for object libraries.
|
|
kind = SourceKindObjectSource;
|
|
} else if (!rustMainCrateRootSf) {
|
|
// We do not have a main crate root source file, we use the first
|
|
// Rust source file for it.
|
|
rustMainCrateRootSf = sf;
|
|
kind = SourceKindRustMainCrateRoot;
|
|
} else if (rustMainCrateRootSf == sf) {
|
|
// Current source file is the main crate root defined in the target
|
|
// Rust_MAIN_CRATE_ROOT property.
|
|
kind = SourceKindRustMainCrateRoot;
|
|
} else {
|
|
// Any other Rust source file is treated as a normal object, but will
|
|
// be built into a .rlib. Maybe in the future this could be changed?
|
|
kind = SourceKindObjectSource;
|
|
}
|
|
} else {
|
|
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;
|
|
}
|
|
|
|
void cmGeneratorTarget::ComputeAllConfigCompileLanguages() 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);
|
|
}
|
|
}
|
|
this->AllConfigCompileLanguages = languages;
|
|
}
|
|
|
|
std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const
|
|
{
|
|
if (this->AllConfigCompileLanguages.empty()) {
|
|
this->ComputeAllConfigCompileLanguages();
|
|
}
|
|
return this->AllConfigCompileLanguages;
|
|
}
|