mirror of
https://github.com/Kitware/CMake.git
synced 2025-06-09 23:47:26 +08:00

These generator expressions can only be used in link options properties. These expressions return the arguments respectively for device and host link step, otherwise return an empty string.
2564 lines
88 KiB
C++
2564 lines
88 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
#include "cmGeneratorExpressionNode.h"
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cerrno>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <sstream>
|
|
#include <utility>
|
|
|
|
#include <cm/iterator>
|
|
#include <cm/string_view>
|
|
#include <cm/vector>
|
|
#include <cmext/algorithm>
|
|
|
|
#include "cmsys/RegularExpression.hxx"
|
|
#include "cmsys/String.h"
|
|
|
|
#include "cm_static_string_view.hxx"
|
|
|
|
#include "cmAlgorithms.h"
|
|
#include "cmGeneratorExpression.h"
|
|
#include "cmGeneratorExpressionContext.h"
|
|
#include "cmGeneratorExpressionDAGChecker.h"
|
|
#include "cmGeneratorExpressionEvaluator.h"
|
|
#include "cmGeneratorTarget.h"
|
|
#include "cmGlobalGenerator.h"
|
|
#include "cmLinkItem.h"
|
|
#include "cmLocalGenerator.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmMessageType.h"
|
|
#include "cmOutputConverter.h"
|
|
#include "cmPolicies.h"
|
|
#include "cmRange.h"
|
|
#include "cmState.h"
|
|
#include "cmStateSnapshot.h"
|
|
#include "cmStateTypes.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmSystemTools.h"
|
|
#include "cmTarget.h"
|
|
#include "cmake.h"
|
|
|
|
std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
|
|
std::string const& prop, cmLocalGenerator* lg,
|
|
cmGeneratorExpressionContext* context, cmGeneratorTarget const* headTarget,
|
|
cmGeneratorExpressionDAGChecker* dagChecker,
|
|
cmGeneratorTarget const* currentTarget)
|
|
{
|
|
cmGeneratorExpression ge(context->Backtrace);
|
|
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
|
|
cge->SetEvaluateForBuildsystem(context->EvaluateForBuildsystem);
|
|
cge->SetQuiet(context->Quiet);
|
|
std::string result =
|
|
cge->Evaluate(lg, context->Config, headTarget, dagChecker, currentTarget,
|
|
context->Language);
|
|
if (cge->GetHadContextSensitiveCondition()) {
|
|
context->HadContextSensitiveCondition = true;
|
|
}
|
|
if (cge->GetHadHeadSensitiveCondition()) {
|
|
context->HadHeadSensitiveCondition = true;
|
|
}
|
|
if (cge->GetHadLinkLanguageSensitiveCondition()) {
|
|
context->HadLinkLanguageSensitiveCondition = true;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static const struct ZeroNode : public cmGeneratorExpressionNode
|
|
{
|
|
ZeroNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
bool GeneratesContent() const override { return false; }
|
|
|
|
bool AcceptsArbitraryContentParameter() const override { return true; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& /*parameters*/,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
return std::string();
|
|
}
|
|
} zeroNode;
|
|
|
|
static const struct OneNode : public cmGeneratorExpressionNode
|
|
{
|
|
OneNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
bool AcceptsArbitraryContentParameter() const override { return true; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
return parameters.front();
|
|
}
|
|
} oneNode;
|
|
|
|
static const struct OneNode buildInterfaceNode;
|
|
|
|
static const struct ZeroNode installInterfaceNode;
|
|
|
|
struct BooleanOpNode : public cmGeneratorExpressionNode
|
|
{
|
|
BooleanOpNode(const char* op_, const char* successVal_,
|
|
const char* failureVal_)
|
|
: op(op_)
|
|
, successVal(successVal_)
|
|
, failureVal(failureVal_)
|
|
{
|
|
}
|
|
|
|
int NumExpectedParameters() const override { return OneOrMoreParameters; }
|
|
|
|
std::string Evaluate(const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker*) const override
|
|
{
|
|
for (std::string const& param : parameters) {
|
|
if (param == this->failureVal) {
|
|
return this->failureVal;
|
|
}
|
|
if (param != this->successVal) {
|
|
std::ostringstream e;
|
|
e << "Parameters to $<" << this->op;
|
|
e << "> must resolve to either '0' or '1'.";
|
|
reportError(context, content->GetOriginalExpression(), e.str());
|
|
return std::string();
|
|
}
|
|
}
|
|
return this->successVal;
|
|
}
|
|
|
|
const char *const op, *const successVal, *const failureVal;
|
|
};
|
|
|
|
static const BooleanOpNode andNode("AND", "1", "0"), orNode("OR", "0", "1");
|
|
|
|
static const struct NotNode : public cmGeneratorExpressionNode
|
|
{
|
|
NotNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
if (parameters.front() != "0" && parameters.front() != "1") {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<NOT> parameter must resolve to exactly one '0' or '1' value.");
|
|
return std::string();
|
|
}
|
|
return parameters.front() == "0" ? "1" : "0";
|
|
}
|
|
} notNode;
|
|
|
|
static const struct BoolNode : public cmGeneratorExpressionNode
|
|
{
|
|
BoolNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 1; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
return !cmIsOff(parameters.front()) ? "1" : "0";
|
|
}
|
|
} boolNode;
|
|
|
|
static const struct IfNode : public cmGeneratorExpressionNode
|
|
{
|
|
IfNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 3; }
|
|
|
|
std::string Evaluate(const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker*) const override
|
|
{
|
|
if (parameters[0] != "1" && parameters[0] != "0") {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"First parameter to $<IF> must resolve to exactly one '0' "
|
|
"or '1' value.");
|
|
return std::string();
|
|
}
|
|
return parameters[0] == "1" ? parameters[1] : parameters[2];
|
|
}
|
|
} ifNode;
|
|
|
|
static const struct StrEqualNode : public cmGeneratorExpressionNode
|
|
{
|
|
StrEqualNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 2; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
return parameters.front() == parameters[1] ? "1" : "0";
|
|
}
|
|
} strEqualNode;
|
|
|
|
static const struct EqualNode : public cmGeneratorExpressionNode
|
|
{
|
|
EqualNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 2; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
long numbers[2];
|
|
for (int i = 0; i < 2; ++i) {
|
|
if (!ParameterToLong(parameters[i].c_str(), &numbers[i])) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<EQUAL> parameter " + parameters[i] +
|
|
" is not a valid integer.");
|
|
return {};
|
|
}
|
|
}
|
|
return numbers[0] == numbers[1] ? "1" : "0";
|
|
}
|
|
|
|
static bool ParameterToLong(const char* param, long* outResult)
|
|
{
|
|
const char isNegative = param[0] == '-';
|
|
|
|
int base = 0;
|
|
if (cmHasLiteralPrefix(param, "0b") || cmHasLiteralPrefix(param, "0B")) {
|
|
base = 2;
|
|
param += 2;
|
|
} else if (cmHasLiteralPrefix(param, "-0b") ||
|
|
cmHasLiteralPrefix(param, "-0B") ||
|
|
cmHasLiteralPrefix(param, "+0b") ||
|
|
cmHasLiteralPrefix(param, "+0B")) {
|
|
base = 2;
|
|
param += 3;
|
|
}
|
|
|
|
char* pEnd;
|
|
long result = strtol(param, &pEnd, base);
|
|
if (pEnd == param || *pEnd != '\0' || errno == ERANGE) {
|
|
return false;
|
|
}
|
|
if (isNegative && result > 0) {
|
|
result *= -1;
|
|
}
|
|
*outResult = result;
|
|
return true;
|
|
}
|
|
} equalNode;
|
|
|
|
static const struct InListNode : public cmGeneratorExpressionNode
|
|
{
|
|
InListNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 2; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
std::vector<std::string> values;
|
|
std::vector<std::string> checkValues;
|
|
bool check = false;
|
|
switch (context->LG->GetPolicyStatus(cmPolicies::CMP0085)) {
|
|
case cmPolicies::WARN:
|
|
if (parameters.front().empty()) {
|
|
check = true;
|
|
cmExpandList(parameters[1], checkValues, true);
|
|
}
|
|
CM_FALLTHROUGH;
|
|
case cmPolicies::OLD:
|
|
cmExpandList(parameters[1], values);
|
|
if (check && values != checkValues) {
|
|
std::ostringstream e;
|
|
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0085)
|
|
<< "\nSearch Item:\n \"" << parameters.front()
|
|
<< "\"\nList:\n \"" << parameters[1] << "\"\n";
|
|
context->LG->GetCMakeInstance()->IssueMessage(
|
|
MessageType ::AUTHOR_WARNING, e.str(), context->Backtrace);
|
|
return "0";
|
|
}
|
|
if (values.empty()) {
|
|
return "0";
|
|
}
|
|
break;
|
|
case cmPolicies::REQUIRED_IF_USED:
|
|
case cmPolicies::REQUIRED_ALWAYS:
|
|
case cmPolicies::NEW:
|
|
cmExpandList(parameters[1], values, true);
|
|
break;
|
|
}
|
|
|
|
return cm::contains(values, parameters.front()) ? "1" : "0";
|
|
}
|
|
} inListNode;
|
|
|
|
static const struct FilterNode : public cmGeneratorExpressionNode
|
|
{
|
|
FilterNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 3; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
if (parameters.size() != 3) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<FILTER:...> expression requires three parameters");
|
|
return {};
|
|
}
|
|
|
|
if (parameters[1] != "INCLUDE" && parameters[1] != "EXCLUDE") {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE");
|
|
return {};
|
|
}
|
|
|
|
const bool exclude = parameters[1] == "EXCLUDE";
|
|
|
|
cmsys::RegularExpression re;
|
|
if (!re.compile(parameters[2])) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<FILTER:...> failed to compile regex");
|
|
return {};
|
|
}
|
|
|
|
std::vector<std::string> values;
|
|
std::vector<std::string> result;
|
|
cmExpandList(parameters.front(), values, true);
|
|
|
|
std::copy_if(values.cbegin(), values.cend(), std::back_inserter(result),
|
|
[&re, exclude](std::string const& input) {
|
|
return exclude ^ re.find(input);
|
|
});
|
|
return cmJoin(cmMakeRange(result.cbegin(), result.cend()), ";");
|
|
}
|
|
} filterNode;
|
|
|
|
static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode
|
|
{
|
|
RemoveDuplicatesNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 1; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
if (parameters.size() != 1) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<REMOVE_DUPLICATES:...> expression requires one parameter");
|
|
}
|
|
|
|
std::vector<std::string> values = cmExpandedList(parameters.front(), true);
|
|
|
|
auto valuesEnd = cmRemoveDuplicates(values);
|
|
auto valuesBegin = values.cbegin();
|
|
return cmJoin(cmMakeRange(valuesBegin, valuesEnd), ";");
|
|
}
|
|
|
|
} removeDuplicatesNode;
|
|
|
|
static const struct TargetExistsNode : public cmGeneratorExpressionNode
|
|
{
|
|
TargetExistsNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 1; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
if (parameters.size() != 1) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<TARGET_EXISTS:...> expression requires one parameter");
|
|
return std::string();
|
|
}
|
|
|
|
std::string targetName = parameters.front();
|
|
if (targetName.empty() ||
|
|
!cmGeneratorExpression::IsValidTargetName(targetName)) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<TARGET_EXISTS:tgt> expression requires a non-empty "
|
|
"valid target name.");
|
|
return std::string();
|
|
}
|
|
|
|
return context->LG->GetMakefile()->FindTargetToUse(targetName) ? "1" : "0";
|
|
}
|
|
} targetExistsNode;
|
|
|
|
static const struct TargetNameIfExistsNode : public cmGeneratorExpressionNode
|
|
{
|
|
TargetNameIfExistsNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 1; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
if (parameters.size() != 1) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<TARGET_NAME_IF_EXISTS:...> expression requires one "
|
|
"parameter");
|
|
return std::string();
|
|
}
|
|
|
|
std::string targetName = parameters.front();
|
|
if (targetName.empty() ||
|
|
!cmGeneratorExpression::IsValidTargetName(targetName)) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<TARGET_NAME_IF_EXISTS:tgt> expression requires a "
|
|
"non-empty valid target name.");
|
|
return std::string();
|
|
}
|
|
|
|
return context->LG->GetMakefile()->FindTargetToUse(targetName)
|
|
? targetName
|
|
: std::string();
|
|
}
|
|
} targetNameIfExistsNode;
|
|
|
|
struct GenexEvaluator : public cmGeneratorExpressionNode
|
|
{
|
|
GenexEvaluator() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
protected:
|
|
std::string EvaluateExpression(
|
|
const std::string& genexOperator, const std::string& expression,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagCheckerParent) const
|
|
{
|
|
if (context->HeadTarget) {
|
|
cmGeneratorExpressionDAGChecker dagChecker(
|
|
context->Backtrace, context->HeadTarget,
|
|
genexOperator + ":" + expression, content, dagCheckerParent);
|
|
switch (dagChecker.Check()) {
|
|
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
|
|
case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: {
|
|
dagChecker.ReportError(context, content->GetOriginalExpression());
|
|
return std::string();
|
|
}
|
|
case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
|
|
case cmGeneratorExpressionDAGChecker::DAG:
|
|
break;
|
|
}
|
|
|
|
return this->EvaluateDependentExpression(
|
|
expression, context->LG, context, context->HeadTarget, &dagChecker,
|
|
context->CurrentTarget);
|
|
}
|
|
|
|
return this->EvaluateDependentExpression(
|
|
expression, context->LG, context, context->HeadTarget, dagCheckerParent,
|
|
context->CurrentTarget);
|
|
}
|
|
};
|
|
|
|
static const struct TargetGenexEvalNode : public GenexEvaluator
|
|
{
|
|
TargetGenexEvalNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 2; }
|
|
|
|
bool AcceptsArbitraryContentParameter() const override { return true; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
|
|
{
|
|
const std::string& targetName = parameters.front();
|
|
if (targetName.empty() ||
|
|
!cmGeneratorExpression::IsValidTargetName(targetName)) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<TARGET_GENEX_EVAL:tgt, ...> expression requires a "
|
|
"non-empty valid target name.");
|
|
return std::string();
|
|
}
|
|
|
|
const auto* target = context->LG->FindGeneratorTargetToUse(targetName);
|
|
if (!target) {
|
|
std::ostringstream e;
|
|
e << "$<TARGET_GENEX_EVAL:tgt, ...> target \"" << targetName
|
|
<< "\" not found.";
|
|
reportError(context, content->GetOriginalExpression(), e.str());
|
|
return std::string();
|
|
}
|
|
|
|
const std::string& expression = parameters[1];
|
|
if (expression.empty()) {
|
|
return expression;
|
|
}
|
|
|
|
cmGeneratorExpressionContext targetContext(
|
|
context->LG, context->Config, context->Quiet, target, target,
|
|
context->EvaluateForBuildsystem, context->Backtrace, context->Language);
|
|
|
|
return this->EvaluateExpression("TARGET_GENEX_EVAL", expression,
|
|
&targetContext, content, dagCheckerParent);
|
|
}
|
|
} targetGenexEvalNode;
|
|
|
|
static const struct GenexEvalNode : public GenexEvaluator
|
|
{
|
|
GenexEvalNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 1; }
|
|
|
|
bool AcceptsArbitraryContentParameter() const override { return true; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
|
|
{
|
|
const std::string& expression = parameters[0];
|
|
if (expression.empty()) {
|
|
return expression;
|
|
}
|
|
|
|
return this->EvaluateExpression("GENEX_EVAL", expression, context, content,
|
|
dagCheckerParent);
|
|
}
|
|
} genexEvalNode;
|
|
|
|
static const struct LowerCaseNode : public cmGeneratorExpressionNode
|
|
{
|
|
LowerCaseNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
bool AcceptsArbitraryContentParameter() const override { return true; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
return cmSystemTools::LowerCase(parameters.front());
|
|
}
|
|
} lowerCaseNode;
|
|
|
|
static const struct UpperCaseNode : public cmGeneratorExpressionNode
|
|
{
|
|
UpperCaseNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
bool AcceptsArbitraryContentParameter() const override { return true; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
return cmSystemTools::UpperCase(parameters.front());
|
|
}
|
|
} upperCaseNode;
|
|
|
|
static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode
|
|
{
|
|
MakeCIdentifierNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
bool AcceptsArbitraryContentParameter() const override { return true; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
return cmSystemTools::MakeCidentifier(parameters.front());
|
|
}
|
|
} makeCIdentifierNode;
|
|
|
|
template <char C>
|
|
struct CharacterNode : public cmGeneratorExpressionNode
|
|
{
|
|
CharacterNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 0; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& /*parameters*/,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
return { C };
|
|
}
|
|
};
|
|
static const CharacterNode<'>'> angle_rNode;
|
|
static const CharacterNode<','> commaNode;
|
|
static const CharacterNode<';'> semicolonNode;
|
|
|
|
struct CompilerIdNode : public cmGeneratorExpressionNode
|
|
{
|
|
CompilerIdNode(const char* compilerLang)
|
|
: CompilerLanguage(compilerLang)
|
|
{
|
|
}
|
|
|
|
int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
if (!context->HeadTarget) {
|
|
std::ostringstream e;
|
|
e << "$<" << this->CompilerLanguage
|
|
<< "_COMPILER_ID> may only be used with binary targets. It may "
|
|
"not be used with add_custom_command or add_custom_target.";
|
|
reportError(context, content->GetOriginalExpression(), e.str());
|
|
return {};
|
|
}
|
|
return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
|
|
this->CompilerLanguage);
|
|
}
|
|
|
|
std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*unused*/,
|
|
const std::string& lang) const
|
|
{
|
|
std::string const& compilerId =
|
|
context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
|
|
"_COMPILER_ID");
|
|
if (parameters.empty()) {
|
|
return compilerId;
|
|
}
|
|
if (compilerId.empty()) {
|
|
return parameters.front().empty() ? "1" : "0";
|
|
}
|
|
static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
|
|
|
|
for (auto& param : parameters) {
|
|
|
|
if (!compilerIdValidator.find(param)) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"Expression syntax not recognized.");
|
|
return std::string();
|
|
}
|
|
|
|
if (strcmp(param.c_str(), compilerId.c_str()) == 0) {
|
|
return "1";
|
|
}
|
|
|
|
if (cmsysString_strcasecmp(param.c_str(), compilerId.c_str()) == 0) {
|
|
switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
|
|
case cmPolicies::WARN: {
|
|
context->LG->GetCMakeInstance()->IssueMessage(
|
|
MessageType::AUTHOR_WARNING,
|
|
cmPolicies::GetPolicyWarning(cmPolicies::CMP0044),
|
|
context->Backtrace);
|
|
CM_FALLTHROUGH;
|
|
}
|
|
case cmPolicies::OLD:
|
|
return "1";
|
|
case cmPolicies::NEW:
|
|
case cmPolicies::REQUIRED_ALWAYS:
|
|
case cmPolicies::REQUIRED_IF_USED:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return "0";
|
|
}
|
|
|
|
const char* const CompilerLanguage;
|
|
};
|
|
|
|
static const CompilerIdNode cCompilerIdNode("C"), cxxCompilerIdNode("CXX"),
|
|
cudaCompilerIdNode("CUDA"), objcCompilerIdNode("OBJC"),
|
|
objcxxCompilerIdNode("OBJCXX"), fortranCompilerIdNode("Fortran");
|
|
|
|
struct CompilerVersionNode : public cmGeneratorExpressionNode
|
|
{
|
|
CompilerVersionNode(const char* compilerLang)
|
|
: CompilerLanguage(compilerLang)
|
|
{
|
|
}
|
|
|
|
int NumExpectedParameters() const override { return OneOrZeroParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
if (!context->HeadTarget) {
|
|
std::ostringstream e;
|
|
e << "$<" << this->CompilerLanguage
|
|
<< "_COMPILER_VERSION> may only be used with binary targets. It "
|
|
"may not be used with add_custom_command or add_custom_target.";
|
|
reportError(context, content->GetOriginalExpression(), e.str());
|
|
return {};
|
|
}
|
|
return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
|
|
this->CompilerLanguage);
|
|
}
|
|
|
|
std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*unused*/,
|
|
const std::string& lang) const
|
|
{
|
|
std::string const& compilerVersion =
|
|
context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
|
|
"_COMPILER_VERSION");
|
|
if (parameters.empty()) {
|
|
return compilerVersion;
|
|
}
|
|
|
|
static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$");
|
|
if (!compilerIdValidator.find(parameters.front())) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"Expression syntax not recognized.");
|
|
return {};
|
|
}
|
|
if (compilerVersion.empty()) {
|
|
return parameters.front().empty() ? "1" : "0";
|
|
}
|
|
|
|
return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
|
|
parameters.front().c_str(),
|
|
compilerVersion.c_str())
|
|
? "1"
|
|
: "0";
|
|
}
|
|
|
|
const char* const CompilerLanguage;
|
|
};
|
|
|
|
static const CompilerVersionNode cCompilerVersionNode("C"),
|
|
cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"),
|
|
objcCompilerVersionNode("OBJC"), objcxxCompilerVersionNode("OBJCXX"),
|
|
fortranCompilerVersionNode("Fortran");
|
|
|
|
struct PlatformIdNode : public cmGeneratorExpressionNode
|
|
{
|
|
PlatformIdNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
std::string const& platformId =
|
|
context->LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME");
|
|
if (parameters.empty()) {
|
|
return platformId;
|
|
}
|
|
|
|
if (platformId.empty()) {
|
|
return parameters.front().empty() ? "1" : "0";
|
|
}
|
|
|
|
for (auto& param : parameters) {
|
|
if (param == platformId) {
|
|
return "1";
|
|
}
|
|
}
|
|
return "0";
|
|
}
|
|
} platformIdNode;
|
|
|
|
template <cmSystemTools::CompareOp Op>
|
|
struct VersionNode : public cmGeneratorExpressionNode
|
|
{
|
|
VersionNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 2; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
return cmSystemTools::VersionCompare(Op, parameters.front().c_str(),
|
|
parameters[1].c_str())
|
|
? "1"
|
|
: "0";
|
|
}
|
|
};
|
|
|
|
static const VersionNode<cmSystemTools::OP_GREATER> versionGreaterNode;
|
|
static const VersionNode<cmSystemTools::OP_GREATER_EQUAL> versionGreaterEqNode;
|
|
static const VersionNode<cmSystemTools::OP_LESS> versionLessNode;
|
|
static const VersionNode<cmSystemTools::OP_LESS_EQUAL> versionLessEqNode;
|
|
static const VersionNode<cmSystemTools::OP_EQUAL> versionEqualNode;
|
|
|
|
static const struct LinkOnlyNode : public cmGeneratorExpressionNode
|
|
{
|
|
LinkOnlyNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
if (!dagChecker) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<LINK_ONLY:...> may only be used for linking");
|
|
return std::string();
|
|
}
|
|
if (!dagChecker->GetTransitivePropertiesOnly()) {
|
|
return parameters.front();
|
|
}
|
|
return std::string();
|
|
}
|
|
} linkOnlyNode;
|
|
|
|
static const struct ConfigurationNode : public cmGeneratorExpressionNode
|
|
{
|
|
ConfigurationNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 0; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& /*parameters*/,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
context->HadContextSensitiveCondition = true;
|
|
return context->Config;
|
|
}
|
|
} configurationNode;
|
|
|
|
static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
|
|
{
|
|
ConfigurationTestNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return OneOrZeroParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
if (parameters.empty()) {
|
|
return configurationNode.Evaluate(parameters, context, content, nullptr);
|
|
}
|
|
static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
|
|
if (!configValidator.find(parameters.front())) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"Expression syntax not recognized.");
|
|
return std::string();
|
|
}
|
|
context->HadContextSensitiveCondition = true;
|
|
if (context->Config.empty()) {
|
|
return parameters.front().empty() ? "1" : "0";
|
|
}
|
|
|
|
if (cmsysString_strcasecmp(parameters.front().c_str(),
|
|
context->Config.c_str()) == 0) {
|
|
return "1";
|
|
}
|
|
|
|
if (context->CurrentTarget && context->CurrentTarget->IsImported()) {
|
|
cmProp loc = nullptr;
|
|
cmProp imp = nullptr;
|
|
std::string suffix;
|
|
if (context->CurrentTarget->Target->GetMappedConfig(context->Config, loc,
|
|
imp, suffix)) {
|
|
// This imported target has an appropriate location
|
|
// for this (possibly mapped) config.
|
|
// Check if there is a proper config mapping for the tested config.
|
|
std::vector<std::string> mappedConfigs;
|
|
std::string mapProp = cmStrCat(
|
|
"MAP_IMPORTED_CONFIG_", cmSystemTools::UpperCase(context->Config));
|
|
if (const char* mapValue =
|
|
context->CurrentTarget->GetProperty(mapProp)) {
|
|
cmExpandList(cmSystemTools::UpperCase(mapValue), mappedConfigs);
|
|
return cm::contains(mappedConfigs,
|
|
cmSystemTools::UpperCase(parameters.front()))
|
|
? "1"
|
|
: "0";
|
|
}
|
|
}
|
|
}
|
|
return "0";
|
|
}
|
|
} configurationTestNode;
|
|
|
|
static const struct JoinNode : public cmGeneratorExpressionNode
|
|
{
|
|
JoinNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 2; }
|
|
|
|
bool AcceptsArbitraryContentParameter() const override { return true; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
std::vector<std::string> list = cmExpandedList(parameters.front());
|
|
return cmJoin(list, parameters[1]);
|
|
}
|
|
} joinNode;
|
|
|
|
static const struct CompileLanguageNode : public cmGeneratorExpressionNode
|
|
{
|
|
CompileLanguageNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
if (context->Language.empty()) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<COMPILE_LANGUAGE:...> may only be used to specify include "
|
|
"directories, compile definitions, compile options, and to evaluate "
|
|
"components of the file(GENERATE) command.");
|
|
return std::string();
|
|
}
|
|
|
|
cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
|
|
std::string genName = gg->GetName();
|
|
if (genName.find("Makefiles") == std::string::npos &&
|
|
genName.find("Ninja") == std::string::npos &&
|
|
genName.find("Visual Studio") == std::string::npos &&
|
|
genName.find("Xcode") == std::string::npos &&
|
|
genName.find("Watcom WMake") == std::string::npos) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<COMPILE_LANGUAGE:...> not supported for this generator.");
|
|
return std::string();
|
|
}
|
|
if (parameters.empty()) {
|
|
return context->Language;
|
|
}
|
|
|
|
for (auto& param : parameters) {
|
|
if (context->Language == param) {
|
|
return "1";
|
|
}
|
|
}
|
|
return "0";
|
|
}
|
|
} languageNode;
|
|
|
|
static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
|
|
{
|
|
CompileLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return TwoOrMoreParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
if (!context->HeadTarget || context->Language.empty()) {
|
|
// reportError(context, content->GetOriginalExpression(), "");
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets "
|
|
"to specify include directories, compile definitions, and compile "
|
|
"options. It may not be used with the add_custom_command, "
|
|
"add_custom_target, or file(GENERATE) commands.");
|
|
return std::string();
|
|
}
|
|
cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
|
|
std::string genName = gg->GetName();
|
|
if (genName.find("Makefiles") == std::string::npos &&
|
|
genName.find("Ninja") == std::string::npos &&
|
|
genName.find("Visual Studio") == std::string::npos &&
|
|
genName.find("Xcode") == std::string::npos &&
|
|
genName.find("Watcom WMake") == std::string::npos) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<COMPILE_LANG_AND_ID:lang,id> not supported for this generator.");
|
|
return std::string();
|
|
}
|
|
|
|
const std::string& lang = context->Language;
|
|
if (lang == parameters.front()) {
|
|
std::vector<std::string> idParameter((parameters.cbegin() + 1),
|
|
parameters.cend());
|
|
return CompilerIdNode{ lang.c_str() }.EvaluateWithLanguage(
|
|
idParameter, context, content, dagChecker, lang);
|
|
}
|
|
return "0";
|
|
}
|
|
} languageAndIdNode;
|
|
|
|
static const struct LinkLanguageNode : public cmGeneratorExpressionNode
|
|
{
|
|
LinkLanguageNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
if (!context->HeadTarget || !dagChecker ||
|
|
!(dagChecker->EvaluatingLinkExpression() ||
|
|
dagChecker->EvaluatingLinkLibraries())) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<LINK_LANGUAGE:...> may only be used with binary targets "
|
|
"to specify link libraries, link directories, link options "
|
|
"and link depends.");
|
|
return std::string();
|
|
}
|
|
if (dagChecker->EvaluatingLinkLibraries() && parameters.empty()) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<LINK_LANGUAGE> is not supported in link libraries expression.");
|
|
return std::string();
|
|
}
|
|
|
|
cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
|
|
std::string genName = gg->GetName();
|
|
if (genName.find("Makefiles") == std::string::npos &&
|
|
genName.find("Ninja") == std::string::npos &&
|
|
genName.find("Visual Studio") == std::string::npos &&
|
|
genName.find("Xcode") == std::string::npos &&
|
|
genName.find("Watcom WMake") == std::string::npos) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<LINK_LANGUAGE:...> not supported for this generator.");
|
|
return std::string();
|
|
}
|
|
|
|
if (dagChecker->EvaluatingLinkLibraries()) {
|
|
context->HadHeadSensitiveCondition = true;
|
|
context->HadLinkLanguageSensitiveCondition = true;
|
|
}
|
|
|
|
if (parameters.empty()) {
|
|
return context->Language;
|
|
}
|
|
|
|
for (auto& param : parameters) {
|
|
if (context->Language == param) {
|
|
return "1";
|
|
}
|
|
}
|
|
return "0";
|
|
}
|
|
} linkLanguageNode;
|
|
|
|
namespace {
|
|
struct LinkerId
|
|
{
|
|
static std::string Evaluate(const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
const std::string& lang)
|
|
{
|
|
std::string const& linkerId =
|
|
context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
|
|
"_COMPILER_ID");
|
|
if (parameters.empty()) {
|
|
return linkerId;
|
|
}
|
|
if (linkerId.empty()) {
|
|
return parameters.front().empty() ? "1" : "0";
|
|
}
|
|
static cmsys::RegularExpression linkerIdValidator("^[A-Za-z0-9_]*$");
|
|
|
|
for (auto& param : parameters) {
|
|
if (!linkerIdValidator.find(param)) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"Expression syntax not recognized.");
|
|
return std::string();
|
|
}
|
|
|
|
if (param == linkerId) {
|
|
return "1";
|
|
}
|
|
}
|
|
return "0";
|
|
}
|
|
};
|
|
}
|
|
|
|
static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode
|
|
{
|
|
LinkLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return TwoOrMoreParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
if (!context->HeadTarget || !dagChecker ||
|
|
!(dagChecker->EvaluatingLinkExpression() ||
|
|
dagChecker->EvaluatingLinkLibraries())) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<LINK_LANG_AND_ID:lang,id> may only be used with binary targets "
|
|
"to specify link libraries, link directories, link options, and link "
|
|
"depends.");
|
|
return std::string();
|
|
}
|
|
|
|
cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
|
|
std::string genName = gg->GetName();
|
|
if (genName.find("Makefiles") == std::string::npos &&
|
|
genName.find("Ninja") == std::string::npos &&
|
|
genName.find("Visual Studio") == std::string::npos &&
|
|
genName.find("Xcode") == std::string::npos &&
|
|
genName.find("Watcom WMake") == std::string::npos) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<LINK_LANG_AND_ID:lang,id> not supported for this generator.");
|
|
return std::string();
|
|
}
|
|
|
|
if (dagChecker->EvaluatingLinkLibraries()) {
|
|
context->HadHeadSensitiveCondition = true;
|
|
context->HadLinkLanguageSensitiveCondition = true;
|
|
}
|
|
|
|
const std::string& lang = context->Language;
|
|
if (lang == parameters.front()) {
|
|
std::vector<std::string> idParameter((parameters.cbegin() + 1),
|
|
parameters.cend());
|
|
return LinkerId::Evaluate(idParameter, context, content, lang);
|
|
}
|
|
return "0";
|
|
}
|
|
} linkLanguageAndIdNode;
|
|
|
|
static const struct HostLinkNode : public cmGeneratorExpressionNode
|
|
{
|
|
HostLinkNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
if (!context->HeadTarget || !dagChecker ||
|
|
!dagChecker->EvaluatingLinkOptionsExpression()) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<HOST_LINK:...> may only be used with binary targets "
|
|
"to specify link options.");
|
|
return std::string();
|
|
}
|
|
|
|
return context->HeadTarget->IsDeviceLink() ? std::string()
|
|
: cmJoin(parameters, ";");
|
|
}
|
|
} hostLinkNode;
|
|
|
|
static const struct DeviceLinkNode : public cmGeneratorExpressionNode
|
|
{
|
|
DeviceLinkNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
if (!context->HeadTarget || !dagChecker ||
|
|
!dagChecker->EvaluatingLinkOptionsExpression()) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"$<DEVICE_LINK:...> may only be used with binary targets "
|
|
"to specify link options.");
|
|
return std::string();
|
|
}
|
|
|
|
if (context->HeadTarget->IsDeviceLink()) {
|
|
std::vector<std::string> list;
|
|
cmExpandLists(parameters.begin(), parameters.end(), list);
|
|
const auto DL_BEGIN = "<DEVICE_LINK>"_s;
|
|
const auto DL_END = "</DEVICE_LINK>"_s;
|
|
cm::erase_if(list, [&](const std::string& item) {
|
|
return item == DL_BEGIN || item == DL_END;
|
|
});
|
|
|
|
list.insert(list.begin(), static_cast<std::string>(DL_BEGIN));
|
|
list.push_back(static_cast<std::string>(DL_END));
|
|
|
|
return cmJoin(list, ";");
|
|
}
|
|
|
|
return std::string();
|
|
}
|
|
} deviceLinkNode;
|
|
|
|
std::string getLinkedTargetsContent(
|
|
cmGeneratorTarget const* target, std::string const& prop,
|
|
cmGeneratorExpressionContext* context,
|
|
cmGeneratorExpressionDAGChecker* dagChecker)
|
|
{
|
|
std::string result;
|
|
if (cmLinkImplementationLibraries const* impl =
|
|
target->GetLinkImplementationLibraries(context->Config)) {
|
|
for (cmLinkImplItem const& lib : impl->Libraries) {
|
|
if (lib.Target) {
|
|
// Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
|
|
// caller's property and hand-evaluate it as if it were compiled.
|
|
// Create a context as cmCompiledGeneratorExpression::Evaluate does.
|
|
cmGeneratorExpressionContext libContext(
|
|
target->GetLocalGenerator(), context->Config, context->Quiet, target,
|
|
target, context->EvaluateForBuildsystem, lib.Backtrace,
|
|
context->Language);
|
|
std::string libResult =
|
|
lib.Target->EvaluateInterfaceProperty(prop, &libContext, dagChecker);
|
|
if (!libResult.empty()) {
|
|
if (result.empty()) {
|
|
result = std::move(libResult);
|
|
} else {
|
|
result.reserve(result.size() + 1 + libResult.size());
|
|
result += ";";
|
|
result += libResult;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static const struct TargetPropertyNode : public cmGeneratorExpressionNode
|
|
{
|
|
TargetPropertyNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
// This node handles errors on parameter count itself.
|
|
int NumExpectedParameters() const override { return OneOrMoreParameters; }
|
|
|
|
static const char* GetErrorText(std::string const& targetName,
|
|
std::string const& propertyName)
|
|
{
|
|
static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
|
|
if (targetName.empty() && propertyName.empty()) {
|
|
return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
|
|
"target name and property name.";
|
|
}
|
|
if (targetName.empty()) {
|
|
return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
|
|
"target name.";
|
|
}
|
|
if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
|
|
if (!propertyNameValidator.find(propertyName)) {
|
|
return "Target name and property name not supported.";
|
|
}
|
|
return "Target name not supported.";
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
|
|
{
|
|
static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
|
|
|
|
cmGeneratorTarget const* target = nullptr;
|
|
std::string targetName;
|
|
std::string propertyName;
|
|
|
|
if (parameters.size() == 2) {
|
|
targetName = parameters[0];
|
|
propertyName = parameters[1];
|
|
|
|
if (const char* e = GetErrorText(targetName, propertyName)) {
|
|
reportError(context, content->GetOriginalExpression(), e);
|
|
return std::string();
|
|
}
|
|
if (propertyName == "ALIASED_TARGET"_s) {
|
|
if (context->LG->GetMakefile()->IsAlias(targetName)) {
|
|
if (cmGeneratorTarget* tgt =
|
|
context->LG->FindGeneratorTargetToUse(targetName)) {
|
|
return tgt->GetName();
|
|
}
|
|
}
|
|
return std::string();
|
|
}
|
|
target = context->LG->FindGeneratorTargetToUse(targetName);
|
|
|
|
if (!target) {
|
|
std::ostringstream e;
|
|
e << "Target \"" << targetName << "\" not found.";
|
|
reportError(context, content->GetOriginalExpression(), e.str());
|
|
return std::string();
|
|
}
|
|
context->AllTargets.insert(target);
|
|
|
|
} else if (parameters.size() == 1) {
|
|
target = context->HeadTarget;
|
|
propertyName = parameters[0];
|
|
|
|
// Keep track of the properties seen while processing.
|
|
// The evaluation of the LINK_LIBRARIES generator expressions
|
|
// will check this to ensure that properties have one consistent
|
|
// value for all evaluations.
|
|
context->SeenTargetProperties.insert(propertyName);
|
|
|
|
context->HadHeadSensitiveCondition = true;
|
|
if (!target) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<TARGET_PROPERTY:prop> may only be used with binary targets. "
|
|
"It may not be used with add_custom_command or add_custom_target. "
|
|
" "
|
|
"Specify the target to read a property from using the "
|
|
"$<TARGET_PROPERTY:tgt,prop> signature instead.");
|
|
return std::string();
|
|
}
|
|
} else {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<TARGET_PROPERTY:...> expression requires one or two parameters");
|
|
return std::string();
|
|
}
|
|
|
|
if (propertyName == "SOURCES") {
|
|
context->SourceSensitiveTargets.insert(target);
|
|
}
|
|
|
|
if (propertyName.empty()) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<TARGET_PROPERTY:...> expression requires a non-empty property "
|
|
"name.");
|
|
return std::string();
|
|
}
|
|
|
|
if (!propertyNameValidator.find(propertyName)) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"Property name not supported.");
|
|
return std::string();
|
|
}
|
|
|
|
assert(target);
|
|
|
|
if (propertyName == "LINKER_LANGUAGE") {
|
|
if (target->LinkLanguagePropagatesToDependents() && dagCheckerParent &&
|
|
(dagCheckerParent->EvaluatingLinkLibraries() ||
|
|
dagCheckerParent->EvaluatingSources())) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"LINKER_LANGUAGE target property can not be used while evaluating "
|
|
"link libraries for a static library");
|
|
return std::string();
|
|
}
|
|
return target->GetLinkerLanguage(context->Config);
|
|
}
|
|
|
|
std::string interfacePropertyName;
|
|
bool isInterfaceProperty = false;
|
|
|
|
#define POPULATE_INTERFACE_PROPERTY_NAME(prop) \
|
|
if (propertyName == #prop) { \
|
|
interfacePropertyName = "INTERFACE_" #prop; \
|
|
} else if (propertyName == "INTERFACE_" #prop) { \
|
|
interfacePropertyName = "INTERFACE_" #prop; \
|
|
isInterfaceProperty = true; \
|
|
} else
|
|
|
|
CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME)
|
|
// Note that the above macro terminates with an else
|
|
/* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) {
|
|
cmPolicies::PolicyStatus polSt =
|
|
context->LG->GetPolicyStatus(cmPolicies::CMP0043);
|
|
if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
|
|
interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS";
|
|
}
|
|
}
|
|
#undef POPULATE_INTERFACE_PROPERTY_NAME
|
|
|
|
bool evaluatingLinkLibraries = false;
|
|
|
|
if (dagCheckerParent) {
|
|
if (dagCheckerParent->EvaluatingGenexExpression() ||
|
|
dagCheckerParent->EvaluatingPICExpression()) {
|
|
// No check required.
|
|
} else if (dagCheckerParent->EvaluatingLinkLibraries()) {
|
|
evaluatingLinkLibraries = true;
|
|
if (!interfacePropertyName.empty()) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<TARGET_PROPERTY:...> expression in link libraries "
|
|
"evaluation depends on target property which is transitive "
|
|
"over the link libraries, creating a recursion.");
|
|
return std::string();
|
|
}
|
|
} else {
|
|
#define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) dagCheckerParent->METHOD() ||
|
|
assert(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
|
|
ASSERT_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(clang-tidy)
|
|
#undef ASSERT_TRANSITIVE_PROPERTY_METHOD
|
|
}
|
|
}
|
|
|
|
if (isInterfaceProperty) {
|
|
return target->EvaluateInterfaceProperty(propertyName, context,
|
|
dagCheckerParent);
|
|
}
|
|
|
|
cmGeneratorExpressionDAGChecker dagChecker(
|
|
context->Backtrace, target, 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::ALREADY_SEEN:
|
|
// We handle transitive properties above. For non-transitive
|
|
// properties we accept repeats anyway.
|
|
case cmGeneratorExpressionDAGChecker::DAG:
|
|
break;
|
|
}
|
|
|
|
std::string result;
|
|
bool haveProp = false;
|
|
if (const char* p = target->GetProperty(propertyName)) {
|
|
result = p;
|
|
haveProp = true;
|
|
} else if (evaluatingLinkLibraries) {
|
|
return std::string();
|
|
}
|
|
|
|
if (!haveProp && !target->IsImported() &&
|
|
target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
|
|
if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
|
|
context->Config)) {
|
|
context->HadContextSensitiveCondition = true;
|
|
return target->GetLinkInterfaceDependentBoolProperty(propertyName,
|
|
context->Config)
|
|
? "1"
|
|
: "0";
|
|
}
|
|
if (target->IsLinkInterfaceDependentStringProperty(propertyName,
|
|
context->Config)) {
|
|
context->HadContextSensitiveCondition = true;
|
|
const char* propContent =
|
|
target->GetLinkInterfaceDependentStringProperty(propertyName,
|
|
context->Config);
|
|
return propContent ? propContent : "";
|
|
}
|
|
if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
|
|
context->Config)) {
|
|
context->HadContextSensitiveCondition = true;
|
|
const char* propContent =
|
|
target->GetLinkInterfaceDependentNumberMinProperty(propertyName,
|
|
context->Config);
|
|
return propContent ? propContent : "";
|
|
}
|
|
if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
|
|
context->Config)) {
|
|
context->HadContextSensitiveCondition = true;
|
|
const char* propContent =
|
|
target->GetLinkInterfaceDependentNumberMaxProperty(propertyName,
|
|
context->Config);
|
|
return propContent ? propContent : "";
|
|
}
|
|
}
|
|
|
|
if (!target->IsImported() && dagCheckerParent &&
|
|
!dagCheckerParent->EvaluatingLinkLibraries()) {
|
|
if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
|
|
context->Config)) {
|
|
context->HadContextSensitiveCondition = true;
|
|
const char* propContent =
|
|
target->GetLinkInterfaceDependentNumberMinProperty(propertyName,
|
|
context->Config);
|
|
return propContent ? propContent : "";
|
|
}
|
|
if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
|
|
context->Config)) {
|
|
context->HadContextSensitiveCondition = true;
|
|
const char* propContent =
|
|
target->GetLinkInterfaceDependentNumberMaxProperty(propertyName,
|
|
context->Config);
|
|
return propContent ? propContent : "";
|
|
}
|
|
}
|
|
|
|
if (!interfacePropertyName.empty()) {
|
|
result = this->EvaluateDependentExpression(result, context->LG, context,
|
|
target, &dagChecker, target);
|
|
std::string linkedTargetsContent = getLinkedTargetsContent(
|
|
target, interfacePropertyName, context, &dagChecker);
|
|
if (!linkedTargetsContent.empty()) {
|
|
result += (result.empty() ? "" : ";") + linkedTargetsContent;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} targetPropertyNode;
|
|
|
|
static const struct TargetNameNode : public cmGeneratorExpressionNode
|
|
{
|
|
TargetNameNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
bool GeneratesContent() const override { return true; }
|
|
|
|
bool AcceptsArbitraryContentParameter() const override { return true; }
|
|
bool RequiresLiteralInput() const override { return true; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* /*context*/,
|
|
const GeneratorExpressionContent* /*content*/,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
return parameters.front();
|
|
}
|
|
|
|
int NumExpectedParameters() const override { return 1; }
|
|
|
|
} targetNameNode;
|
|
|
|
static const struct TargetObjectsNode : public cmGeneratorExpressionNode
|
|
{
|
|
TargetObjectsNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
std::string tgtName = parameters.front();
|
|
cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName);
|
|
if (!gt) {
|
|
std::ostringstream e;
|
|
e << "Objects of target \"" << tgtName
|
|
<< "\" referenced but no such target exists.";
|
|
reportError(context, content->GetOriginalExpression(), e.str());
|
|
return std::string();
|
|
}
|
|
cmStateEnums::TargetType type = gt->GetType();
|
|
if (type != cmStateEnums::EXECUTABLE &&
|
|
type != cmStateEnums::STATIC_LIBRARY &&
|
|
type != cmStateEnums::SHARED_LIBRARY &&
|
|
type != cmStateEnums::MODULE_LIBRARY &&
|
|
type != cmStateEnums::OBJECT_LIBRARY) {
|
|
std::ostringstream e;
|
|
e << "Objects of target \"" << tgtName
|
|
<< "\" referenced but is not an allowed library types (EXECUTABLE, "
|
|
<< "STATIC, SHARED, MODULE, OBJECT).";
|
|
reportError(context, content->GetOriginalExpression(), e.str());
|
|
return std::string();
|
|
}
|
|
if (!context->EvaluateForBuildsystem) {
|
|
cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
|
|
std::string reason;
|
|
if (!gg->HasKnownObjectFileLocation(&reason)) {
|
|
std::ostringstream e;
|
|
e << "The evaluation of the TARGET_OBJECTS generator expression "
|
|
"is only suitable for consumption by CMake (limited"
|
|
<< reason
|
|
<< "). "
|
|
"It is not suitable for writing out elsewhere.";
|
|
reportError(context, content->GetOriginalExpression(), e.str());
|
|
return std::string();
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> objects;
|
|
|
|
if (gt->IsImported()) {
|
|
cmProp loc = nullptr;
|
|
cmProp imp = nullptr;
|
|
std::string suffix;
|
|
if (gt->Target->GetMappedConfig(context->Config, loc, imp, suffix)) {
|
|
cmExpandList(*loc, objects);
|
|
}
|
|
context->HadContextSensitiveCondition = true;
|
|
} else {
|
|
gt->GetTargetObjectNames(context->Config, objects);
|
|
|
|
std::string obj_dir;
|
|
if (context->EvaluateForBuildsystem) {
|
|
// Use object file directory with buildsystem placeholder.
|
|
obj_dir = gt->ObjectDirectory;
|
|
// Here we assume that the set of object files produced
|
|
// by an object library does not vary with configuration
|
|
// and do not set HadContextSensitiveCondition to true.
|
|
} else {
|
|
// Use object file directory with per-config location.
|
|
obj_dir = gt->GetObjectDirectory(context->Config);
|
|
context->HadContextSensitiveCondition = true;
|
|
}
|
|
|
|
for (std::string& o : objects) {
|
|
o = cmStrCat(obj_dir, o);
|
|
}
|
|
}
|
|
|
|
// Create the cmSourceFile instances in the referencing directory.
|
|
cmMakefile* mf = context->LG->GetMakefile();
|
|
for (std::string& o : objects) {
|
|
mf->AddTargetObject(tgtName, o);
|
|
}
|
|
|
|
return cmJoin(objects, ";");
|
|
}
|
|
} targetObjectsNode;
|
|
|
|
static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
|
|
{
|
|
CompileFeaturesNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return OneOrMoreParameters; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
cmGeneratorTarget const* target = context->HeadTarget;
|
|
if (!target) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<COMPILE_FEATURE> may only be used with binary targets. It may "
|
|
"not be used with add_custom_command or add_custom_target.");
|
|
return std::string();
|
|
}
|
|
context->HadHeadSensitiveCondition = true;
|
|
|
|
using LangMap = std::map<std::string, std::vector<std::string>>;
|
|
static LangMap availableFeatures;
|
|
|
|
LangMap testedFeatures;
|
|
|
|
for (std::string const& p : parameters) {
|
|
std::string error;
|
|
std::string lang;
|
|
if (!context->LG->GetMakefile()->CompileFeatureKnown(
|
|
context->HeadTarget->Target, p, lang, &error)) {
|
|
reportError(context, content->GetOriginalExpression(), error);
|
|
return std::string();
|
|
}
|
|
testedFeatures[lang].push_back(p);
|
|
|
|
if (availableFeatures.find(lang) == availableFeatures.end()) {
|
|
const char* featuresKnown =
|
|
context->LG->GetMakefile()->CompileFeaturesAvailable(lang, &error);
|
|
if (!featuresKnown) {
|
|
reportError(context, content->GetOriginalExpression(), error);
|
|
return std::string();
|
|
}
|
|
cmExpandList(featuresKnown, availableFeatures[lang]);
|
|
}
|
|
}
|
|
|
|
bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries();
|
|
|
|
for (auto const& lit : testedFeatures) {
|
|
std::vector<std::string> const& langAvailable =
|
|
availableFeatures[lit.first];
|
|
const char* standardDefault = context->LG->GetMakefile()->GetDefinition(
|
|
"CMAKE_" + lit.first + "_STANDARD_DEFAULT");
|
|
for (std::string const& it : lit.second) {
|
|
if (!cm::contains(langAvailable, it)) {
|
|
return "0";
|
|
}
|
|
if (standardDefault && !*standardDefault) {
|
|
// This compiler has no notion of language standard levels.
|
|
// All features known for the language are always available.
|
|
continue;
|
|
}
|
|
if (!context->LG->GetMakefile()->HaveStandardAvailable(
|
|
target->Target, lit.first, it)) {
|
|
if (evalLL) {
|
|
const char* l = target->GetProperty(lit.first + "_STANDARD");
|
|
if (!l) {
|
|
l = standardDefault;
|
|
}
|
|
assert(l);
|
|
context->MaxLanguageStandard[target][lit.first] = l;
|
|
} else {
|
|
return "0";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return "1";
|
|
}
|
|
} compileFeaturesNode;
|
|
|
|
static const char* targetPolicyWhitelist[] = {
|
|
nullptr
|
|
#define TARGET_POLICY_STRING(POLICY) , #POLICY
|
|
|
|
CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING)
|
|
|
|
#undef TARGET_POLICY_STRING
|
|
};
|
|
|
|
cmPolicies::PolicyStatus statusForTarget(cmGeneratorTarget const* tgt,
|
|
const char* policy)
|
|
{
|
|
#define RETURN_POLICY(POLICY) \
|
|
if (strcmp(policy, #POLICY) == 0) { \
|
|
return tgt->GetPolicyStatus##POLICY(); \
|
|
}
|
|
|
|
CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY)
|
|
|
|
#undef RETURN_POLICY
|
|
|
|
assert(false && "Unreachable code. Not a valid policy");
|
|
return cmPolicies::WARN;
|
|
}
|
|
|
|
cmPolicies::PolicyID policyForString(const char* policy_id)
|
|
{
|
|
#define RETURN_POLICY_ID(POLICY_ID) \
|
|
if (strcmp(policy_id, #POLICY_ID) == 0) { \
|
|
return cmPolicies::POLICY_ID; \
|
|
}
|
|
|
|
CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID)
|
|
|
|
#undef RETURN_POLICY_ID
|
|
|
|
assert(false && "Unreachable code. Not a valid policy");
|
|
return cmPolicies::CMP0002;
|
|
}
|
|
|
|
static const struct TargetPolicyNode : public cmGeneratorExpressionNode
|
|
{
|
|
TargetPolicyNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 1; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
if (!context->HeadTarget) {
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<TARGET_POLICY:prop> may only be used with binary targets. It "
|
|
"may not be used with add_custom_command or add_custom_target.");
|
|
return std::string();
|
|
}
|
|
|
|
context->HadContextSensitiveCondition = true;
|
|
context->HadHeadSensitiveCondition = true;
|
|
|
|
for (size_t i = 1; i < cm::size(targetPolicyWhitelist); ++i) {
|
|
const char* policy = targetPolicyWhitelist[i];
|
|
if (parameters.front() == policy) {
|
|
cmLocalGenerator* lg = context->HeadTarget->GetLocalGenerator();
|
|
switch (statusForTarget(context->HeadTarget, policy)) {
|
|
case cmPolicies::WARN:
|
|
lg->IssueMessage(
|
|
MessageType::AUTHOR_WARNING,
|
|
cmPolicies::GetPolicyWarning(policyForString(policy)));
|
|
CM_FALLTHROUGH;
|
|
case cmPolicies::REQUIRED_IF_USED:
|
|
case cmPolicies::REQUIRED_ALWAYS:
|
|
case cmPolicies::OLD:
|
|
return "0";
|
|
case cmPolicies::NEW:
|
|
return "1";
|
|
}
|
|
}
|
|
}
|
|
reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"$<TARGET_POLICY:prop> may only be used with a limited number of "
|
|
"policies. Currently it may be used with the following policies:\n"
|
|
|
|
#define STRINGIFY_HELPER(X) #X
|
|
#define STRINGIFY(X) STRINGIFY_HELPER(X)
|
|
|
|
#define TARGET_POLICY_LIST_ITEM(POLICY) " * " STRINGIFY(POLICY) "\n"
|
|
|
|
CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM)
|
|
|
|
#undef TARGET_POLICY_LIST_ITEM
|
|
);
|
|
return std::string();
|
|
}
|
|
|
|
} targetPolicyNode;
|
|
|
|
static const struct InstallPrefixNode : public cmGeneratorExpressionNode
|
|
{
|
|
InstallPrefixNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
bool GeneratesContent() const override { return true; }
|
|
int NumExpectedParameters() const override { return 0; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& /*parameters*/,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"INSTALL_PREFIX is a marker for install(EXPORT) only. It "
|
|
"should never be evaluated.");
|
|
return std::string();
|
|
}
|
|
|
|
} installPrefixNode;
|
|
|
|
class ArtifactDirTag;
|
|
class ArtifactLinkerTag;
|
|
class ArtifactNameTag;
|
|
class ArtifactPathTag;
|
|
class ArtifactPdbTag;
|
|
class ArtifactSonameTag;
|
|
class ArtifactBundleDirTag;
|
|
class ArtifactBundleContentDirTag;
|
|
|
|
template <typename ArtifactT>
|
|
struct TargetFilesystemArtifactResultCreator
|
|
{
|
|
static std::string Create(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content);
|
|
};
|
|
|
|
template <>
|
|
struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag>
|
|
{
|
|
static std::string Create(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content)
|
|
{
|
|
// The target soname file (.so.1).
|
|
if (target->IsDLLPlatform()) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_SONAME_FILE is not allowed "
|
|
"for DLL target platforms.");
|
|
return std::string();
|
|
}
|
|
if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_SONAME_FILE is allowed only for "
|
|
"SHARED libraries.");
|
|
return std::string();
|
|
}
|
|
std::string result = cmStrCat(target->GetDirectory(context->Config), '/',
|
|
target->GetSOName(context->Config));
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
|
|
{
|
|
static std::string Create(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content)
|
|
{
|
|
if (target->IsImported()) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_PDB_FILE not allowed for IMPORTED targets.");
|
|
return std::string();
|
|
}
|
|
|
|
std::string language = target->GetLinkerLanguage(context->Config);
|
|
|
|
std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
|
|
|
|
if (!context->LG->GetMakefile()->IsOn(pdbSupportVar)) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_PDB_FILE is not supported by the target linker.");
|
|
return std::string();
|
|
}
|
|
|
|
cmStateEnums::TargetType targetType = target->GetType();
|
|
|
|
if (targetType != cmStateEnums::SHARED_LIBRARY &&
|
|
targetType != cmStateEnums::MODULE_LIBRARY &&
|
|
targetType != cmStateEnums::EXECUTABLE) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_PDB_FILE is allowed only for "
|
|
"targets with linker created artifacts.");
|
|
return std::string();
|
|
}
|
|
|
|
std::string result = cmStrCat(target->GetPDBDirectory(context->Config),
|
|
'/', target->GetPDBName(context->Config));
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
|
|
{
|
|
static std::string Create(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content)
|
|
{
|
|
// The file used to link to the target (.so, .lib, .a).
|
|
if (!target->IsLinkable()) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_LINKER_FILE is allowed only for libraries and "
|
|
"executables with ENABLE_EXPORTS.");
|
|
return std::string();
|
|
}
|
|
cmStateEnums::ArtifactType artifact =
|
|
target->HasImportLibrary(context->Config)
|
|
? cmStateEnums::ImportLibraryArtifact
|
|
: cmStateEnums::RuntimeBinaryArtifact;
|
|
return target->GetFullPath(context->Config, artifact);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag>
|
|
{
|
|
static std::string Create(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content)
|
|
{
|
|
if (target->IsImported()) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_BUNDLE_DIR not allowed for IMPORTED targets.");
|
|
return std::string();
|
|
}
|
|
if (!target->IsBundleOnApple()) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_BUNDLE_DIR is allowed only for Bundle targets.");
|
|
return std::string();
|
|
}
|
|
|
|
std::string outpath = target->GetDirectory(context->Config) + '/';
|
|
return target->BuildBundleDirectory(outpath, context->Config,
|
|
cmGeneratorTarget::BundleDirLevel);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct TargetFilesystemArtifactResultCreator<ArtifactBundleContentDirTag>
|
|
{
|
|
static std::string Create(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content)
|
|
{
|
|
if (target->IsImported()) {
|
|
::reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"TARGET_BUNDLE_CONTENT_DIR not allowed for IMPORTED targets.");
|
|
return std::string();
|
|
}
|
|
if (!target->IsBundleOnApple()) {
|
|
::reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"TARGET_BUNDLE_CONTENT_DIR is allowed only for Bundle targets.");
|
|
return std::string();
|
|
}
|
|
|
|
std::string outpath = target->GetDirectory(context->Config) + '/';
|
|
return target->BuildBundleDirectory(outpath, context->Config,
|
|
cmGeneratorTarget::ContentLevel);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct TargetFilesystemArtifactResultCreator<ArtifactNameTag>
|
|
{
|
|
static std::string Create(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* /*unused*/)
|
|
{
|
|
return target->GetFullPath(context->Config,
|
|
cmStateEnums::RuntimeBinaryArtifact, true);
|
|
}
|
|
};
|
|
|
|
template <typename ArtifactT>
|
|
struct TargetFilesystemArtifactResultGetter
|
|
{
|
|
static std::string Get(const std::string& result);
|
|
};
|
|
|
|
template <>
|
|
struct TargetFilesystemArtifactResultGetter<ArtifactNameTag>
|
|
{
|
|
static std::string Get(const std::string& result)
|
|
{
|
|
return cmSystemTools::GetFilenameName(result);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct TargetFilesystemArtifactResultGetter<ArtifactDirTag>
|
|
{
|
|
static std::string Get(const std::string& result)
|
|
{
|
|
return cmSystemTools::GetFilenamePath(result);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct TargetFilesystemArtifactResultGetter<ArtifactPathTag>
|
|
{
|
|
static std::string Get(const std::string& result) { return result; }
|
|
};
|
|
|
|
struct TargetArtifactBase : public cmGeneratorExpressionNode
|
|
{
|
|
TargetArtifactBase() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
protected:
|
|
cmGeneratorTarget* GetTarget(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const
|
|
{
|
|
// Lookup the referenced target.
|
|
std::string name = parameters.front();
|
|
|
|
if (!cmGeneratorExpression::IsValidTargetName(name)) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"Expression syntax not recognized.");
|
|
return nullptr;
|
|
}
|
|
cmGeneratorTarget* target = context->LG->FindGeneratorTargetToUse(name);
|
|
if (!target) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"No target \"" + name + "\"");
|
|
return nullptr;
|
|
}
|
|
if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY &&
|
|
target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"Target \"" + name +
|
|
"\" is not an executable or library.");
|
|
return nullptr;
|
|
}
|
|
if (dagChecker &&
|
|
(dagChecker->EvaluatingLinkLibraries(target) ||
|
|
(dagChecker->EvaluatingSources() &&
|
|
target == dagChecker->TopTarget()))) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"Expressions which require the linker language may not "
|
|
"be used while evaluating link libraries");
|
|
return nullptr;
|
|
}
|
|
|
|
return target;
|
|
}
|
|
};
|
|
|
|
template <typename ArtifactT, typename ComponentT>
|
|
struct TargetFilesystemArtifact : public TargetArtifactBase
|
|
{
|
|
TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 1; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
cmGeneratorTarget* target =
|
|
this->GetTarget(parameters, context, content, dagChecker);
|
|
if (!target) {
|
|
return std::string();
|
|
}
|
|
context->DependTargets.insert(target);
|
|
context->AllTargets.insert(target);
|
|
|
|
std::string result =
|
|
TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, context,
|
|
content);
|
|
if (context->HadError) {
|
|
return std::string();
|
|
}
|
|
return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
|
|
}
|
|
};
|
|
|
|
template <typename ArtifactT>
|
|
struct TargetFilesystemArtifactNodeGroup
|
|
{
|
|
TargetFilesystemArtifactNodeGroup() // NOLINT(modernize-use-equals-default)
|
|
{
|
|
}
|
|
|
|
TargetFilesystemArtifact<ArtifactT, ArtifactPathTag> File;
|
|
TargetFilesystemArtifact<ArtifactT, ArtifactNameTag> FileName;
|
|
TargetFilesystemArtifact<ArtifactT, ArtifactDirTag> FileDir;
|
|
};
|
|
|
|
static const TargetFilesystemArtifactNodeGroup<ArtifactNameTag>
|
|
targetNodeGroup;
|
|
|
|
static const TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag>
|
|
targetLinkerNodeGroup;
|
|
|
|
static const TargetFilesystemArtifactNodeGroup<ArtifactSonameTag>
|
|
targetSoNameNodeGroup;
|
|
|
|
static const TargetFilesystemArtifactNodeGroup<ArtifactPdbTag>
|
|
targetPdbNodeGroup;
|
|
|
|
static const TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag>
|
|
targetBundleDirNode;
|
|
|
|
static const TargetFilesystemArtifact<ArtifactBundleContentDirTag,
|
|
ArtifactPathTag>
|
|
targetBundleContentDirNode;
|
|
|
|
//
|
|
// To retrieve base name for various artifacts
|
|
//
|
|
template <typename ArtifactT>
|
|
struct TargetOutputNameArtifactResultGetter
|
|
{
|
|
static std::string Get(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content);
|
|
};
|
|
|
|
template <>
|
|
struct TargetOutputNameArtifactResultGetter<ArtifactNameTag>
|
|
{
|
|
static std::string Get(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* /*unused*/)
|
|
{
|
|
return target->GetOutputName(context->Config,
|
|
cmStateEnums::RuntimeBinaryArtifact) +
|
|
target->GetFilePostfix(context->Config);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
|
|
{
|
|
static std::string Get(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content)
|
|
{
|
|
// The file used to link to the target (.so, .lib, .a).
|
|
if (!target->IsLinkable()) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_LINKER_FILE_BASE_NAME is allowed only for "
|
|
"libraries and executables with ENABLE_EXPORTS.");
|
|
return std::string();
|
|
}
|
|
cmStateEnums::ArtifactType artifact =
|
|
target->HasImportLibrary(context->Config)
|
|
? cmStateEnums::ImportLibraryArtifact
|
|
: cmStateEnums::RuntimeBinaryArtifact;
|
|
return target->GetOutputName(context->Config, artifact) +
|
|
target->GetFilePostfix(context->Config);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
|
|
{
|
|
static std::string Get(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content)
|
|
{
|
|
if (target->IsImported()) {
|
|
::reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"TARGET_PDB_FILE_BASE_NAME not allowed for IMPORTED targets.");
|
|
return std::string();
|
|
}
|
|
|
|
std::string language = target->GetLinkerLanguage(context->Config);
|
|
|
|
std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
|
|
|
|
if (!context->LG->GetMakefile()->IsOn(pdbSupportVar)) {
|
|
::reportError(
|
|
context, content->GetOriginalExpression(),
|
|
"TARGET_PDB_FILE_BASE_NAME is not supported by the target linker.");
|
|
return std::string();
|
|
}
|
|
|
|
cmStateEnums::TargetType targetType = target->GetType();
|
|
|
|
if (targetType != cmStateEnums::SHARED_LIBRARY &&
|
|
targetType != cmStateEnums::MODULE_LIBRARY &&
|
|
targetType != cmStateEnums::EXECUTABLE) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_PDB_FILE_BASE_NAME is allowed only for "
|
|
"targets with linker created artifacts.");
|
|
return std::string();
|
|
}
|
|
|
|
return target->GetPDBOutputName(context->Config) +
|
|
target->GetFilePostfix(context->Config);
|
|
}
|
|
};
|
|
|
|
template <typename ArtifactT>
|
|
struct TargetFileBaseNameArtifact : public TargetArtifactBase
|
|
{
|
|
TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 1; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
cmGeneratorTarget* target =
|
|
this->GetTarget(parameters, context, content, dagChecker);
|
|
if (!target) {
|
|
return std::string();
|
|
}
|
|
|
|
std::string result = TargetOutputNameArtifactResultGetter<ArtifactT>::Get(
|
|
target, context, content);
|
|
if (context->HadError) {
|
|
return std::string();
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
static const TargetFileBaseNameArtifact<ArtifactNameTag>
|
|
targetFileBaseNameNode;
|
|
static const TargetFileBaseNameArtifact<ArtifactLinkerTag>
|
|
targetLinkerFileBaseNameNode;
|
|
static const TargetFileBaseNameArtifact<ArtifactPdbTag>
|
|
targetPdbFileBaseNameNode;
|
|
|
|
class ArtifactFilePrefixTag;
|
|
class ArtifactLinkerFilePrefixTag;
|
|
class ArtifactFileSuffixTag;
|
|
class ArtifactLinkerFileSuffixTag;
|
|
|
|
template <typename ArtifactT>
|
|
struct TargetFileArtifactResultGetter
|
|
{
|
|
static std::string Get(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content);
|
|
};
|
|
|
|
template <>
|
|
struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
|
|
{
|
|
static std::string Get(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent*)
|
|
{
|
|
return target->GetFilePrefix(context->Config);
|
|
}
|
|
};
|
|
template <>
|
|
struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
|
|
{
|
|
static std::string Get(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content)
|
|
{
|
|
if (!target->IsLinkable()) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_LINKER_PREFIX is allowed only for libraries and "
|
|
"executables with ENABLE_EXPORTS.");
|
|
return std::string();
|
|
}
|
|
|
|
cmStateEnums::ArtifactType artifact =
|
|
target->HasImportLibrary(context->Config)
|
|
? cmStateEnums::ImportLibraryArtifact
|
|
: cmStateEnums::RuntimeBinaryArtifact;
|
|
|
|
return target->GetFilePrefix(context->Config, artifact);
|
|
}
|
|
};
|
|
template <>
|
|
struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
|
|
{
|
|
static std::string Get(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent*)
|
|
{
|
|
return target->GetFileSuffix(context->Config);
|
|
}
|
|
};
|
|
template <>
|
|
struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
|
|
{
|
|
static std::string Get(cmGeneratorTarget* target,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content)
|
|
{
|
|
if (!target->IsLinkable()) {
|
|
::reportError(context, content->GetOriginalExpression(),
|
|
"TARGET_LINKER_SUFFIX is allowed only for libraries and "
|
|
"executables with ENABLE_EXPORTS.");
|
|
return std::string();
|
|
}
|
|
|
|
cmStateEnums::ArtifactType artifact =
|
|
target->HasImportLibrary(context->Config)
|
|
? cmStateEnums::ImportLibraryArtifact
|
|
: cmStateEnums::RuntimeBinaryArtifact;
|
|
|
|
return target->GetFileSuffix(context->Config, artifact);
|
|
}
|
|
};
|
|
|
|
template <typename ArtifactT>
|
|
struct TargetFileArtifact : public TargetArtifactBase
|
|
{
|
|
TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
int NumExpectedParameters() const override { return 1; }
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* dagChecker) const override
|
|
{
|
|
cmGeneratorTarget* target =
|
|
this->GetTarget(parameters, context, content, dagChecker);
|
|
if (!target) {
|
|
return std::string();
|
|
}
|
|
|
|
std::string result =
|
|
TargetFileArtifactResultGetter<ArtifactT>::Get(target, context, content);
|
|
if (context->HadError) {
|
|
return std::string();
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
static const TargetFileArtifact<ArtifactFilePrefixTag> targetFilePrefixNode;
|
|
static const TargetFileArtifact<ArtifactLinkerFilePrefixTag>
|
|
targetLinkerFilePrefixNode;
|
|
static const TargetFileArtifact<ArtifactFileSuffixTag> targetFileSuffixNode;
|
|
static const TargetFileArtifact<ArtifactLinkerFileSuffixTag>
|
|
targetLinkerFileSuffixNode;
|
|
|
|
static const struct ShellPathNode : public cmGeneratorExpressionNode
|
|
{
|
|
ShellPathNode() {} // NOLINT(modernize-use-equals-default)
|
|
|
|
std::string Evaluate(
|
|
const std::vector<std::string>& parameters,
|
|
cmGeneratorExpressionContext* context,
|
|
const GeneratorExpressionContent* content,
|
|
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
|
{
|
|
std::vector<std::string> listIn = cmExpandedList(parameters.front());
|
|
if (listIn.empty()) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"\"\" is not an absolute path.");
|
|
return std::string();
|
|
}
|
|
cmStateSnapshot snapshot = context->LG->GetStateSnapshot();
|
|
cmOutputConverter converter(snapshot);
|
|
const char* separator = snapshot.GetState()->UseWindowsShell() ? ";" : ":";
|
|
std::vector<std::string> listOut;
|
|
listOut.reserve(listIn.size());
|
|
for (auto const& in : listIn) {
|
|
if (!cmSystemTools::FileIsFullPath(in)) {
|
|
reportError(context, content->GetOriginalExpression(),
|
|
"\"" + in + "\" is not an absolute path.");
|
|
return std::string();
|
|
}
|
|
listOut.emplace_back(converter.ConvertDirectorySeparatorsForShell(in));
|
|
}
|
|
return cmJoin(listOut, separator);
|
|
}
|
|
} shellPathNode;
|
|
|
|
const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
|
|
const std::string& identifier)
|
|
{
|
|
static std::map<std::string, cmGeneratorExpressionNode const*> const nodeMap{
|
|
{ "0", &zeroNode },
|
|
{ "1", &oneNode },
|
|
{ "AND", &andNode },
|
|
{ "OR", &orNode },
|
|
{ "NOT", ¬Node },
|
|
{ "C_COMPILER_ID", &cCompilerIdNode },
|
|
{ "CXX_COMPILER_ID", &cxxCompilerIdNode },
|
|
{ "OBJC_COMPILER_ID", &objcCompilerIdNode },
|
|
{ "OBJCXX_COMPILER_ID", &objcxxCompilerIdNode },
|
|
{ "CUDA_COMPILER_ID", &cudaCompilerIdNode },
|
|
{ "Fortran_COMPILER_ID", &fortranCompilerIdNode },
|
|
{ "VERSION_GREATER", &versionGreaterNode },
|
|
{ "VERSION_GREATER_EQUAL", &versionGreaterEqNode },
|
|
{ "VERSION_LESS", &versionLessNode },
|
|
{ "VERSION_LESS_EQUAL", &versionLessEqNode },
|
|
{ "VERSION_EQUAL", &versionEqualNode },
|
|
{ "C_COMPILER_VERSION", &cCompilerVersionNode },
|
|
{ "CXX_COMPILER_VERSION", &cxxCompilerVersionNode },
|
|
{ "CUDA_COMPILER_VERSION", &cudaCompilerVersionNode },
|
|
{ "OBJC_COMPILER_VERSION", &objcCompilerVersionNode },
|
|
{ "OBJCXX_COMPILER_VERSION", &objcxxCompilerVersionNode },
|
|
{ "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode },
|
|
{ "PLATFORM_ID", &platformIdNode },
|
|
{ "COMPILE_FEATURES", &compileFeaturesNode },
|
|
{ "CONFIGURATION", &configurationNode },
|
|
{ "CONFIG", &configurationTestNode },
|
|
{ "TARGET_FILE", &targetNodeGroup.File },
|
|
{ "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
|
|
{ "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
|
|
{ "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
|
|
{ "TARGET_FILE_BASE_NAME", &targetFileBaseNameNode },
|
|
{ "TARGET_LINKER_FILE_BASE_NAME", &targetLinkerFileBaseNameNode },
|
|
{ "TARGET_PDB_FILE_BASE_NAME", &targetPdbFileBaseNameNode },
|
|
{ "TARGET_FILE_PREFIX", &targetFilePrefixNode },
|
|
{ "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode },
|
|
{ "TARGET_FILE_SUFFIX", &targetFileSuffixNode },
|
|
{ "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode },
|
|
{ "TARGET_FILE_NAME", &targetNodeGroup.FileName },
|
|
{ "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
|
|
{ "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
|
|
{ "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName },
|
|
{ "TARGET_FILE_DIR", &targetNodeGroup.FileDir },
|
|
{ "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir },
|
|
{ "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir },
|
|
{ "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir },
|
|
{ "TARGET_BUNDLE_DIR", &targetBundleDirNode },
|
|
{ "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode },
|
|
{ "STREQUAL", &strEqualNode },
|
|
{ "EQUAL", &equalNode },
|
|
{ "IN_LIST", &inListNode },
|
|
{ "FILTER", &filterNode },
|
|
{ "REMOVE_DUPLICATES", &removeDuplicatesNode },
|
|
{ "LOWER_CASE", &lowerCaseNode },
|
|
{ "UPPER_CASE", &upperCaseNode },
|
|
{ "MAKE_C_IDENTIFIER", &makeCIdentifierNode },
|
|
{ "BOOL", &boolNode },
|
|
{ "IF", &ifNode },
|
|
{ "ANGLE-R", &angle_rNode },
|
|
{ "COMMA", &commaNode },
|
|
{ "SEMICOLON", &semicolonNode },
|
|
{ "TARGET_PROPERTY", &targetPropertyNode },
|
|
{ "TARGET_NAME", &targetNameNode },
|
|
{ "TARGET_OBJECTS", &targetObjectsNode },
|
|
{ "TARGET_POLICY", &targetPolicyNode },
|
|
{ "TARGET_EXISTS", &targetExistsNode },
|
|
{ "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
|
|
{ "TARGET_GENEX_EVAL", &targetGenexEvalNode },
|
|
{ "GENEX_EVAL", &genexEvalNode },
|
|
{ "BUILD_INTERFACE", &buildInterfaceNode },
|
|
{ "INSTALL_INTERFACE", &installInterfaceNode },
|
|
{ "INSTALL_PREFIX", &installPrefixNode },
|
|
{ "JOIN", &joinNode },
|
|
{ "LINK_ONLY", &linkOnlyNode },
|
|
{ "COMPILE_LANG_AND_ID", &languageAndIdNode },
|
|
{ "COMPILE_LANGUAGE", &languageNode },
|
|
{ "LINK_LANG_AND_ID", &linkLanguageAndIdNode },
|
|
{ "LINK_LANGUAGE", &linkLanguageNode },
|
|
{ "HOST_LINK", &hostLinkNode },
|
|
{ "DEVICE_LINK", &deviceLinkNode },
|
|
{ "SHELL_PATH", &shellPathNode }
|
|
};
|
|
|
|
{
|
|
auto itr = nodeMap.find(identifier);
|
|
if (itr != nodeMap.end()) {
|
|
return itr->second;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void reportError(cmGeneratorExpressionContext* context,
|
|
const std::string& expr, const std::string& result)
|
|
{
|
|
context->HadError = true;
|
|
if (context->Quiet) {
|
|
return;
|
|
}
|
|
|
|
std::ostringstream e;
|
|
/* clang-format off */
|
|
e << "Error evaluating generator expression:\n"
|
|
<< " " << expr << "\n"
|
|
<< result;
|
|
/* clang-format on */
|
|
context->LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
|
|
e.str(), context->Backtrace);
|
|
}
|