Merge topic 'imported-same-name'

f35be59961 Fix transitive usage requirements through same-name imported targets
1b57f49586 genex: Simplify cmGeneratorExpressionInterpreter
bea390e9bd Fix dependency propagation through same-name imported targets
fc7e4d1ed8 cmLinkItem: Convert to a "sum type" over a string and target pointer

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2359
This commit is contained in:
Brad King
2018-09-11 12:20:44 +00:00
committed by Kitware Robot
32 changed files with 297 additions and 221 deletions
+1
View File
@@ -265,6 +265,7 @@ set(SRCS
cmInstallDirectoryGenerator.h
cmInstallDirectoryGenerator.cxx
cmLinkedTree.h
cmLinkItem.cxx
cmLinkItem.h
cmLinkLineComputer.cxx
cmLinkLineComputer.h
+17 -16
View File
@@ -279,12 +279,12 @@ cmComputeLinkDepends::Compute()
return this->FinalLinkEntries;
}
std::map<std::string, int>::iterator cmComputeLinkDepends::AllocateLinkEntry(
std::string const& item)
std::map<cmLinkItem, int>::iterator cmComputeLinkDepends::AllocateLinkEntry(
cmLinkItem const& item)
{
std::map<std::string, int>::value_type index_entry(
std::map<cmLinkItem, int>::value_type index_entry(
item, static_cast<int>(this->EntryList.size()));
std::map<std::string, int>::iterator lei =
std::map<cmLinkItem, int>::iterator lei =
this->LinkEntryIndex.insert(index_entry).first;
this->EntryList.emplace_back();
this->InferredDependSets.push_back(nullptr);
@@ -295,7 +295,7 @@ std::map<std::string, int>::iterator cmComputeLinkDepends::AllocateLinkEntry(
int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item)
{
// Check if the item entry has already been added.
std::map<std::string, int>::iterator lei = this->LinkEntryIndex.find(item);
std::map<cmLinkItem, int>::iterator lei = this->LinkEntryIndex.find(item);
if (lei != this->LinkEntryIndex.end()) {
// Yes. We do not need to follow the item's dependencies again.
return lei->second;
@@ -307,10 +307,11 @@ int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item)
// Initialize the item entry.
int index = lei->second;
LinkEntry& entry = this->EntryList[index];
entry.Item = item;
entry.Item = item.AsStr();
entry.Target = item.Target;
entry.IsFlag = (!entry.Target && item[0] == '-' && item[1] != 'l' &&
item.substr(0, 10) != "-framework");
entry.IsFlag =
(!entry.Target && entry.Item[0] == '-' && entry.Item[1] != 'l' &&
entry.Item.substr(0, 10) != "-framework");
// If the item has dependencies queue it to follow them.
if (entry.Target) {
@@ -395,7 +396,7 @@ void cmComputeLinkDepends::QueueSharedDependencies(
void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
{
// Check if the target already has an entry.
std::map<std::string, int>::iterator lei =
std::map<cmLinkItem, int>::iterator lei =
this->LinkEntryIndex.find(dep.Item);
if (lei == this->LinkEntryIndex.end()) {
// Allocate a spot for the item entry.
@@ -403,7 +404,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
// Initialize the item entry.
LinkEntry& entry = this->EntryList[lei->second];
entry.Item = dep.Item;
entry.Item = dep.Item.AsStr();
entry.Target = dep.Item.Target;
// This item was added specifically because it is a dependent
@@ -473,9 +474,9 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
// If the library is meant for this link type then use it.
if (llt == GENERAL_LibraryType || llt == this->LinkType) {
actual_libs.emplace_back(d, this->FindTargetToLink(depender_index, d));
actual_libs.emplace_back(this->ResolveLinkItem(depender_index, d));
} else if (this->OldLinkDirMode) {
cmLinkItem item(d, this->FindTargetToLink(depender_index, d));
cmLinkItem item = this->ResolveLinkItem(depender_index, d);
this->CheckWrongConfigItem(item);
}
@@ -512,7 +513,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
// Skip entries that will resolve to the target getting linked or
// are empty.
cmLinkItem const& item = l;
if (item == this->Target->GetName() || item.empty()) {
if (item.AsStr() == this->Target->GetName() || item.AsStr().empty()) {
continue;
}
@@ -553,8 +554,8 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
}
}
cmGeneratorTarget const* cmComputeLinkDepends::FindTargetToLink(
int depender_index, const std::string& name)
cmLinkItem cmComputeLinkDepends::ResolveLinkItem(int depender_index,
const std::string& name)
{
// Look for a target in the scope of the depender.
cmGeneratorTarget const* from = this->Target;
@@ -564,7 +565,7 @@ cmGeneratorTarget const* cmComputeLinkDepends::FindTargetToLink(
from = depender;
}
}
return from->FindTargetToLink(name);
return from->ResolveLinkItem(name);
}
void cmComputeLinkDepends::InferDependencies()
+4 -5
View File
@@ -72,19 +72,18 @@ private:
std::string Config;
EntryVector FinalLinkEntries;
std::map<std::string, int>::iterator AllocateLinkEntry(
std::string const& item);
std::map<cmLinkItem, int>::iterator AllocateLinkEntry(
cmLinkItem const& item);
int AddLinkEntry(cmLinkItem const& item);
void AddVarLinkEntries(int depender_index, const char* value);
void AddDirectLinkEntries();
template <typename T>
void AddLinkEntries(int depender_index, std::vector<T> const& libs);
cmGeneratorTarget const* FindTargetToLink(int depender_index,
const std::string& name);
cmLinkItem ResolveLinkItem(int depender_index, const std::string& name);
// One entry for each unique item.
std::vector<LinkEntry> EntryList;
std::map<std::string, int> LinkEntryIndex;
std::map<cmLinkItem, int> LinkEntryIndex;
// BFS of initial dependencies.
struct BFSEntry
+25 -21
View File
@@ -195,7 +195,7 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
// dependencies in all targets, because the generated build-systems can't
// deal with config-specific dependencies.
{
std::set<std::string> emitted;
std::set<cmLinkItem> emitted;
std::vector<std::string> configs;
depender->Makefile->GetConfigurations(configs);
@@ -206,27 +206,31 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
std::vector<cmSourceFile const*> objectFiles;
depender->GetExternalObjects(objectFiles, it);
for (cmSourceFile const* o : objectFiles) {
std::string objLib = o->GetObjectLibrary();
if (!objLib.empty() && emitted.insert(objLib).second) {
if (depender->GetType() != cmStateEnums::EXECUTABLE &&
depender->GetType() != cmStateEnums::STATIC_LIBRARY &&
depender->GetType() != cmStateEnums::SHARED_LIBRARY &&
depender->GetType() != cmStateEnums::MODULE_LIBRARY &&
depender->GetType() != cmStateEnums::OBJECT_LIBRARY) {
this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
cmake::FATAL_ERROR,
"Only executables and libraries may reference target objects.",
depender->GetBacktrace());
return;
std::string const& objLib = o->GetObjectLibrary();
if (!objLib.empty()) {
cmLinkItem const& objItem = depender->ResolveLinkItem(objLib);
if (emitted.insert(objItem).second) {
if (depender->GetType() != cmStateEnums::EXECUTABLE &&
depender->GetType() != cmStateEnums::STATIC_LIBRARY &&
depender->GetType() != cmStateEnums::SHARED_LIBRARY &&
depender->GetType() != cmStateEnums::MODULE_LIBRARY &&
depender->GetType() != cmStateEnums::OBJECT_LIBRARY) {
this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
cmake::FATAL_ERROR,
"Only executables and libraries may reference target objects.",
depender->GetBacktrace());
return;
}
const_cast<cmGeneratorTarget*>(depender)->Target->AddUtility(
objLib);
}
const_cast<cmGeneratorTarget*>(depender)->Target->AddUtility(objLib);
}
}
cmLinkImplementation const* impl = depender->GetLinkImplementation(it);
// A target should not depend on itself.
emitted.insert(depender->GetName());
emitted.insert(cmLinkItem(depender));
for (cmLinkImplItem const& lib : impl->Libraries) {
// Don't emit the same library twice for this target.
if (emitted.insert(lib).second) {
@@ -240,9 +244,9 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
// Loop over all utility dependencies.
{
std::set<cmLinkItem> const& tutils = depender->GetUtilityItems();
std::set<std::string> emitted;
std::set<cmLinkItem> emitted;
// A target should not depend on itself.
emitted.insert(depender->GetName());
emitted.insert(cmLinkItem(depender));
for (cmLinkItem const& litem : tutils) {
// Don't emit the same utility twice for this target.
if (emitted.insert(litem).second) {
@@ -254,7 +258,7 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
void cmComputeTargetDepends::AddInterfaceDepends(
int depender_index, const cmGeneratorTarget* dependee,
const std::string& config, std::set<std::string>& emitted)
const std::string& config, std::set<cmLinkItem>& emitted)
{
cmGeneratorTarget const* depender = this->Targets[depender_index];
if (cmLinkInterface const* iface =
@@ -271,7 +275,7 @@ void cmComputeTargetDepends::AddInterfaceDepends(
void cmComputeTargetDepends::AddInterfaceDepends(
int depender_index, cmLinkItem const& dependee_name,
const std::string& config, std::set<std::string>& emitted)
const std::string& config, std::set<cmLinkItem>& emitted)
{
cmGeneratorTarget const* depender = this->Targets[depender_index];
cmGeneratorTarget const* dependee = dependee_name.Target;
@@ -285,7 +289,7 @@ void cmComputeTargetDepends::AddInterfaceDepends(
if (dependee) {
// A target should not depend on itself.
emitted.insert(depender->GetName());
emitted.insert(cmLinkItem(depender));
this->AddInterfaceDepends(depender_index, dependee, config, emitted);
}
}
@@ -324,7 +328,7 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index,
<< depender->GetName() << "\" does not exist.";
cmListFileBacktrace const* backtrace =
depender->GetUtilityBacktrace(dependee_name);
depender->GetUtilityBacktrace(dependee_name.AsStr());
if (backtrace) {
cm->IssueMessage(messageType, e.str(), *backtrace);
} else {
+2 -2
View File
@@ -51,11 +51,11 @@ private:
bool ComputeFinalDepends(cmComputeComponentGraph const& ccg);
void AddInterfaceDepends(int depender_index, cmLinkItem const& dependee_name,
const std::string& config,
std::set<std::string>& emitted);
std::set<cmLinkItem>& emitted);
void AddInterfaceDepends(int depender_index,
cmGeneratorTarget const* dependee,
const std::string& config,
std::set<std::string>& emitted);
std::set<cmLinkItem>& emitted);
cmGlobalGenerator* GlobalGenerator;
bool DebugMode;
bool NoCycles;
+1 -1
View File
@@ -108,7 +108,7 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
// build type of the makefile
cmGeneratorExpression ge;
cmGeneratorExpressionDAGChecker dagChecker(
target->GetName(), "INTERFACE_LINK_LIBRARIES", nullptr, nullptr);
target, "INTERFACE_LINK_LIBRARIES", nullptr, nullptr);
std::unique_ptr<cmCompiledGeneratorExpression> cge =
ge.Parse(property.second);
std::string evaluated = cge->Evaluate(
+11 -1
View File
@@ -831,6 +831,16 @@ void cmExportFileGenerator::SetImportDetailProperties(
}
}
static std::string const& asString(std::string const& l)
{
return l;
}
static std::string const& asString(cmLinkItem const& l)
{
return l.AsStr();
}
template <typename T>
void cmExportFileGenerator::SetImportLinkProperty(
std::string const& suffix, cmGeneratorTarget* target,
@@ -850,7 +860,7 @@ void cmExportFileGenerator::SetImportLinkProperty(
link_entries += sep;
sep = ";";
std::string temp = l;
std::string temp = asString(l);
this->AddTargetNamespace(temp, target, missingTargets);
link_entries += temp;
}
+1 -2
View File
@@ -65,8 +65,7 @@ std::string cmExportTryCompileFileGenerator::FindTargets(
cmGeneratorExpression ge;
cmGeneratorExpressionDAGChecker dagChecker(tgt->GetName(), propName, nullptr,
nullptr);
cmGeneratorExpressionDAGChecker dagChecker(tgt, propName, nullptr, nullptr);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
+6 -6
View File
@@ -354,8 +354,8 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
lg->GetTargetCompileFlags(gtgt, config, language, flags);
// Add source file specific flags.
cmGeneratorExpressionInterpreter genexInterpreter(lg, gtgt, config,
gtgt->GetName(), language);
cmGeneratorExpressionInterpreter genexInterpreter(lg, config, gtgt,
language);
const std::string COMPILE_FLAGS("COMPILE_FLAGS");
if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) {
@@ -381,8 +381,8 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines(
cmMakefile* makefile = lg->GetMakefile();
const std::string& language = source->GetLanguage();
const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
cmGeneratorExpressionInterpreter genexInterpreter(
lg, target, config, target->GetName(), language);
cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target,
language);
// Add the export symbol definition for shared library objects.
if (const char* exportMacro = target->GetExportMacro()) {
@@ -419,8 +419,8 @@ std::string cmExtraSublimeTextGenerator::ComputeIncludes(
cmMakefile* makefile = lg->GetMakefile();
const std::string& language = source->GetLanguage();
const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
cmGeneratorExpressionInterpreter genexInterpreter(
lg, target, config, target->GetName(), language);
cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target,
language);
// Add include directories for this source file
const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+8 -6
View File
@@ -389,14 +389,16 @@ void cmCompiledGeneratorExpression::GetMaxLanguageStandard(
const std::string& cmGeneratorExpressionInterpreter::Evaluate(
const char* expression, const std::string& property)
{
if (this->Target.empty()) {
return this->EvaluateExpression(expression);
}
this->CompiledGeneratorExpression =
this->GeneratorExpression.Parse(expression);
// Specify COMPILE_OPTIONS to DAGchecker, same semantic as COMPILE_FLAGS
cmGeneratorExpressionDAGChecker dagChecker(
this->Target, property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property,
nullptr, nullptr);
this->HeadTarget,
property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property, nullptr,
nullptr);
return this->EvaluateExpression(expression, &dagChecker);
return this->CompiledGeneratorExpression->Evaluate(
this->LocalGenerator, this->Config, false, this->HeadTarget, &dagChecker,
this->Language);
}
+5 -50
View File
@@ -160,24 +160,15 @@ class cmGeneratorExpressionInterpreter
public:
cmGeneratorExpressionInterpreter(cmLocalGenerator* localGenerator,
cmGeneratorTarget* generatorTarget,
const std::string& config,
const std::string& target,
const std::string& lang)
std::string const& config,
cmGeneratorTarget const* headTarget,
std::string const& lang = std::string())
: LocalGenerator(localGenerator)
, GeneratorTarget(generatorTarget)
, Config(config)
, Target(target)
, HeadTarget(headTarget)
, Language(lang)
{
}
cmGeneratorExpressionInterpreter(cmLocalGenerator* localGenerator,
cmGeneratorTarget* generatorTarget,
const std::string& config)
: cmGeneratorExpressionInterpreter(localGenerator, generatorTarget, config,
std::string(), std::string())
{
}
const std::string& Evaluate(const char* expression,
const std::string& property);
@@ -188,47 +179,11 @@ public:
}
protected:
cmGeneratorExpression& GetGeneratorExpression()
{
return this->GeneratorExpression;
}
cmCompiledGeneratorExpression& GetCompiledGeneratorExpression()
{
return *(this->CompiledGeneratorExpression);
}
cmLocalGenerator* GetLocalGenerator() { return this->LocalGenerator; }
cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
const std::string& GetTargetName() const { return this->Target; }
const std::string& GetLanguage() const { return this->Language; }
const std::string& EvaluateExpression(
const char* expression,
cmGeneratorExpressionDAGChecker* dagChecker = nullptr)
{
this->CompiledGeneratorExpression =
this->GeneratorExpression.Parse(expression);
if (dagChecker == nullptr) {
return this->CompiledGeneratorExpression->Evaluate(
this->LocalGenerator, this->Config, false, this->GeneratorTarget);
}
return this->CompiledGeneratorExpression->Evaluate(
this->LocalGenerator, this->Config, false, this->GeneratorTarget,
dagChecker, this->Language);
}
private:
cmGeneratorExpression GeneratorExpression;
std::unique_ptr<cmCompiledGeneratorExpression> CompiledGeneratorExpression;
cmLocalGenerator* LocalGenerator = nullptr;
cmGeneratorTarget* GeneratorTarget = nullptr;
std::string Config;
std::string Target;
cmGeneratorTarget const* HeadTarget = nullptr;
std::string Language;
};
+7 -6
View File
@@ -14,7 +14,7 @@
#include <utility>
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
const cmListFileBacktrace& backtrace, const std::string& target,
const cmListFileBacktrace& backtrace, cmGeneratorTarget const* target,
const std::string& property, const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* parent)
: Parent(parent)
@@ -28,7 +28,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
}
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
const std::string& target, const std::string& property,
cmGeneratorTarget const* target, const std::string& property,
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* parent)
: Parent(parent)
@@ -58,8 +58,8 @@ void cmGeneratorExpressionDAGChecker::Initialize()
TEST_TRANSITIVE_PROPERTY_METHOD) false)) // NOLINT(clang-tidy)
#undef TEST_TRANSITIVE_PROPERTY_METHOD
{
std::map<std::string, std::set<std::string>>::const_iterator it =
top->Seen.find(this->Target);
std::map<cmGeneratorTarget const*, std::set<std::string>>::const_iterator
it = top->Seen.find(this->Target);
if (it != top->Seen.end()) {
const std::set<std::string>& propSet = it->second;
if (propSet.find(this->Property) != propSet.end()) {
@@ -166,7 +166,8 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression()
return top->Property == "TARGET_GENEX_EVAL" || top->Property == "GENEX_EVAL";
}
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(const char* tgt)
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
cmGeneratorTarget const* tgt)
{
const cmGeneratorExpressionDAGChecker* top = this;
const cmGeneratorExpressionDAGChecker* parent = this->Parent;
@@ -189,7 +190,7 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(const char* tgt)
strcmp(prop, "INTERFACE_LINK_LIBRARIES") == 0;
}
std::string cmGeneratorExpressionDAGChecker::TopTarget() const
cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const
{
const cmGeneratorExpressionDAGChecker* top = this;
const cmGeneratorExpressionDAGChecker* parent = this->Parent;
+7 -6
View File
@@ -13,6 +13,7 @@
struct GeneratorExpressionContent;
struct cmGeneratorExpressionContext;
class cmGeneratorTarget;
#define CM_SELECT_BOTH(F, A1, A2) F(A1, A2)
#define CM_SELECT_FIRST(F, A1, A2) F(A1)
@@ -41,11 +42,11 @@ struct cmGeneratorExpressionContext;
struct cmGeneratorExpressionDAGChecker
{
cmGeneratorExpressionDAGChecker(const cmListFileBacktrace& backtrace,
const std::string& target,
cmGeneratorTarget const* target,
const std::string& property,
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* parent);
cmGeneratorExpressionDAGChecker(const std::string& target,
cmGeneratorExpressionDAGChecker(cmGeneratorTarget const* target,
const std::string& property,
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* parent);
@@ -64,7 +65,7 @@ struct cmGeneratorExpressionDAGChecker
const std::string& expr);
bool EvaluatingGenexExpression();
bool EvaluatingLinkLibraries(const char* tgt = nullptr);
bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr);
#define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const;
@@ -75,7 +76,7 @@ struct cmGeneratorExpressionDAGChecker
bool GetTransitivePropertiesOnly();
void SetTransitivePropertiesOnly() { this->TransitivePropertiesOnly = true; }
std::string TopTarget() const;
cmGeneratorTarget const* TopTarget() const;
private:
Result CheckGraph() const;
@@ -83,9 +84,9 @@ private:
private:
const cmGeneratorExpressionDAGChecker* const Parent;
const std::string Target;
cmGeneratorTarget const* Target;
const std::string Property;
std::map<std::string, std::set<std::string>> Seen;
std::map<cmGeneratorTarget const*, std::set<std::string>> Seen;
const GeneratorExpressionContent* const Content;
const cmListFileBacktrace Backtrace;
Result CheckResult;
+6 -7
View File
@@ -378,8 +378,8 @@ protected:
{
if (context->HeadTarget) {
cmGeneratorExpressionDAGChecker dagChecker(
context->Backtrace, context->HeadTarget->GetName(), genexOperator,
content, dagCheckerParent);
context->Backtrace, context->HeadTarget, genexOperator, content,
dagCheckerParent);
switch (dagChecker.Check()) {
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: {
@@ -1196,9 +1196,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
return target->GetLinkerLanguage(context->Config);
}
cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
target->GetName(), propertyName,
content, dagCheckerParent);
cmGeneratorExpressionDAGChecker dagChecker(
context->Backtrace, target, propertyName, content, dagCheckerParent);
switch (dagChecker.Check()) {
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
@@ -1911,9 +1910,9 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
return std::string();
}
if (dagChecker &&
(dagChecker->EvaluatingLinkLibraries(name.c_str()) ||
(dagChecker->EvaluatingLinkLibraries(target) ||
(dagChecker->EvaluatingSources() &&
name == dagChecker->TopTarget()))) {
target == dagChecker->TopTarget()))) {
::reportError(context, content->GetOriginalExpression(),
"Expressions which require the linker language may not "
"be used while evaluating link libraries");
+46 -41
View File
@@ -671,9 +671,12 @@ std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
this->UtilityItemsDone = true;
std::set<std::string> const& utilities = this->GetUtilities();
for (std::string const& i : utilities) {
cmGeneratorTarget* gt =
this->LocalGenerator->FindGeneratorTargetToUse(i);
this->UtilityItems.insert(cmLinkItem(i, gt));
if (cmGeneratorTarget* gt =
this->LocalGenerator->FindGeneratorTargetToUse(i)) {
this->UtilityItems.insert(cmLinkItem(gt));
} else {
this->UtilityItems.insert(cmLinkItem(i));
}
}
}
return this->UtilityItems;
@@ -770,7 +773,7 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(
if (iter == this->SystemIncludesCache.end()) {
cmGeneratorExpressionDAGChecker dagChecker(
this->GetName(), "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
@@ -816,7 +819,8 @@ static void AddInterfaceEntries(
thisTarget->GetLinkImplementationLibraries(config)) {
for (cmLinkImplItem const& lib : impl->Libraries) {
if (lib.Target) {
std::string genex = "$<TARGET_PROPERTY:" + lib + "," + prop + ">";
std::string genex =
"$<TARGET_PROPERTY:" + lib.AsStr() + "," + prop + ">";
cmGeneratorExpression ge(lib.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
cge->SetEvaluateForBuildsystem(true);
@@ -836,7 +840,7 @@ static void AddObjectEntries(
for (cmLinkImplItem const& lib : impl->Libraries) {
if (lib.Target &&
lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
std::string genex = "$<TARGET_OBJECTS:" + lib + ">";
std::string genex = "$<TARGET_OBJECTS:" + lib.AsStr() + ">";
cmGeneratorExpression ge(lib.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
cge->SetEvaluateForBuildsystem(true);
@@ -860,7 +864,7 @@ static bool processSources(
for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
cmLinkImplItem const& item = entry->LinkImplItem;
std::string const& targetName = item;
std::string const& targetName = item.AsStr();
std::vector<std::string> entrySources;
cmSystemTools::ExpandListArgument(
entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt, tgt,
@@ -960,8 +964,8 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files,
this->DebugSourcesDone = true;
}
cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), "SOURCES",
nullptr, nullptr);
cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr,
nullptr);
std::unordered_set<std::string> uniqueSrcs;
bool contextDependentDirectSources =
@@ -1756,7 +1760,7 @@ public:
void Visit(cmLinkItem const& item)
{
if (!item.Target) {
if (item.find("::") != std::string::npos) {
if (item.AsStr().find("::") != std::string::npos) {
bool noMessage = false;
cmake::MessageType messageType = cmake::FATAL_ERROR;
std::ostringstream e;
@@ -1777,7 +1781,7 @@ public:
if (!noMessage) {
e << "Target \"" << this->Target->GetName()
<< "\" links to target \"" << item
<< "\" links to target \"" << item.AsStr()
<< "\" but the target was not found. Perhaps a find_package() "
"call is missing for an IMPORTED target, or an ALIAS target is "
"missing?";
@@ -2074,8 +2078,8 @@ void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result,
}
cmGeneratorExpression ge;
cmGeneratorExpressionDAGChecker dagChecker(
this->GetName(), "AUTOUIC_OPTIONS", nullptr, nullptr);
cmGeneratorExpressionDAGChecker dagChecker(this, "AUTOUIC_OPTIONS", nullptr,
nullptr);
cmSystemTools::ExpandListArgument(
ge.Parse(prop)->Evaluate(this->LocalGenerator, config, false, this,
&dagChecker),
@@ -2477,7 +2481,7 @@ static void processIncludeDirectories(
{
for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
cmLinkImplItem const& item = entry->LinkImplItem;
std::string const& targetName = item;
std::string const& targetName = item.AsStr();
bool const fromImported = item.Target && item.Target->IsImported();
bool const checkCMP0027 = item.FromGenex;
std::vector<std::string> entryIncludes;
@@ -2584,8 +2588,8 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories(
std::vector<std::string> includes;
std::unordered_set<std::string> uniqueIncludes;
cmGeneratorExpressionDAGChecker dagChecker(
this->GetName(), "INCLUDE_DIRECTORIES", nullptr, nullptr);
cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES",
nullptr, nullptr);
std::vector<std::string> debugProperties;
const char* debugProp =
@@ -2615,7 +2619,7 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories(
cmLinkImplementationLibraries const* impl =
this->GetLinkImplementationLibraries(config);
for (cmLinkImplItem const& lib : impl->Libraries) {
std::string libDir = cmSystemTools::CollapseFullPath(lib);
std::string libDir = cmSystemTools::CollapseFullPath(lib.AsStr());
static cmsys::RegularExpression frameworkCheck(
"(.*\\.framework)(/Versions/[^/]+)?/[^/]+$");
@@ -2706,8 +2710,8 @@ void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
{
std::unordered_set<std::string> uniqueOptions;
cmGeneratorExpressionDAGChecker dagChecker(
this->GetName(), "COMPILE_OPTIONS", nullptr, nullptr);
cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr,
nullptr);
std::vector<std::string> debugProperties;
const char* debugProp =
@@ -2759,8 +2763,8 @@ void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
{
std::unordered_set<std::string> uniqueFeatures;
cmGeneratorExpressionDAGChecker dagChecker(
this->GetName(), "COMPILE_FEATURES", nullptr, nullptr);
cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr,
nullptr);
std::vector<std::string> debugProperties;
const char* debugProp =
@@ -2810,8 +2814,8 @@ void cmGeneratorTarget::GetCompileDefinitions(
{
std::unordered_set<std::string> uniqueOptions;
cmGeneratorExpressionDAGChecker dagChecker(
this->GetName(), "COMPILE_DEFINITIONS", nullptr, nullptr);
cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS",
nullptr, nullptr);
std::vector<std::string> debugProperties;
const char* debugProp =
@@ -2891,8 +2895,8 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
{
std::unordered_set<std::string> uniqueOptions;
cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), "LINK_OPTIONS",
nullptr, nullptr);
cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr,
nullptr);
std::vector<std::string> debugProperties;
const char* debugProp =
@@ -3039,8 +3043,8 @@ void cmGeneratorTarget::GetStaticLibraryLinkOptions(
std::vector<cmGeneratorTarget::TargetPropertyEntry*> entries;
std::unordered_set<std::string> uniqueOptions;
cmGeneratorExpressionDAGChecker dagChecker(
this->GetName(), "STATIC_LIBRARY_OPTIONS", nullptr, nullptr);
cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS",
nullptr, nullptr);
if (const char* linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
std::vector<std::string> options;
@@ -3079,8 +3083,8 @@ void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result,
{
std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkDependsEntries;
std::unordered_set<std::string> uniqueOptions;
cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), "LINK_DEPENDS",
nullptr, nullptr);
cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr,
nullptr);
if (const char* linkDepends = this->GetProperty("LINK_DEPENDS")) {
std::vector<std::string> depends;
@@ -4495,7 +4499,7 @@ void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names,
if (name == this->GetName() || name.empty()) {
continue;
}
items.emplace_back(name, this->FindTargetToLink(name));
items.push_back(this->ResolveLinkItem(name));
}
}
@@ -4505,8 +4509,7 @@ void cmGeneratorTarget::ExpandLinkItems(
std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition) const
{
cmGeneratorExpression ge;
cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), prop, nullptr,
nullptr);
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.
if (usage_requirements_only) {
@@ -4571,7 +4574,7 @@ void cmGeneratorTarget::ComputeLinkInterface(
this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
// Shared libraries may have runtime implementation dependencies
// on other shared libraries that are not in the interface.
std::unordered_set<std::string> emitted;
std::set<cmLinkItem> emitted;
for (cmLinkItem const& lib : iface.Libraries) {
emitted.insert(lib);
}
@@ -5557,8 +5560,8 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
end = entryRange.end();
le != end; ++le, ++btIt) {
std::vector<std::string> llibs;
cmGeneratorExpressionDAGChecker dagChecker(
this->GetName(), "LINK_LIBRARIES", nullptr, nullptr);
cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
nullptr);
cmGeneratorExpression ge(*btIt);
std::unique_ptr<cmCompiledGeneratorExpression> const cge = ge.Parse(*le);
std::string const& evaluated =
@@ -5603,7 +5606,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
}
// The entry is meant for this configuration.
impl.Libraries.emplace_back(name, this->FindTargetToLink(name), *btIt,
impl.Libraries.emplace_back(this->ResolveLinkItem(name), *btIt,
evaluated != *le);
}
@@ -5631,14 +5634,12 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
continue;
}
// Support OLD behavior for CMP0003.
impl.WrongConfigLibraries.emplace_back(name,
this->FindTargetToLink(name));
impl.WrongConfigLibraries.push_back(this->ResolveLinkItem(name));
}
}
}
cmGeneratorTarget* cmGeneratorTarget::FindTargetToLink(
std::string const& name) const
cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name) const
{
cmGeneratorTarget* tgt =
this->LocalGenerator->FindGeneratorTargetToUse(name);
@@ -5651,7 +5652,11 @@ cmGeneratorTarget* cmGeneratorTarget::FindTargetToLink(
tgt = nullptr;
}
return tgt;
if (tgt) {
return cmLinkItem(tgt);
}
return cmLinkItem(name);
}
std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
+1 -1
View File
@@ -357,7 +357,7 @@ public:
cmOptionalLinkImplementation& impl,
const cmGeneratorTarget* head) const;
cmGeneratorTarget* FindTargetToLink(std::string const& name) const;
cmLinkItem ResolveLinkItem(std::string const& name) const;
// Compute the set of languages compiled by the target. This is
// computed every time it is called because the languages can change
+5 -7
View File
@@ -751,11 +751,10 @@ class XCodeGeneratorExpressionInterpreter
public:
XCodeGeneratorExpressionInterpreter(cmSourceFile* sourceFile,
cmLocalGenerator* localGenerator,
cmGeneratorTarget* generatorTarget,
cmGeneratorTarget* headTarget,
const std::string& lang)
: cmGeneratorExpressionInterpreter(localGenerator, generatorTarget,
"NO-PER-CONFIG-SUPPORT-IN-XCODE",
generatorTarget->GetName(), lang)
: cmGeneratorExpressionInterpreter(
localGenerator, "NO-PER-CONFIG-SUPPORT-IN-XCODE", headTarget, lang)
, SourceFile(sourceFile)
{
}
@@ -767,8 +766,7 @@ public:
{
const std::string& processed =
this->cmGeneratorExpressionInterpreter::Evaluate(expression, property);
if (this->GetCompiledGeneratorExpression()
.GetHadContextSensitiveCondition()) {
if (this->CompiledGeneratorExpression->GetHadContextSensitiveCondition()) {
std::ostringstream e;
/* clang-format off */
e <<
@@ -777,7 +775,7 @@ public:
"specified for source:\n"
" " << this->SourceFile->GetFullPath() << "\n";
/* clang-format on */
this->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, e.str());
this->LocalGenerator->IssueMessage(cmake::FATAL_ERROR, e.str());
}
return processed;
+72
View File
@@ -0,0 +1,72 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLinkItem.h"
#include "cmGeneratorTarget.h"
#include <utility> // IWYU pragma: keep
cmLinkItem::cmLinkItem()
: String()
, Target(nullptr)
{
}
cmLinkItem::cmLinkItem(std::string const& n)
: String(n)
, Target(nullptr)
{
}
cmLinkItem::cmLinkItem(cmGeneratorTarget const* t)
: String()
, Target(t)
{
}
std::string const& cmLinkItem::AsStr() const
{
return this->Target ? this->Target->GetName() : this->String;
}
bool operator<(cmLinkItem const& l, cmLinkItem const& r)
{
// Order among targets.
if (l.Target && r.Target) {
return l.Target < r.Target;
}
// Order targets before strings.
if (l.Target) {
return true;
}
if (r.Target) {
return false;
}
// Order among strings.
return l.String < r.String;
}
bool operator==(cmLinkItem const& l, cmLinkItem const& r)
{
return l.Target == r.Target && l.String == r.String;
}
std::ostream& operator<<(std::ostream& os, cmLinkItem const& item)
{
return os << item.AsStr();
}
cmLinkImplItem::cmLinkImplItem()
: cmLinkItem()
, Backtrace()
, FromGenex(false)
{
}
cmLinkImplItem::cmLinkImplItem(cmLinkItem item, cmListFileBacktrace const& bt,
bool fromGenex)
: cmLinkItem(std::move(item))
, Backtrace(bt)
, FromGenex(fromGenex)
{
}
+13 -25
View File
@@ -7,6 +7,7 @@
#include <algorithm>
#include <map>
#include <ostream>
#include <string>
#include <vector>
@@ -17,40 +18,27 @@
class cmGeneratorTarget;
// Basic information about each link item.
class cmLinkItem : public std::string
class cmLinkItem
{
typedef std::string std_string;
std::string String;
public:
cmLinkItem()
: std_string()
, Target(nullptr)
{
}
cmLinkItem(const std_string& n, cmGeneratorTarget const* t)
: std_string(n)
, Target(t)
{
}
cmLinkItem();
explicit cmLinkItem(std::string const& s);
explicit cmLinkItem(cmGeneratorTarget const* t);
std::string const& AsStr() const;
cmGeneratorTarget const* Target;
friend bool operator<(cmLinkItem const& l, cmLinkItem const& r);
friend bool operator==(cmLinkItem const& l, cmLinkItem const& r);
friend std::ostream& operator<<(std::ostream& os, cmLinkItem const& item);
};
class cmLinkImplItem : public cmLinkItem
{
public:
cmLinkImplItem()
: cmLinkItem()
, Backtrace()
, FromGenex(false)
{
}
cmLinkImplItem(std::string const& n, cmGeneratorTarget const* t,
cmListFileBacktrace const& bt, bool fromGenex)
: cmLinkItem(n, t)
, Backtrace(bt)
, FromGenex(fromGenex)
{
}
cmLinkImplItem();
cmLinkImplItem(cmLinkItem item, cmListFileBacktrace const& bt,
bool fromGenex);
cmListFileBacktrace Backtrace;
bool FromGenex;
};
+1 -2
View File
@@ -1497,8 +1497,7 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
lang = sourceLang;
}
cmGeneratorExpressionInterpreter genexInterpreter(lg, gt, *i,
gt->GetName(), lang);
cmGeneratorExpressionInterpreter genexInterpreter(lg, *i, gt, lang);
bool needfc = false;
if (!objectName.empty()) {
+1 -2
View File
@@ -434,8 +434,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
std::string config = this->LocalGenerator->GetConfigName();
std::string configUpper = cmSystemTools::UpperCase(config);
cmGeneratorExpressionInterpreter genexInterpreter(
this->LocalGenerator, this->GeneratorTarget, config,
this->GeneratorTarget->GetName(), lang);
this->LocalGenerator, config, this->GeneratorTarget, lang);
// Add Fortran format flags.
if (lang == "Fortran") {
+4 -7
View File
@@ -136,9 +136,8 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
// Add source file specific flags.
cmGeneratorExpressionInterpreter genexInterpreter(
this->LocalGenerator, this->GeneratorTarget,
this->LocalGenerator->GetConfigName(), this->GeneratorTarget->GetName(),
language);
this->LocalGenerator, this->LocalGenerator->GetConfigName(),
this->GeneratorTarget, language);
const std::string COMPILE_FLAGS("COMPILE_FLAGS");
if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) {
@@ -188,8 +187,7 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
std::set<std::string> defines;
const std::string config = this->LocalGenerator->GetConfigName();
cmGeneratorExpressionInterpreter genexInterpreter(
this->LocalGenerator, this->GeneratorTarget, config,
this->GeneratorTarget->GetName(), language);
this->LocalGenerator, config, this->GeneratorTarget, language);
const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
@@ -217,8 +215,7 @@ std::string cmNinjaTargetGenerator::ComputeIncludes(
std::vector<std::string> includes;
const std::string config = this->LocalGenerator->GetConfigName();
cmGeneratorExpressionInterpreter genexInterpreter(
this->LocalGenerator, this->GeneratorTarget, config,
this->GeneratorTarget->GetName(), language);
this->LocalGenerator, config, this->GeneratorTarget, language);
const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
if (const char* cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) {
+4 -5
View File
@@ -722,8 +722,8 @@ static void PopulateFileGroupData(
? languageDataMap.at(kInterfaceSourcesLanguageDataKey)
: languageDataMap.at(fileData.Language);
cmLocalGenerator* lg = target->GetLocalGenerator();
cmGeneratorExpressionInterpreter genexInterpreter(
lg, target, config, target->GetName(), fileData.Language);
cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target,
fileData.Language);
std::string compileFlags = ld.Flags;
const std::string COMPILE_FLAGS("COMPILE_FLAGS");
@@ -817,7 +817,7 @@ static Json::Value DumpSourceFilesList(
auto targetProp = target->Target->GetProperty("INTERFACE_SOURCES");
if (targetProp != nullptr) {
cmGeneratorExpressionInterpreter genexInterpreter(
target->GetLocalGenerator(), target, config, target->GetName(), "");
target->GetLocalGenerator(), config, target);
auto evaluatedSources = cmsys::SystemTools::SplitString(
genexInterpreter.Evaluate(targetProp, "INTERFACE_SOURCES"), ';');
@@ -977,8 +977,7 @@ static void CreateInterfaceSourcesEntry(
LanguageData& ld = languageDataMap[kInterfaceSourcesLanguageDataKey];
ld.Language = "";
cmGeneratorExpressionInterpreter genexInterpreter(lg, target, config,
target->GetName(), "");
cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target);
std::vector<std::string> propertyValue;
GetTargetProperty(genexInterpreter, target, "INTERFACE_INCLUDE_DIRECTORIES",
propertyValue);
+1 -2
View File
@@ -2117,8 +2117,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
flagtable = gg->GetCSharpFlagTable();
}
cmGeneratorExpressionInterpreter genexInterpreter(
this->LocalGenerator, this->GeneratorTarget, config,
this->GeneratorTarget->GetName(), lang);
this->LocalGenerator, config, this->GeneratorTarget, lang);
cmVS10GeneratorOptions clOptions(
this->LocalGenerator, cmVisualStudioGeneratorOptions::Compiler,
flagtable, this);
+1
View File
@@ -396,6 +396,7 @@ if(BUILD_TESTING)
ADD_TEST_MACRO(CompatibleInterface CompatibleInterface)
ADD_TEST_MACRO(AliasTarget AliasTarget)
ADD_TEST_MACRO(StagingPrefix StagingPrefix)
ADD_TEST_MACRO(ImportedSameName ImportedSameName)
ADD_TEST_MACRO(InterfaceLibrary InterfaceLibrary)
if (CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
set(ConfigSources_BUILD_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+8
View File
@@ -0,0 +1,8 @@
add_library(a STATIC a.c)
target_compile_definitions(a INTERFACE DEF_A)
add_library(sameName INTERFACE IMPORTED)
target_link_libraries(sameName INTERFACE a)
add_library(ifaceA INTERFACE)
target_link_libraries(ifaceA INTERFACE sameName)
+3
View File
@@ -0,0 +1,3 @@
void a(void)
{
}
+8
View File
@@ -0,0 +1,8 @@
add_library(b STATIC b.c)
target_compile_definitions(b INTERFACE DEF_B)
add_library(sameName INTERFACE IMPORTED)
target_link_libraries(sameName INTERFACE b)
add_library(ifaceB INTERFACE)
target_link_libraries(ifaceB INTERFACE sameName)
+3
View File
@@ -0,0 +1,3 @@
void b(void)
{
}
+8
View File
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.12)
project(ImportedSameName C)
add_subdirectory(A)
add_subdirectory(B)
add_executable(ImportedSameName main.c)
target_link_libraries(ImportedSameName PRIVATE ifaceA ifaceB)
+16
View File
@@ -0,0 +1,16 @@
#ifndef DEF_A
# error "DEF_A not defined"
#endif
#ifndef DEF_B
# error "DEF_B not defined"
#endif
extern void a(void);
extern void b(void);
int main(void)
{
a();
b();
return 0;
}
+1
View File
@@ -352,6 +352,7 @@ CMAKE_CXX_SOURCES="\
cmInstallTargetsCommand \
cmInstalledFile \
cmLinkDirectoriesCommand \
cmLinkItem \
cmLinkLineComputer \
cmListCommand \
cmListFileCache \