Merge topic 'minor-cleanups'

84fac67 Don't allow include() of export(EXPORT) file at configure time.
faedd2b cmTarget: Fix system include annotation propagation.
9eb06d0 add_library: Disallow invalid signatures for INTERFACE_LIBRARY.
10d65d5 cmTarget: Move a variable initialization closer to where it is used.
0f3e8e9 Undefine local preprocessor loop variables.
9ba47ee Genex: Reform error-checking for nullary/unary expressions.
fa651c7 cmTarget: Remove some of the INTERFACE_LIBRARY whitelisted properties.
61d138a cmTarget: INTERFACE_LIBRARY is always EXCLUDE_FROM_ALL.
3429541 export: Rename some variables to reflect content type.
7461d67 cmTarget: Enable convenient include dir handling for INTERFACE_LIBRARY.
7fc6e3d cmTarget: Remove dead code.
2af966d Genex: Add EQUAL expression.
2d66380 cmTarget: Use strtol for numeric parsing.
This commit is contained in:
Brad King 2014-01-06 11:43:12 -05:00 committed by CMake Topic Stage
commit dc08199848
34 changed files with 582 additions and 156 deletions

View File

@ -109,12 +109,21 @@ The signature
::
add_library(<name> INTERFACE)
add_library(<name> INTERFACE [IMPORTED [GLOBAL]])
creates an interface target. An interface target does not directly
create build output, though it may have properties set on it and it
may be installed, exported and imported. Typically the INTERFACE_*
properties are populated on the interface target using the
set_property(), target_link_libraries(), target_include_directories()
and target_compile_defintions() commands, and then it is used as an
argument to target_link_libraries() like any other target.
:command:`set_property`, :command:`target_link_libraries`,
:command:`target_include_directories`
and :command:`target_compile_defintions` commands, and then it is used as an
argument to :command:`target_link_libraries` like any other target.
An ``INTERFACE`` :prop_tgt:`IMPORTED` target may also be created with this
signature. An :prop_tgt:`IMPORTED` library target references a library defined
outside the project. The target name has scope in the directory in which it is
created and below, but the ``GLOBAL`` option extends visibility. It may be
referenced like any target built within the project. :prop_tgt:`IMPORTED`
libraries are useful for convenient reference from commands like
:command:`target_link_libraries`.

View File

