mirror of
https://github.com/Kitware/CMake.git
synced 2026-08-09 17:18:18 +00:00
Add and use a couple helper functions for issuing policy warnings. This improves consistency and allows some simplification of many call sites. (One or two instances in particular are greatly simplified.)
578 lines
20 KiB
C++
578 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) {
|
|
auto const* fileSet = this->GetFileSetForSource(config, sf);
|
|
if (fileSet->GetType() == cm::FileSetMetadata::HEADERS) {
|
|
sf->SetProperty("HEADER_FILE_ONLY", "TRUE");
|
|
}
|
|
#if !defined(CMAKE_BOOTSTRAP)
|
|
cmMakefile* mf = this->Target->GetMakefile();
|
|
auto const& path = sf->GetFullPath();
|
|
bool found = false;
|
|
for (auto const& sg : mf->GetSourceGroups()) {
|
|
if (sg->MatchChildrenFiles(path)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
if (fileSet->GetType() == cm::FileSetMetadata::HEADERS) {
|
|
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;
|
|
}
|