Add the $<LINKED:...> generator expression.
This is both a short form of using a TARGET_DEFINED expression together with a TARGET_PROPERTY definition, and a way to strip non-target content from interface properties when exporting.
This commit is contained in:
parent
0fa7f69c0e
commit
0b92602b81
|
@ -51,6 +51,14 @@
|
|||
"on the target tgt.\n" \
|
||||
"Note that tgt is not added as a dependency of the target this " \
|
||||
"expression is evaluated on.\n" \
|
||||
" $<LINKED:item> = An empty string if item is not a " \
|
||||
"target. If item is a target then the " \
|
||||
"INTERFACE_INCLUDE_DIRECTORIES or INTERFACE_COMPILE_DEFINITIONS " \
|
||||
"content is read from the target. " \
|
||||
"This generator expression can only be used in evaluation of the " \
|
||||
"INCLUDE_DIRECTORIES or COMPILE_DEFINITIONS property. Note that " \
|
||||
"this expression is for internal use and may be changed or removed " \
|
||||
"in the future.\n" \
|
||||
" $<TARGET_POLICY:pol> = '1' if the policy was NEW when " \
|
||||
"the 'head' target was created, else '0'. If the policy was not " \
|
||||
"set, the warning message for the policy will be emitted. This " \
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include <cmsys/auto_ptr.hxx>
|
||||
|
||||
#include "assert.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
cmExportFileGenerator::cmExportFileGenerator()
|
||||
{
|
||||
|
@ -160,7 +162,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName,
|
|||
preprocessRule);
|
||||
if (!prepro.empty())
|
||||
{
|
||||
this->ResolveTargetsInGeneratorExpressions(prepro, target,
|
||||
this->ResolveTargetsInGeneratorExpressions(prepro, target, propName,
|
||||
missingTargets);
|
||||
properties[outputName] = prepro;
|
||||
}
|
||||
|
@ -324,13 +326,14 @@ static bool isGeneratorExpression(const std::string &lib)
|
|||
void
|
||||
cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
|
||||
std::string &input,
|
||||
cmTarget* target,
|
||||
cmTarget* target, const char *propName,
|
||||
std::vector<std::string> &missingTargets,
|
||||
FreeTargetsReplace replace)
|
||||
{
|
||||
if (replace == NoReplaceFreeTargets)
|
||||
{
|
||||
this->ResolveTargetsInGeneratorExpression(input, target, missingTargets);
|
||||
this->ResolveTargetsInGeneratorExpression(input, target, propName,
|
||||
missingTargets);
|
||||
return;
|
||||
}
|
||||
std::vector<std::string> parts;
|
||||
|
@ -349,7 +352,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
|
|||
{
|
||||
this->ResolveTargetsInGeneratorExpression(
|
||||
*li,
|
||||
target,
|
||||
target, propName,
|
||||
missingTargets);
|
||||
}
|
||||
input += sep + *li;
|
||||
|
@ -361,7 +364,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
|
|||
void
|
||||
cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
|
||||
std::string &input,
|
||||
cmTarget* target,
|
||||
cmTarget* target, const char *propName,
|
||||
std::vector<std::string> &missingTargets)
|
||||
{
|
||||
std::string::size_type pos = 0;
|
||||
|
@ -396,6 +399,57 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
|
|||
}
|
||||
|
||||
std::string errorString;
|
||||
pos = 0;
|
||||
lastPos = pos;
|
||||
while((pos = input.find("$<LINKED:", lastPos)) != input.npos)
|
||||
{
|
||||
std::string::size_type nameStartPos = pos + sizeof("$<LINKED:") - 1;
|
||||
std::string::size_type endPos = input.find(">", nameStartPos);
|
||||
if (endPos == input.npos)
|
||||
{
|
||||
errorString = "$<LINKED:...> expression incomplete";
|
||||
break;
|
||||
}
|
||||
std::string targetName = input.substr(nameStartPos,
|
||||
endPos - nameStartPos);
|
||||
if(targetName.find("$<") != input.npos)
|
||||
{
|
||||
errorString = "$<LINKED:...> requires its parameter to be a "
|
||||
"literal.";
|
||||
break;
|
||||
}
|
||||
if (this->AddTargetNamespace(targetName, target, missingTargets))
|
||||
{
|
||||
assert(propName); // The link libraries strings will
|
||||
// never contain $<LINKED>
|
||||
std::string replacement = "$<TARGET_PROPERTY:"
|
||||
+ targetName + "," + propName;
|
||||
input.replace(pos, endPos - pos, replacement);
|
||||
lastPos = pos + replacement.size() + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pos != 0)
|
||||
{
|
||||
if (input[pos - 1] == ';')
|
||||
{
|
||||
--pos;
|
||||
}
|
||||
}
|
||||
else if (input[endPos + 1] == ';')
|
||||
{
|
||||
++endPos;
|
||||
}
|
||||
input.replace(pos, endPos - pos + 1, "");
|
||||
lastPos = pos;
|
||||
}
|
||||
}
|
||||
if (!errorString.empty())
|
||||
{
|
||||
mf->IssueMessage(cmake::FATAL_ERROR, errorString);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
lastPos = pos;
|
||||
while((pos = input.find("$<TARGET_NAME:", lastPos)) != input.npos)
|
||||
|
@ -491,7 +545,7 @@ cmExportFileGenerator
|
|||
preprocessRule);
|
||||
if (!prepro.empty())
|
||||
{
|
||||
this->ResolveTargetsInGeneratorExpressions(prepro, target,
|
||||
this->ResolveTargetsInGeneratorExpressions(prepro, target, 0,
|
||||
missingTargets,
|
||||
ReplaceFreeTargets);
|
||||
properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro;
|
||||
|
|
|
@ -119,7 +119,7 @@ protected:
|
|||
};
|
||||
|
||||
void ResolveTargetsInGeneratorExpressions(std::string &input,
|
||||
cmTarget* target,
|
||||
cmTarget* target, const char *propName,
|
||||
std::vector<std::string> &missingTargets,
|
||||
FreeTargetsReplace replace = NoReplaceFreeTargets);
|
||||
|
||||
|
@ -150,7 +150,7 @@ private:
|
|||
std::vector<std::string> &missingTargets);
|
||||
|
||||
void ResolveTargetsInGeneratorExpression(std::string &input,
|
||||
cmTarget* target,
|
||||
cmTarget* target, const char *propName,
|
||||
std::vector<std::string> &missingTargets);
|
||||
|
||||
virtual void ReplaceInstallPrefix(std::string &input);
|
||||
|
|
|
@ -637,6 +637,89 @@ static const struct InstallPrefixNode : public cmGeneratorExpressionNode
|
|||
|
||||
} installPrefixNode;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static const struct LinkedNode : public cmGeneratorExpressionNode
|
||||
{
|
||||
LinkedNode() {}
|
||||
|
||||
virtual bool GeneratesContent() const { return true; }
|
||||
virtual int NumExpectedParameters() const { return 1; }
|
||||
virtual bool RequiresLiteralInput() const { return true; }
|
||||
|
||||
std::string Evaluate(const std::vector<std::string> ¶meters,
|
||||
cmGeneratorExpressionContext *context,
|
||||
const GeneratorExpressionContent *content,
|
||||
cmGeneratorExpressionDAGChecker *dagChecker) const
|
||||
{
|
||||
if (dagChecker->EvaluatingIncludeDirectories())
|
||||
{
|
||||
return this->GetInterfaceProperty(parameters.front(),
|
||||
"INCLUDE_DIRECTORIES",
|
||||
context, content, dagChecker);
|
||||
}
|
||||
if (dagChecker->EvaluatingCompileDefinitions())
|
||||
{
|
||||
return this->GetInterfaceProperty(parameters.front(),
|
||||
"COMPILE_DEFINITIONS",
|
||||
context, content, dagChecker);
|
||||
}
|
||||
|
||||
reportError(context, content->GetOriginalExpression(),
|
||||
"$<LINKED:...> may only be used in INCLUDE_DIRECTORIES and "
|
||||
"COMPILE_DEFINITIONS properties.");
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string GetInterfaceProperty(const std::string &item,
|
||||
const std::string &prop,
|
||||
cmGeneratorExpressionContext *context,
|
||||
const GeneratorExpressionContent *content,
|
||||
cmGeneratorExpressionDAGChecker *dagCheckerParent) const
|
||||
{
|
||||
cmTarget *target = context->CurrentTarget
|
||||
->GetMakefile()->FindTargetToUse(item.c_str());
|
||||
if (!target)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
std::string propertyName = "INTERFACE_" + prop;
|
||||
const char *propContent = target->GetProperty(propertyName.c_str());
|
||||
if (!propContent)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
|
||||
target->GetName(),
|
||||
propertyName,
|
||||
content,
|
||||
dagCheckerParent);
|
||||
|
||||
switch (dagChecker.check())
|
||||
{
|
||||
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
|
||||
dagChecker.reportError(context, content->GetOriginalExpression());
|
||||
return std::string();
|
||||
case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
|
||||
// No error. We just skip cyclic references.
|
||||
return std::string();
|
||||
case cmGeneratorExpressionDAGChecker::DAG:
|
||||
break;
|
||||
}
|
||||
|
||||
cmGeneratorExpression ge(context->Backtrace);
|
||||
return ge.Parse(propContent)->Evaluate(context->Makefile,
|
||||
context->Config,
|
||||
context->Quiet,
|
||||
context->HeadTarget,
|
||||
target,
|
||||
&dagChecker);
|
||||
}
|
||||
|
||||
} linkedNode;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
template<bool linker, bool soname>
|
||||
struct TargetFilesystemArtifactResultCreator
|
||||
|
@ -874,6 +957,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
|
|||
return &targetDefinedNode;
|
||||
else if (identifier == "INSTALL_PREFIX")
|
||||
return &installPrefixNode;
|
||||
else if (identifier == "LINKED")
|
||||
return &linkedNode;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
|
|
@ -16,9 +16,15 @@ add_executable(consumer
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
|
||||
)
|
||||
|
||||
add_library(linked UNKNOWN IMPORTED)
|
||||
set_property(TARGET linked PROPERTY
|
||||
INTERFACE_COMPILE_DEFINITIONS "MY_LINKED_DEFINE")
|
||||
|
||||
|
||||
target_compile_definitions(consumer
|
||||
PRIVATE $<TARGET_PROPERTY:target_compile_definitions,INTERFACE_COMPILE_DEFINITIONS>
|
||||
$<$<TARGET_DEFINED:notdefined>:SHOULD_NOT_BE_DEFINED>
|
||||
$<$<TARGET_DEFINED:target_compile_definitions>:SHOULD_BE_DEFINED>
|
||||
$<LINKED:linked>
|
||||
-DDASH_D_DEFINE
|
||||
)
|
||||
|
|
|
@ -23,4 +23,8 @@
|
|||
#error Expected DASH_D_DEFINE
|
||||
#endif
|
||||
|
||||
#ifndef MY_LINKED_DEFINE
|
||||
#error Expected MY_LINKED_DEFINE
|
||||
#endif
|
||||
|
||||
int main() { return 0; }
|
||||
|
|
|
@ -17,6 +17,9 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/poison/common.h" "#error Should not be i
|
|||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/cure")
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cure/common.h" "#define CURE_DEFINE\n")
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude")
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude/linkedinclude.h" "#define LINKEDINCLUDE_DEFINE\n")
|
||||
|
||||
add_executable(target_include_directories
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
|
||||
)
|
||||
|
@ -42,7 +45,13 @@ add_executable(consumer
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
|
||||
)
|
||||
|
||||
add_library(linked UNKNOWN IMPORTED)
|
||||
set_property(TARGET linked PROPERTY
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude")
|
||||
|
||||
target_include_directories(consumer
|
||||
PRIVATE $<TARGET_PROPERTY:target_include_directories,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
PRIVATE
|
||||
$<TARGET_PROPERTY:target_include_directories,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<LINKED:linked>
|
||||
relative_dir
|
||||
)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "publicinclude.h"
|
||||
#include "interfaceinclude.h"
|
||||
#include "relative_dir.h"
|
||||
#include "linkedinclude.h"
|
||||
|
||||
#ifdef PRIVATEINCLUDE_DEFINE
|
||||
#error Unexpected PRIVATEINCLUDE_DEFINE
|
||||
|
@ -24,4 +25,8 @@
|
|||
#error Expected RELATIVE_DIR_DEFINE
|
||||
#endif
|
||||
|
||||
#ifndef LINKEDINCLUDE_DEFINE
|
||||
#error Expected LINKEDINCLUDE_DEFINE
|
||||
#endif
|
||||
|
||||
int main() { return 0; }
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
1
|
|
@ -0,0 +1,7 @@
|
|||
CMake Error:
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<LINKED:something>
|
||||
|
||||
\$<LINKED:...> may only be used in INCLUDE_DIRECTORIES and
|
||||
COMPILE_DEFINITIONS properties.$
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
|
||||
"int main(int, char **) { return 0; }\n")
|
||||
|
||||
add_executable(TargetPropertyGeneratorExpressions
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
|
||||
target_link_libraries(TargetPropertyGeneratorExpressions "$<LINKED:something>")
|
|
@ -15,3 +15,4 @@ run_cmake(BadInvalidName5)
|
|||
run_cmake(BadInvalidName6)
|
||||
run_cmake(BadInvalidName7)
|
||||
run_cmake(BadInvalidName8)
|
||||
run_cmake(BadLinked)
|
||||
|
|
Loading…
Reference in New Issue