@ -55,6 +55,8 @@ otherwise expands to nothing.
``0`` if ``?`` is ``1``, else ``1``
``$<STREQUAL:a,b>``
``1`` if ``a`` is STREQUAL ``b``, else ``0``
``$<EQUAL:a,b>``
``1`` if ``a`` is EQUAL ``b`` in a numeric comparison, else ``0``
``$<CONFIG:cfg>``
``1`` if config is ``cfg``, else ``0``. This is a case-insensitive comparison.
The mapping in :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` is also considered by

View File

@ -49,47 +49,117 @@ bool cmAddLibraryCommand
std::string libType = *s;
if(libType == "STATIC")
{
if (type == cmTarget::INTERFACE_LIBRARY)
{
cmOStringStream e;
e << "INTERFACE library specified with conflicting STATIC type.";
this->SetError(e.str().c_str());
return false;
}
++s;
type = cmTarget::STATIC_LIBRARY;
haveSpecifiedType = true;
}
else if(libType == "SHARED")
{
if (type == cmTarget::INTERFACE_LIBRARY)
{
cmOStringStream e;
e << "INTERFACE library specified with conflicting SHARED type.";
this->SetError(e.str().c_str());
return false;
}
++s;
type = cmTarget::SHARED_LIBRARY;
haveSpecifiedType = true;
}
else if(libType == "MODULE")
{
if (type == cmTarget::INTERFACE_LIBRARY)
{
cmOStringStream e;
e << "INTERFACE library specified with conflicting MODULE type.";
this->SetError(e.str().c_str());
return false;
}
++s;
type = cmTarget::MODULE_LIBRARY;
haveSpecifiedType = true;
}
else if(libType == "OBJECT")
{
if (type == cmTarget::INTERFACE_LIBRARY)
{
cmOStringStream e;
e << "INTERFACE library specified with conflicting OBJECT type.";
this->SetError(e.str().c_str());
return false;
}
++s;
type = cmTarget::OBJECT_LIBRARY;
haveSpecifiedType = true;
}
else if(libType == "UNKNOWN")
{
if (type == cmTarget::INTERFACE_LIBRARY)
{
cmOStringStream e;
e << "INTERFACE library specified with conflicting UNKNOWN type.";
this->SetError(e.str().c_str());
return false;
}
++s;
type = cmTarget::UNKNOWN_LIBRARY;
haveSpecifiedType = true;
}
else if(libType == "ALIAS")
{
if (type == cmTarget::INTERFACE_LIBRARY)
{
cmOStringStream e;
e << "INTERFACE library specified with conflicting ALIAS type.";
this->SetError(e.str().c_str());
return false;
}
++s;
isAlias = true;
}
else if(libType == "INTERFACE")
{
if (haveSpecifiedType)
{
cmOStringStream e;
e << "INTERFACE library specified with conflicting/multiple types.";
this->SetError(e.str().c_str());
return false;
}
if (isAlias)
{
cmOStringStream e;
e << "INTERFACE library specified with conflicting ALIAS type.";
this->SetError(e.str().c_str());
return false;
}
if (excludeFromAll)
{
cmOStringStream e;
e << "INTERFACE library may not be used with EXCLUDE_FROM_ALL.";
this->SetError(e.str().c_str());
return false;
}
++s;
type = cmTarget::INTERFACE_LIBRARY;
haveSpecifiedType = true;
}
else if(*s == "EXCLUDE_FROM_ALL")
{
if (type == cmTarget::INTERFACE_LIBRARY)
{
cmOStringStream e;
e << "INTERFACE library may not be used with EXCLUDE_FROM_ALL.";
this->SetError(e.str().c_str());
return false;
}
++s;
excludeFromAll = true;
}
@ -109,6 +179,24 @@ bool cmAddLibraryCommand
}
}
if (type == cmTarget::INTERFACE_LIBRARY)
{
if (s != args.end())
{
cmOStringStream e;
e << "INTERFACE library requires no source arguments.";
this->SetError(e.str().c_str());
return false;
}
if (importGlobal && !importTarget)
{
cmOStringStream e;
e << "INTERFACE library specified as GLOBAL, but not as IMPORTED.";
this->SetError(e.str().c_str());
return false;
}
}
bool nameOk = cmGeneratorExpression::IsValidTargetName(libName) &&
!cmGlobalGenerator::IsReservedTarget(libName);

View File

@ -236,8 +236,14 @@ bool cmExportCommand
{
ebfg->AddConfiguration("");
}
gg->AddBuildExportSet(ebfg);
if (this->ExportSet)
{
gg->AddBuildExportExportSet(ebfg);
}
else
{
gg->AddBuildExportSet(ebfg);
}
return true;
}

View File

@ -825,36 +825,36 @@ cmExportFileGenerator
::SetImportLinkProperty(std::string const& suffix,
cmTarget* target,
const char* propName,
std::vector<std::string> const& libs,
std::vector<std::string> const& entries,
ImportPropertyMap& properties,
std::vector<std::string>& missingTargets
)
{
// Skip the property if there are no libraries.
if(libs.empty())
// Skip the property if there are no entries.
if(entries.empty())
{
return;
}
// Construct the property value.
std::string link_libs;
std::string link_entries;
const char* sep = "";
for(std::vector<std::string>::const_iterator li = libs.begin();
li != libs.end(); ++li)
for(std::vector<std::string>::const_iterator li = entries.begin();
li != entries.end(); ++li)
{
// Separate this from the previous entry.
link_libs += sep;
link_entries += sep;
sep = ";";
std::string temp = *li;
this->AddTargetNamespace(temp, target, missingTargets);
link_libs += temp;
link_entries += temp;
}
// Store the property.
std::string prop = propName;
prop += suffix;
properties[prop] = link_libs;
properties[prop] = link_entries;
}

View File

@ -82,7 +82,7 @@ protected:
std::vector<std::string>& missingTargets);
void SetImportLinkProperty(std::string const& suffix,
cmTarget* target, const char* propName,
std::vector<std::string> const& libs,
std::vector<std::string> const& entries,
ImportPropertyMap& properties,
std::vector<std::string>& missingTargets);

View File

@ -36,6 +36,8 @@ bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os)
CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(FIND_TARGETS)
#undef FIND_TARGETS
this->PopulateProperties(te, properties, emittedDeps);
this->GenerateInterfaceProperties(te, os, properties);

View File

@ -40,6 +40,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(TEST_TRANSITIVE_PROPERTY_METHOD)
false)
)
#undef TEST_TRANSITIVE_PROPERTY_METHOD
{
std::map<cmStdString, std::set<cmStdString> >::const_iterator it
= top->Seen.find(target);
@ -191,7 +192,8 @@ bool
cmGeneratorExpressionDAGChecker::EvaluatingSystemIncludeDirectories() const
{
const char *prop = this->Property.c_str();
return strcmp(prop, "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES") == 0;
return (strcmp(prop, "SYSTEM_INCLUDE_DIRECTORIES") == 0
|| strcmp(prop, "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES") == 0);
}
//----------------------------------------------------------------------------

View File

@ -56,7 +56,9 @@ struct cmGeneratorExpressionDAGChecker
#define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) \
bool METHOD () const;
CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(DECLARE_TRANSITIVE_PROPERTY_METHOD)
CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(DECLARE_TRANSITIVE_PROPERTY_METHOD)
#undef DECLARE_TRANSITIVE_PROPERTY_METHOD
bool GetTransitivePropertiesOnly();
void SetTransitivePropertiesOnly()

View File

@ -19,6 +19,7 @@
#include <cmsys/String.h>
#include <assert.h>
#include <errno.h>
//----------------------------------------------------------------------------
#if !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x510
@ -48,7 +49,7 @@ struct cmGeneratorExpressionNode
enum {
DynamicParameters = 0,
OneOrMoreParameters = -1,
ZeroOrMoreParameters = -2
OneOrZeroParameters = -2
};
virtual ~cmGeneratorExpressionNode() {}
@ -196,6 +197,92 @@ static const struct StrEqualNode : public cmGeneratorExpressionNode
}
} strEqualNode;
//----------------------------------------------------------------------------
static const struct EqualNode : public cmGeneratorExpressionNode
{
EqualNode() {}
virtual int NumExpectedParameters() const { return 2; }
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *) const
{
char *pEnd;
int base = 0;
bool flipSign = false;
const char *lhs = parameters[0].c_str();
if (cmHasLiteralPrefix(lhs, "0b"))
{
base = 2;
lhs += 2;
}
if (cmHasLiteralPrefix(lhs, "-0b"))
{
base = 2;
lhs += 3;
flipSign = true;
}
if (cmHasLiteralPrefix(lhs, "+0b"))
{
base = 2;
lhs += 3;
}
long lnum = strtol(lhs, &pEnd, base);
if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE)
{
reportError(context, content->GetOriginalExpression(),
"$<EQUAL> parameter " + parameters[0] + " is not a valid integer.");
return std::string();
}
if (flipSign)
{
lnum = -lnum;
}
base = 0;
flipSign = false;
const char *rhs = parameters[1].c_str();
if (cmHasLiteralPrefix(rhs, "0b"))
{
base = 2;
rhs += 2;
}
if (cmHasLiteralPrefix(rhs, "-0b"))
{
base = 2;
rhs += 3;
flipSign = true;
}
if (cmHasLiteralPrefix(rhs, "+0b"))
{
base = 2;
rhs += 3;
}
long rnum = strtol(rhs, &pEnd, base);
if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE)
{
reportError(context, content->GetOriginalExpression(),
"$<EQUAL> parameter " + parameters[1] + " is not a valid integer.");
return std::string();
}
if (flipSign)
{
rnum = -rnum;
}
return lnum == rnum ? "1" : "0";
}
} equalNode;
//----------------------------------------------------------------------------
static const struct LowerCaseNode : public cmGeneratorExpressionNode
{
@ -297,7 +384,7 @@ struct CompilerIdNode : public cmGeneratorExpressionNode
{
CompilerIdNode() {}
virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
virtual int NumExpectedParameters() const { return OneOrZeroParameters; }
std::string EvaluateWithLanguage(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
@ -343,12 +430,6 @@ static const struct CCompilerIdNode : public CompilerIdNode
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *dagChecker) const
{
if (parameters.size() != 0 && parameters.size() != 1)
{
reportError(context, content->GetOriginalExpression(),
"$<C_COMPILER_ID> expression requires one or two parameters");
return std::string();
}
if (!context->HeadTarget)
{
reportError(context, content->GetOriginalExpression(),
@ -371,12 +452,6 @@ static const struct CXXCompilerIdNode : public CompilerIdNode
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *dagChecker) const
{
if (parameters.size() != 0 && parameters.size() != 1)
{
reportError(context, content->GetOriginalExpression(),
"$<CXX_COMPILER_ID> expression requires one or two parameters");
return std::string();
}
if (!context->HeadTarget)
{
reportError(context, content->GetOriginalExpression(),
@ -394,7 +469,7 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode
{
CompilerVersionNode() {}
virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
virtual int NumExpectedParameters() const { return OneOrZeroParameters; }
std::string EvaluateWithLanguage(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
@ -439,12 +514,6 @@ static const struct CCompilerVersionNode : public CompilerVersionNode
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *dagChecker) const
{
if (parameters.size() != 0 && parameters.size() != 1)
{
reportError(context, content->GetOriginalExpression(),
"$<C_COMPILER_VERSION> expression requires one or two parameters");
return std::string();
}
if (!context->HeadTarget)
{
reportError(context, content->GetOriginalExpression(),
@ -467,13 +536,6 @@ static const struct CxxCompilerVersionNode : public CompilerVersionNode
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *dagChecker) const
{
if (parameters.size() != 0 && parameters.size() != 1)
{
reportError(context, content->GetOriginalExpression(),
"$<CXX_COMPILER_VERSION> expression requires one or two "
"parameters");
return std::string();
}
if (!context->HeadTarget)
{
reportError(context, content->GetOriginalExpression(),
@ -492,7 +554,7 @@ struct PlatformIdNode : public cmGeneratorExpressionNode
{
PlatformIdNode() {}
virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
virtual int NumExpectedParameters() const { return OneOrZeroParameters; }
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
@ -710,6 +772,8 @@ static const char* targetPropertyTransitiveWhitelist[] = {
CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME)
};
#undef TRANSITIVE_PROPERTY_NAME
std::string getLinkedTargetsContent(const std::vector<std::string> &libraries,
cmTarget const* target,
cmTarget const* headTarget,
@ -937,6 +1001,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
ASSERT_TRANSITIVE_PROPERTY_METHOD)
false);
}
#undef ASSERT_TRANSITIVE_PROPERTY_METHOD
}
std::string linkedTargetsContent;
@ -1492,6 +1557,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
return &targetSoNameFileDirNode;
else if (identifier == "STREQUAL")
return &strEqualNode;
else if (identifier == "EQUAL")
return &equalNode;
else if (identifier == "LOWER_CASE")
return &lowerCaseNode;
else if (identifier == "UPPER_CASE")
@ -1733,6 +1800,12 @@ std::string GeneratorExpressionContent::EvaluateParameters(
reportError(context, this->GetOriginalExpression(), "$<" + identifier
+ "> expression requires at least one parameter.");
}
if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters
&& parameters.size() > 2)
{
reportError(context, this->GetOriginalExpression(), "$<" + identifier
+ "> expression requires one or zero parameters.");
}
return std::string();
}

View File

@ -18,9 +18,12 @@
#include "cmSourceFile.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionDAGChecker.h"
#include "cmComputeLinkInformation.h"
#include <queue>
#include "assert.h"
//----------------------------------------------------------------------------
cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t)
{
@ -59,10 +62,50 @@ cmGeneratorTarget::GetSourceDepends(cmSourceFile* sf) const
return 0;
}
static void handleSystemIncludesDep(cmMakefile *mf, const std::string &name,
const char *config, cmTarget *headTarget,
cmGeneratorExpressionDAGChecker *dagChecker,
std::vector<std::string>& result)
{
cmTarget* depTgt = mf->FindTargetToUse(name.c_str());
if (!depTgt)
{
return;
}
cmListFileBacktrace lfbt;
if (const char* dirs =
depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"))
{
cmGeneratorExpression ge(lfbt);
cmSystemTools::ExpandListArgument(ge.Parse(dirs)
->Evaluate(mf,
config, false, headTarget,
depTgt, dagChecker), result);
}
if (!depTgt->IsImported())
{
return;
}
if (const char* dirs =
depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES"))
{
cmGeneratorExpression ge(lfbt);
cmSystemTools::ExpandListArgument(ge.Parse(dirs)
->Evaluate(mf,
config, false, headTarget,
depTgt, dagChecker), result);
}
}
//----------------------------------------------------------------------------
bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir,
const char *config) const
{
assert(this->GetType() != cmTarget::INTERFACE_LIBRARY);
std::string config_upper;
if(config && *config)
{
@ -75,39 +118,81 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir,
if (iter == this->SystemIncludesCache.end())
{
cmTarget::LinkImplementation const* impl
= this->Target->GetLinkImplementation(config, this->Target);
if(!impl)
{
return false;
}
cmListFileBacktrace lfbt;
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(),
"SYSTEM_INCLUDE_DIRECTORIES", 0, 0);
std::vector<std::string> result;
for (std::set<cmStdString>::const_iterator
it = this->Target->GetSystemIncludeDirectories().begin();
it != this->Target->GetSystemIncludeDirectories().end(); ++it)
{
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(),
"INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", 0, 0);
cmSystemTools::ExpandListArgument(ge.Parse(*it)
->Evaluate(this->Makefile,
config, false, this->Target,
&dagChecker), result);
->Evaluate(this->Makefile,
config, false, this->Target,
&dagChecker), result);
}
std::set<cmStdString> uniqueDeps;
for(std::vector<std::string>::const_iterator li = impl->Libraries.begin();
li != impl->Libraries.end(); ++li)
{
if (uniqueDeps.insert(*li).second)
{
cmTarget* tgt = this->Makefile->FindTargetToUse(li->c_str());
if (!tgt)
{
continue;
}
handleSystemIncludesDep(this->Makefile, *li, config, this->Target,
&dagChecker, result);
std::vector<std::string> deps;
tgt->GetTransitivePropertyLinkLibraries(config, this->Target, deps);
for(std::vector<std::string>::const_iterator di = deps.begin();
di != deps.end(); ++di)
{
if (uniqueDeps.insert(*di).second)
{
handleSystemIncludesDep(this->Makefile, *di, config, this->Target,
&dagChecker, result);
}
}
}
}
std::set<cmStdString> unique;
for(std::vector<std::string>::iterator li = result.begin();
li != result.end(); ++li)
{
cmSystemTools::ConvertToUnixSlashes(*li);
unique.insert(*li);
}
result.clear();
for(std::set<cmStdString>::iterator li = unique.begin();
li != unique.end(); ++li)
{
result.push_back(*li);
}
IncludeCacheType::value_type entry(config_upper, result);
iter = this->SystemIncludesCache.insert(entry).first;
}
if (std::find(iter->second.begin(),
iter->second.end(), dir) != iter->second.end())
{
return true;
}
return false;
std::string dirString = dir;
return std::binary_search(iter->second.begin(), iter->second.end(),
dirString);
}
//----------------------------------------------------------------------------

View File

@ -187,6 +187,13 @@ void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen)
this->BuildExportSets[gen->GetMainExportFileName()] = gen;
}
void
cmGlobalGenerator::AddBuildExportExportSet(cmExportBuildFileGenerator* gen)
{
this->BuildExportSets[gen->GetMainExportFileName()] = gen;
this->BuildExportExportSets[gen->GetMainExportFileName()] = gen;
}
bool cmGlobalGenerator::GenerateImportFile(const std::string &file)
{
std::map<std::string, cmExportBuildFileGenerator*>::iterator it
@ -207,7 +214,12 @@ cmGlobalGenerator::IsExportedTargetsFile(const std::string &filename) const
{
const std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it
= this->BuildExportSets.find(filename);
return it != this->BuildExportSets.end();
if (it == this->BuildExportSets.end())
{
return false;
}
return this->BuildExportExportSets.find(filename)
== this->BuildExportExportSets.end();
}
// Find the make program for the generator, required for try compiles
@ -1164,17 +1176,6 @@ void cmGlobalGenerator::Generate()
// it builds by default.
this->FillLocalGeneratorToTargetMap();
for (i = 0; i < this->LocalGenerators.size(); ++i)
{
cmMakefile* mf = this->LocalGenerators[i]->GetMakefile();
cmTargets* targets = &(mf->GetTargets());
for ( cmTargets::iterator it = targets->begin();
it != targets->end(); ++ it )
{
it->second.FinalizeSystemIncludeDirectories();
}
}
// Generate project files
for (i = 0; i < this->LocalGenerators.size(); ++i)
{
@ -1337,13 +1338,13 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo()
{
cmTarget* t = &ti->second;
t->AppendBuildInterfaceIncludes();
if (t->GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
t->AppendBuildInterfaceIncludes();
for (std::vector<cmValueWithOrigin>::const_iterator it
= noconfig_compile_definitions.begin();
it != noconfig_compile_definitions.end(); ++it)
@ -1908,7 +1909,8 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
cmTarget& target)
{
if(target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
if(target.GetType() == cmTarget::INTERFACE_LIBRARY
|| target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
{
// This target is excluded from its directory.
return true;

View File

@ -311,6 +311,7 @@ public:
std::map<std::string, cmExportBuildFileGenerator*>& GetBuildExportSets()
{return this->BuildExportSets;}
void AddBuildExportSet(cmExportBuildFileGenerator*);
void AddBuildExportExportSet(cmExportBuildFileGenerator*);
bool IsExportedTargetsFile(const std::string &filename) const;
bool GenerateImportFile(const std::string &file);
cmExportBuildFileGenerator*
@ -375,6 +376,7 @@ protected:
// Sets of named target exports
cmExportSetMap ExportSets;
std::map<std::string, cmExportBuildFileGenerator*> BuildExportSets;
std::map<std::string, cmExportBuildFileGenerator*> BuildExportExportSets;
// Manifest of all targets that will be built for each configuration.
// This is computed just before local generators generate.

View File

@ -488,7 +488,8 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
dir.c_str());
}
if(!target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
if(target.GetType() != cmTarget::INTERFACE_LIBRARY
&& !target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
{
allbuild->AddUtility(target.GetName());
}

View File

@ -24,6 +24,7 @@
#include <set>
#include <stdlib.h> // required for atof
#include <assert.h>
#include <errno.h>
const char* cmTarget::GetTargetTypeName(TargetType targetType)
{
@ -1040,62 +1041,6 @@ cmTarget::AddSystemIncludeDirectories(const std::vector<std::string> &incs)
}
}
//----------------------------------------------------------------------------
void cmTarget::FinalizeSystemIncludeDirectories()
{
for (std::vector<cmValueWithOrigin>::const_iterator
it = this->Internal->LinkImplementationPropertyEntries.begin(),
end = this->Internal->LinkImplementationPropertyEntries.end();
it != end; ++it)
{
if (!cmGeneratorExpression::IsValidTargetName(it->Value)
&& cmGeneratorExpression::Find(it->Value) == std::string::npos)
{
continue;
}
{
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
ge.Parse(it->Value);
std::string targetName = cge->Evaluate(this->Makefile, 0,
false, this, 0, 0);
cmTarget *tgt = this->Makefile->FindTargetToUse(targetName.c_str());
if (!tgt || tgt == this)
{
continue;
}
if (tgt->IsImported()
&& tgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")
&& !this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED"))
{
std::string includeGenex = "$<TARGET_PROPERTY:" +
it->Value + ",INTERFACE_INCLUDE_DIRECTORIES>";
if (cmGeneratorExpression::Find(it->Value) != std::string::npos)
{
// Because it->Value is a generator expression, ensure that it
// evaluates to the non-empty string before being used in the
// TARGET_PROPERTY expression.
includeGenex = "$<$<BOOL:" + it->Value + ">:" + includeGenex + ">";
}
this->SystemIncludeDirectories.insert(includeGenex);
return; // The INTERFACE_SYSTEM_INCLUDE_DIRECTORIES are a subset
// of the INTERFACE_INCLUDE_DIRECTORIES
}
}
std::string includeGenex = "$<TARGET_PROPERTY:" +
it->Value + ",INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>";
if (cmGeneratorExpression::Find(it->Value) != std::string::npos)
{
// Because it->Value is a generator expression, ensure that it
// evaluates to the non-empty string before being used in the
// TARGET_PROPERTY expression.
includeGenex = "$<$<BOOL:" + it->Value + ">:" + includeGenex + ">";
}
this->SystemIncludeDirectories.insert(includeGenex);
}
}
//----------------------------------------------------------------------------
void
cmTarget::AnalyzeLibDependencies( const cmMakefile& mf )
@ -1402,14 +1347,10 @@ static bool whiteListedInterfaceProperty(const char *prop)
"COMPATIBLE_INTERFACE_NUMBER_MAX",
"COMPATIBLE_INTERFACE_NUMBER_MIN",
"COMPATIBLE_INTERFACE_STRING",
"EXCLUDE_FROM_ALL",
"EXCLUDE_FROM_DEFAULT_BUILD",
"EXPORT_NAME",
"IMPORTED_LINK_INTERFACE_LANGUAGES",
"IMPORTED",
"NAME",
"TYPE",
"VERSION"
"TYPE"
};
if (std::binary_search(cmArrayBegin(builtIns),
@ -1420,9 +1361,7 @@ static bool whiteListedInterfaceProperty(const char *prop)
return true;
}
if (cmHasLiteralPrefix(prop, "EXCLUDE_FROM_DEFAULT_BUILD_")
|| cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LANGUAGES_")
|| cmHasLiteralPrefix(prop, "MAP_IMPORTED_CONFIG_"))
if (cmHasLiteralPrefix(prop, "MAP_IMPORTED_CONFIG_"))
{
return true;
}
@ -1605,6 +1544,7 @@ void cmTarget::AppendBuildInterfaceIncludes()
if(this->GetType() != cmTarget::SHARED_LIBRARY &&
this->GetType() != cmTarget::STATIC_LIBRARY &&
this->GetType() != cmTarget::MODULE_LIBRARY &&
this->GetType() != cmTarget::INTERFACE_LIBRARY &&
!this->IsExecutableWithExports())
{
return;
@ -2574,6 +2514,8 @@ void cmTarget::GetTargetVersion(bool soversion,
minor = 0;
patch = 0;
assert(this->GetType() != INTERFACE_LIBRARY);
// Look for a VERSION or SOVERSION property.
const char* prop = soversion? "SOVERSION" : "VERSION";
if(const char* version = this->GetProperty(prop))
@ -2687,7 +2629,6 @@ const char *cmTarget::GetProperty(const char* prop,
this->GetType() == cmTarget::STATIC_LIBRARY ||
this->GetType() == cmTarget::SHARED_LIBRARY ||
this->GetType() == cmTarget::MODULE_LIBRARY ||
this->GetType() == cmTarget::INTERFACE_LIBRARY ||
this->GetType() == cmTarget::UNKNOWN_LIBRARY)
{
if(strcmp(prop,"LOCATION") == 0)
@ -3587,6 +3528,8 @@ void cmTarget::GetLibraryNames(std::string& name,
return;
}
assert(this->GetType() != INTERFACE_LIBRARY);
// Check for library version properties.
const char* version = this->GetProperty("VERSION");
const char* soversion = this->GetProperty("SOVERSION");
@ -4162,6 +4105,8 @@ std::string cmTarget::GetOutputName(const char* config, bool implib) const
//----------------------------------------------------------------------------
std::string cmTarget::GetFrameworkVersion() const
{
assert(this->GetType() != INTERFACE_LIBRARY);
if(const char* fversion = this->GetProperty("FRAMEWORK_VERSION"))
{
return fversion;
@ -4274,6 +4219,7 @@ std::pair<bool, const char*> consistentNumberProperty(const char *lhs,
const char *rhs,
CompatibleType t)
{
char *pEnd;
#if defined(_MSC_VER)
static const char* const null_ptr = 0;
@ -4281,10 +4227,14 @@ std::pair<bool, const char*> consistentNumberProperty(const char *lhs,
# define null_ptr 0
#endif
double lnum;
double rnum;
if(sscanf(lhs, "%lg", &lnum) != 1 ||
sscanf(rhs, "%lg", &rnum) != 1)
long lnum = strtol(lhs, &pEnd, 0);
if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE)
{
return std::pair<bool, const char*>(false, null_ptr);
}
long rnum = strtol(rhs, &pEnd, 0);
if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE)
{
return std::pair<bool, const char*>(false, null_ptr);
}
@ -5586,9 +5536,6 @@ void cmTarget::ComputeLinkImplementation(const char* config,
LinkImplementation& impl,
cmTarget const* head) const
{
// Compute which library configuration to link.
cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config);
// Collect libraries directly linked in this configuration.
std::vector<std::string> llibs;
this->GetDirectLinkLibraries(config, llibs, head);
@ -5681,6 +5628,7 @@ void cmTarget::ComputeLinkImplementation(const char* config,
impl.Libraries.push_back(item);
}
cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config);
LinkLibraryVectorType const& oldllibs = this->GetOriginalLinkLibraries();
for(cmTarget::LinkLibraryVectorType::const_iterator li = oldllibs.begin();
li != oldllibs.end(); ++li)

View File

@ -568,8 +568,6 @@ public:
std::set<cmStdString> const & GetSystemIncludeDirectories() const
{ return this->SystemIncludeDirectories; }
void FinalizeSystemIncludeDirectories();
bool LinkLanguagePropagatesToDependents() const
{ return this->TargetTypeValue == STATIC_LIBRARY; }

View File

@ -24,6 +24,8 @@ set_property(TARGET iface1 APPEND PROPERTY
COMPATIBLE_INTERFACE_NUMBER_MIN
NUMBER_MIN_PROP1
NUMBER_MIN_PROP2
NUMBER_MIN_PROP3
NUMBER_MIN_PROP4
)
set_property(TARGET iface1 APPEND PROPERTY
COMPATIBLE_INTERFACE_NUMBER_MAX
@ -34,7 +36,7 @@ set_property(TARGET iface1 APPEND PROPERTY
set(CMAKE_DEBUG_TARGET_PROPERTIES
BOOL_PROP1 BOOL_PROP2 BOOL_PROP3 BOOL_PROP4
STRING_PROP1 STRING_PROP2 STRING_PROP3
NUMBER_MIN_PROP1 NUMBER_MIN_PROP2
NUMBER_MIN_PROP1 NUMBER_MIN_PROP2 NUMBER_MIN_PROP3 NUMBER_MIN_PROP4
NUMBER_MAX_PROP1 NUMBER_MAX_PROP2
)
@ -44,6 +46,8 @@ set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP1 prop1)
set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP2 prop2)
set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP1 100)
set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP2 200)
set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP3 0x10)
set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP4 0x10)
set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MAX_PROP1 100)
set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MAX_PROP2 200)
@ -56,6 +60,8 @@ set_property(TARGET CompatibleInterface PROPERTY STRING_PROP2 prop2)
set_property(TARGET CompatibleInterface PROPERTY STRING_PROP3 prop3)
set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP1 50)
set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP2 250)
set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP3 0xa)
set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP4 0x1A)
set_property(TARGET CompatibleInterface PROPERTY NUMBER_MAX_PROP1 50)
set_property(TARGET CompatibleInterface PROPERTY NUMBER_MAX_PROP2 250)
@ -69,6 +75,8 @@ target_compile_definitions(CompatibleInterface
$<$<STREQUAL:$<TARGET_PROPERTY:STRING_PROP3>,prop3>:STRING_PROP3>
$<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MIN_PROP1>,50>:NUMBER_MIN_PROP1=50>
$<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MIN_PROP2>,200>:NUMBER_MIN_PROP2=200>
$<$<EQUAL:$<TARGET_PROPERTY:NUMBER_MIN_PROP3>,0xA>:NUMBER_MIN_PROP3=0xA>
$<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MIN_PROP4>,0x10>:NUMBER_MIN_PROP4=0x10>
$<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MAX_PROP1>,100>:NUMBER_MAX_PROP1=100>
$<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MAX_PROP2>,250>:NUMBER_MAX_PROP2=250>
)

View File

@ -33,7 +33,9 @@ enum {
NumericMaxTest1 = sizeof(CMakeStaticAssert<NUMBER_MAX_PROP1 == 100>),
NumericMaxTest2 = sizeof(CMakeStaticAssert<NUMBER_MAX_PROP2 == 250>),
NumericMinTest1 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP1 == 50>),
NumericMinTest2 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP2 == 200>)
NumericMinTest2 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP2 == 200>),
NumericMinTest3 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP3 == 0xA>),
NumericMinTest4 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP4 == 0x10>)
};
#include "iface2.h"

View File

@ -196,6 +196,27 @@ add_custom_target(check-part3 ALL
-Dlower_case=$<LOWER_CASE:Mi,XeD>
-Dupper_case=$<UPPER_CASE:MiX,eD>
-Dmake_c_identifier=$<MAKE_C_IDENTIFIER:4f,oo:+bar-$>
-Dequal1=$<EQUAL:1,2>
-Dequal2=$<EQUAL:1,1>
-Dequal3=$<EQUAL:0x1,1>
-Dequal4=$<EQUAL:0x1,2>
-Dequal5=$<EQUAL:0xA,0xa>
-Dequal6=$<EQUAL:0xA,10>
-Dequal7=$<EQUAL:0xA,012>
-Dequal8=$<EQUAL:10,012>
-Dequal9=$<EQUAL:10,010>
-Dequal10=$<EQUAL:10,0b1010>
-Dequal11=$<EQUAL:-10,-0xa>
-Dequal12=$<EQUAL:10,+0xa>
-Dequal13=$<EQUAL:+10,+0xa>
-Dequal14=$<EQUAL:+10,0xa>
-Dequal15=$<EQUAL:-10,-0xa>
-Dequal16=$<EQUAL:-10,-0b1010>
-Dequal17=$<EQUAL:-10,+0b1010>
-Dequal18=$<EQUAL:10,+0b1010>
-Dequal19=$<EQUAL:10,+012>
-Dequal20=$<EQUAL:10,-012>
-Dequal21=$<EQUAL:-10,-012>
-P ${CMAKE_CURRENT_SOURCE_DIR}/check-part3.cmake
COMMAND ${CMAKE_COMMAND} -E echo "check done (part 3 of 3)"
VERBATIM

View File

@ -37,3 +37,24 @@ endforeach()
check(lower_case "mi,xed")
check(upper_case "MIX,ED")
check(make_c_identifier "_4f_oo__bar__")
check(equal1 "0")
check(equal2 "1")
check(equal3 "1")
check(equal4 "0")
check(equal5 "1")
check(equal6 "1")
check(equal7 "1")
check(equal8 "1")
check(equal9 "0")
check(equal10 "1")
check(equal11 "1")
check(equal12 "1")
check(equal13 "1")
check(equal14 "1")
check(equal15 "1")
check(equal16 "1")
check(equal17 "0")
check(equal18 "1")
check(equal19 "1")
check(equal20 "0")
check(equal21 "1")

View File

@ -25,6 +25,10 @@ add_library(imported_consumer imported_consumer.cpp)
target_link_libraries(imported_consumer iface)
target_compile_options(imported_consumer PRIVATE -Werror=unused-variable)
add_library(imported_consumer2 imported_consumer.cpp)
target_link_libraries(imported_consumer2 imported_consumer)
target_compile_options(imported_consumer2 PRIVATE -Werror=unused-variable)
macro(do_try_compile error_option)
set(TC_ARGS
IFACE_TRY_COMPILE_${error_option}

View File

@ -6,13 +6,15 @@ project(InterfaceLibrary)
add_library(iface_nodepends INTERFACE)
target_compile_definitions(iface_nodepends INTERFACE IFACE_DEFINE)
add_subdirectory(headerdir)
add_executable(InterfaceLibrary definetestexe.cpp)
target_link_libraries(InterfaceLibrary iface_nodepends)
target_link_libraries(InterfaceLibrary iface_nodepends headeriface)
add_subdirectory(libsdir)
add_executable(sharedlibtestexe sharedlibtestexe.cpp)
target_link_libraries(sharedlibtestexe shared_iface)
target_link_libraries(sharedlibtestexe shared_iface imported::iface)
add_library(broken EXCLUDE_FROM_ALL broken.cpp)

View File

@ -3,6 +3,18 @@
#error Expected IFACE_DEFINE
#endif
#include "iface_header.h"
#ifndef IFACE_HEADER_SRCDIR
#error Expected IFACE_HEADER_SRCDIR
#endif
#include "iface_header_builddir.h"
#ifndef IFACE_HEADER_BUILDDIR
#error Expected IFACE_HEADER_BUILDDIR
#endif
int main(int,char**)
{
return 0;

View File

@ -0,0 +1,8 @@
set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
add_library(headeriface INTERFACE)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/iface_header_builddir.h"
"#define IFACE_HEADER_BUILDDIR\n"
)

View File

@ -0,0 +1 @@
#define IFACE_HEADER_SRCDIR

View File

@ -24,3 +24,5 @@ target_compile_definitions(shareddependlib
add_library(shared_iface INTERFACE)
target_link_libraries(shared_iface INTERFACE sharedlib)
add_library(imported::iface INTERFACE IMPORTED GLOBAL)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,6 @@
CMake Error at ExportExportInclude.cmake:6 \(include\):
include could not find load file:
.*/Tests/RunCMake/include/ExportExportInclude-build/theTargets.cmake
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,6 @@
add_library(iface INTERFACE)
install(TARGETS iface EXPORT ifaceExport)
export(EXPORT ifaceExport FILE "${CMAKE_CURRENT_BINARY_DIR}/theTargets.cmake")
include("${CMAKE_CURRENT_BINARY_DIR}/theTargets.cmake")

View File

@ -4,3 +4,4 @@ run_cmake(EmptyString)
run_cmake(EmptyStringOptional)
run_cmake(CMP0024-WARN)
run_cmake(CMP0024-NEW)
run_cmake(ExportExportInclude)

View File

@ -4,5 +4,6 @@ run_cmake(invalid_name)
run_cmake(target_commands)
run_cmake(no_shared_libs)
run_cmake(whitelist)
run_cmake(invalid_signature)
run_cmake(genex_link)
run_cmake(add_dependencies)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,89 @@
CMake Error at invalid_signature.cmake:2 \(add_library\):
add_library INTERFACE library requires no source arguments.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:3 \(add_library\):
add_library INTERFACE library specified with conflicting/multiple types.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:4 \(add_library\):
add_library INTERFACE library specified with conflicting/multiple types.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:5 \(add_library\):
add_library INTERFACE library specified with conflicting/multiple types.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:6 \(add_library\):
add_library INTERFACE library specified with conflicting/multiple types.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:7 \(add_library\):
add_library INTERFACE library specified with conflicting/multiple types.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:8 \(add_library\):
add_library INTERFACE library specified with conflicting/multiple types.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:9 \(add_library\):
add_library INTERFACE library specified with conflicting STATIC type.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:10 \(add_library\):
add_library INTERFACE library specified with conflicting SHARED type.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:11 \(add_library\):
add_library INTERFACE library specified with conflicting MODULE type.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:12 \(add_library\):
add_library INTERFACE library specified with conflicting OBJECT type.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:13 \(add_library\):
add_library INTERFACE library specified with conflicting UNKNOWN type.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:14 \(add_library\):
add_library INTERFACE library specified with conflicting ALIAS type.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:15 \(add_library\):
add_library INTERFACE library specified with conflicting ALIAS type.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:16 \(add_library\):
add_library INTERFACE library specified with conflicting/multiple types.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:17 \(add_library\):
add_library INTERFACE library may not be used with EXCLUDE_FROM_ALL.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:18 \(add_library\):
add_library INTERFACE library may not be used with EXCLUDE_FROM_ALL.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_signature.cmake:20 \(add_library\):
add_library INTERFACE library requires no source arguments.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,20 @@
add_library(iface1 INTERFACE empty.cpp)
add_library(iface3 STATIC INTERFACE)
add_library(iface4 STATIC INTERFACE empty.cpp)
add_library(iface5 SHARED INTERFACE)
add_library(iface6 MODULE INTERFACE)
add_library(iface7 OBJECT INTERFACE)
add_library(iface8 UNKNOWN INTERFACE)
add_library(iface9 INTERFACE STATIC)
add_library(iface10 INTERFACE SHARED)
add_library(iface11 INTERFACE MODULE)
add_library(iface12 INTERFACE OBJECT)
add_library(iface13 INTERFACE UNKNOWN)
add_library(iface14 INTERFACE ALIAS)
add_library(iface15 ALIAS INTERFACE)
add_library(iface16 INTERFACE INTERFACE)
add_library(iface17 INTERFACE EXCLUDE_FROM_ALL)
add_library(iface18 EXCLUDE_FROM_ALL INTERFACE)
add_library(iface19 GLOBAL INTERFACE)
add_library(iface20 INTERFACE GLOBAL)