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" \
|
"on the target tgt.\n" \
|
||||||
"Note that tgt is not added as a dependency of the target this " \
|
"Note that tgt is not added as a dependency of the target this " \
|
||||||
"expression is evaluated on.\n" \
|
"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 " \
|
" $<TARGET_POLICY:pol> = '1' if the policy was NEW when " \
|
||||||
"the 'head' target was created, else '0'. If the policy was not " \
|
"the 'head' target was created, else '0'. If the policy was not " \
|
||||||
"set, the warning message for the policy will be emitted. This " \
|
"set, the warning message for the policy will be emitted. This " \
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include <cmsys/auto_ptr.hxx>
|
#include <cmsys/auto_ptr.hxx>
|
||||||
|
|
||||||
|
#include "assert.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
cmExportFileGenerator::cmExportFileGenerator()
|
cmExportFileGenerator::cmExportFileGenerator()
|
||||||
{
|
{
|
||||||
|
@ -160,7 +162,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName,
|
||||||
preprocessRule);
|
preprocessRule);
|
||||||
if (!prepro.empty())
|
if (!prepro.empty())
|
||||||
{
|
{
|
||||||
this->ResolveTargetsInGeneratorExpressions(prepro, target,
|
this->ResolveTargetsInGeneratorExpressions(prepro, target, propName,
|
||||||
missingTargets);
|
missingTargets);
|
||||||
properties[outputName] = prepro;
|
properties[outputName] = prepro;
|
||||||
}
|
}
|
||||||
|
@ -324,13 +326,14 @@ static bool isGeneratorExpression(const std::string &lib)
|
||||||
void
|
void
|
||||||
cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
|
cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
|
||||||
std::string &input,
|
std::string &input,
|
||||||
cmTarget* target,
|
cmTarget* target, const char *propName,
|
||||||
std::vector<std::string> &missingTargets,
|
std::vector<std::string> &missingTargets,
|
||||||
FreeTargetsReplace replace)
|
FreeTargetsReplace replace)
|
||||||
{
|
{
|
||||||
if (replace == NoReplaceFreeTargets)
|
if (replace == NoReplaceFreeTargets)
|
||||||
{
|
{
|
||||||
this->ResolveTargetsInGeneratorExpression(input, target, missingTargets);
|
this->ResolveTargetsInGeneratorExpression(input, target, propName,
|
||||||
|
missingTargets);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::vector<std::string> parts;
|
std::vector<std::string> parts;
|
||||||
|
@ -349,7 +352,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
|
||||||
{
|
{
|
||||||
this->ResolveTargetsInGeneratorExpression(
|
this->ResolveTargetsInGeneratorExpression(
|
||||||
*li,
|
*li,
|
||||||
target,
|
target, propName,
|
||||||
missingTargets);
|
missingTargets);
|
||||||
}
|
}
|
||||||
input += sep + *li;
|
input += sep + *li;
|
||||||
|
@ -361,7 +364,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
|
||||||
void
|
void
|
||||||
cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
|
cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
|
||||||
std::string &input,
|
std::string &input,
|
||||||
cmTarget* target,
|
cmTarget* target, const char *propName,
|
||||||
std::vector<std::string> &missingTargets)
|
std::vector<std::string> &missingTargets)
|
||||||
{
|
{
|
||||||
std::string::size_type pos = 0;
|
std::string::size_type pos = 0;
|
||||||
|
@ -396,6 +399,57 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string errorString;
|
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;
|
pos = 0;
|
||||||
lastPos = pos;
|
lastPos = pos;
|
||||||
while((pos = input.find("$<TARGET_NAME:", lastPos)) != input.npos)
|
while((pos = input.find("$<TARGET_NAME:", lastPos)) != input.npos)
|
||||||
|
@ -491,7 +545,7 @@ cmExportFileGenerator
|
||||||
preprocessRule);
|
preprocessRule);
|
||||||
if (!prepro.empty())
|
if (!prepro.empty())
|
||||||
{
|
{
|
||||||
this->ResolveTargetsInGeneratorExpressions(prepro, target,
|
this->ResolveTargetsInGeneratorExpressions(prepro, target, 0,
|
||||||
missingTargets,
|
missingTargets,
|
||||||
ReplaceFreeTargets);
|
ReplaceFreeTargets);
|
||||||
properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro;
|
properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro;
|
||||||
|
|
|
@ -119,7 +119,7 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
void ResolveTargetsInGeneratorExpressions(std::string &input,
|
void ResolveTargetsInGeneratorExpressions(std::string &input,
|
||||||
cmTarget* target,
|
cmTarget* target, const char *propName,
|
||||||
std::vector<std::string> &missingTargets,
|
std::vector<std::string> &missingTargets,
|
||||||
FreeTargetsReplace replace = NoReplaceFreeTargets);
|
FreeTargetsReplace replace = NoReplaceFreeTargets);
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ private:
|
||||||
std::vector<std::string> &missingTargets);
|
std::vector<std::string> &missingTargets);
|
||||||
|
|
||||||
void ResolveTargetsInGeneratorExpression(std::string &input,
|
void ResolveTargetsInGeneratorExpression(std::string &input,
|
||||||
cmTarget* target,
|
cmTarget* target, const char *propName,
|
||||||
std::vector<std::string> &missingTargets);
|
std::vector<std::string> &missingTargets);
|
||||||
|
|
||||||
virtual void ReplaceInstallPrefix(std::string &input);
|
virtual void ReplaceInstallPrefix(std::string &input);
|
||||||
|
|
|
@ -637,6 +637,89 @@ static const struct InstallPrefixNode : public cmGeneratorExpressionNode
|
||||||
|
|
||||||
} installPrefixNode;
|
} 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>
|
template<bool linker, bool soname>
|
||||||
struct TargetFilesystemArtifactResultCreator
|
struct TargetFilesystemArtifactResultCreator
|
||||||
|
@ -874,6 +957,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
|
||||||
return &targetDefinedNode;
|
return &targetDefinedNode;
|
||||||
else if (identifier == "INSTALL_PREFIX")
|
else if (identifier == "INSTALL_PREFIX")
|
||||||
return &installPrefixNode;
|
return &installPrefixNode;
|
||||||
|
else if (identifier == "LINKED")
|
||||||
|
return &linkedNode;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,15 @@ add_executable(consumer
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
|
"${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
|
target_compile_definitions(consumer
|
||||||
PRIVATE $<TARGET_PROPERTY:target_compile_definitions,INTERFACE_COMPILE_DEFINITIONS>
|
PRIVATE $<TARGET_PROPERTY:target_compile_definitions,INTERFACE_COMPILE_DEFINITIONS>
|
||||||
$<$<TARGET_DEFINED:notdefined>:SHOULD_NOT_BE_DEFINED>
|
$<$<TARGET_DEFINED:notdefined>:SHOULD_NOT_BE_DEFINED>
|
||||||
$<$<TARGET_DEFINED:target_compile_definitions>:SHOULD_BE_DEFINED>
|
$<$<TARGET_DEFINED:target_compile_definitions>:SHOULD_BE_DEFINED>
|
||||||
|
$<LINKED:linked>
|
||||||
-DDASH_D_DEFINE
|
-DDASH_D_DEFINE
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,4 +23,8 @@
|
||||||
#error Expected DASH_D_DEFINE
|
#error Expected DASH_D_DEFINE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MY_LINKED_DEFINE
|
||||||
|
#error Expected MY_LINKED_DEFINE
|
||||||
|
#endif
|
||||||
|
|
||||||
int main() { return 0; }
|
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(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/cure")
|
||||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cure/common.h" "#define CURE_DEFINE\n")
|
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
|
add_executable(target_include_directories
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
|
||||||
)
|
)
|
||||||
|
@ -42,7 +45,13 @@ add_executable(consumer
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
|
"${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
|
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
|
relative_dir
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "publicinclude.h"
|
#include "publicinclude.h"
|
||||||
#include "interfaceinclude.h"
|
#include "interfaceinclude.h"
|
||||||
#include "relative_dir.h"
|
#include "relative_dir.h"
|
||||||
|
#include "linkedinclude.h"
|
||||||
|
|
||||||
#ifdef PRIVATEINCLUDE_DEFINE
|
#ifdef PRIVATEINCLUDE_DEFINE
|
||||||
#error Unexpected PRIVATEINCLUDE_DEFINE
|
#error Unexpected PRIVATEINCLUDE_DEFINE
|
||||||
|
@ -24,4 +25,8 @@
|
||||||
#error Expected RELATIVE_DIR_DEFINE
|
#error Expected RELATIVE_DIR_DEFINE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef LINKEDINCLUDE_DEFINE
|
||||||
|
#error Expected LINKEDINCLUDE_DEFINE
|
||||||
|
#endif
|
||||||
|
|
||||||
int main() { return 0; }
|
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(BadInvalidName6)
|
||||||
run_cmake(BadInvalidName7)
|
run_cmake(BadInvalidName7)
|
||||||
run_cmake(BadInvalidName8)
|
run_cmake(BadInvalidName8)
|
||||||
|
run_cmake(BadLinked)
|
||||||
|
|
Loading…
Reference in New Issue