Commit dc081998 authored by Brad King's avatar Brad King 💬 Committed by Kitware Robot
Browse files

Merge topic 'minor-cleanups'

84fac67f Don't allow include() of export(EXPORT) file at configure time.
faedd2be cmTarget: Fix system include annotation propagation.
9eb06d0d add_library: Disallow invalid signatures for INTERFACE_LIBRARY.
10d65d50 cmTarget: Move a variable initialization closer to where it is used.
0f3e8e95 Undefine local preprocessor loop variables.
9ba47ee4 Genex: Reform error-checking for nullary/unary expressions.
fa651c7a cmTarget: Remove some of the INTERFACE_LIBRARY whitelisted properties.
61d138ae cmTarget: INTERFACE_LIBRARY is always EXCLUDE_FROM_ALL.
3429541e export: Rename some variables to reflect content type.
7461d67c cmTarget: Enable convenient include dir handling for INTERFACE_LIBRARY.
7fc6e3d6 cmTarget: Remove dead code.
2af966d9 Genex: Add EQUAL expression.
2d663800 cmTarget: Use strtol for numeric parsing.
parents b225dbbd 84fac67f
......@@ -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`.
......@@ -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
......
......@@ -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);
......
......@@ -236,8 +236,14 @@ bool cmExportCommand
{
ebfg->AddConfiguration("");
}
gg->AddBuildExportSet(ebfg);
if (this->ExportSet)
{
gg->AddBuildExportExportSet(ebfg);
}
else
{
gg->AddBuildExportSet(ebfg);
}
return true;
}
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
}
//----------------------------------------------------------------------------
......
......@@ -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()
......
......@@ -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();
}
......
......@@ -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);
cmSystemTools::ExpandListArgument(ge.Parse(*it)
->Evaluate(this->Makefile,
config, false, this->Target,
&dagChecker), result);