diff --git a/Help/command/if.rst b/Help/command/if.rst index a45b9951c..79e5d21c2 100644 --- a/Help/command/if.rst +++ b/Help/command/if.rst @@ -199,3 +199,9 @@ above-documented signature accepts ````: * The left and right hand arguments to ``AND`` and ``OR`` are independently tested to see if they are boolean constants, if so they are used as such, otherwise they are assumed to be variables and are dereferenced. + +To prevent ambiguity, potential variable or keyword names can be +specified in a :ref:`Quoted Argument` or a :ref:`Bracket Argument`. +A quoted or bracketed variable or keyword will be interpreted as a +string and not dereferenced or interpreted. +See policy :policy:`CMP0054`. diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 136cf5c78..f1717a08c 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -105,3 +105,4 @@ All Policies /policy/CMP0051 /policy/CMP0052 /policy/CMP0053 + /policy/CMP0054 diff --git a/Help/policy/CMP0054.rst b/Help/policy/CMP0054.rst new file mode 100644 index 000000000..dffee5e81 --- /dev/null +++ b/Help/policy/CMP0054.rst @@ -0,0 +1,18 @@ +CMP0054 +------- + +Only interpret :command:`if` arguments as variables or keywords when unquoted. + +CMake 3.1 and above no longer dereference variables or interpret keywords +in an :command:`if` command argument when it is a :ref:`Quoted Argument` +or a :ref:`Bracket Argument`. + +The ``OLD`` behavior for this policy is to dereference variables and +interpret keywords even if they are quoted or bracketed. +The ``NEW`` behavior is to not dereference variables or interpret keywords +that have been quoted or bracketed. + +This policy was introduced in CMake version 3.1. +CMake version |release| warns when the policy is not set and uses +``OLD`` behavior. Use the :command:`cmake_policy` command to set +it to ``OLD`` or ``NEW`` explicitly. diff --git a/Help/release/dev/if-sanity.rst b/Help/release/dev/if-sanity.rst new file mode 100644 index 000000000..6645bc442 --- /dev/null +++ b/Help/release/dev/if-sanity.rst @@ -0,0 +1,6 @@ +if-sanity +--------- + +* The :command:`if` command no longer automatically dereferences + variables named in quoted or bracket arguments. See policy + :policy:`CMP0054`. diff --git a/Source/cmBootstrapCommands2.cxx b/Source/cmBootstrapCommands2.cxx index 91c189f71..5675295f5 100644 --- a/Source/cmBootstrapCommands2.cxx +++ b/Source/cmBootstrapCommands2.cxx @@ -15,6 +15,7 @@ // like to have CMake to build CMake. #include "cmCommands.h" #include "cmConditionEvaluator.cxx" +#include "cmExpandedCommandArgument.cxx" #include "cmGeneratorExpressionEvaluationFile.cxx" #include "cmGetCMakePropertyCommand.cxx" #include "cmGetDirectoryPropertyCommand.cxx" diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 869d3c5d8..aba26de10 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -14,7 +14,8 @@ cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile): Makefile(makefile), - Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012)) + Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012)), + Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054)) { } @@ -36,7 +37,7 @@ cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile): // directly. AND OR take variables or the values 0 or 1. bool cmConditionEvaluator::IsTrue( - const std::vector &args, + const std::vector &args, std::string &errorString, cmake::MessageType &status) { @@ -99,22 +100,93 @@ bool cmConditionEvaluator::IsTrue( } //========================================================================= -const char* cmConditionEvaluator::GetVariableOrString( - const std::string& str) const +const char* cmConditionEvaluator::GetDefinitionIfUnquoted( + cmExpandedCommandArgument const& argument) const { - const char* def = this->Makefile.GetDefinition(str); - - if(!def) + if((this->Policy54Status != cmPolicies::WARN && + this->Policy54Status != cmPolicies::OLD) && + argument.WasQuoted()) { - def = str.c_str(); + return 0; + } + + const char* def = this->Makefile.GetDefinition(argument.GetValue()); + + if(def && argument.WasQuoted() && this->Policy54Status == cmPolicies::WARN) + { + bool hasBeenReported = this->Makefile.HasCMP0054AlreadyBeenReported( + this->Makefile.GetBacktrace()[0]); + + if(!hasBeenReported) + { + cmOStringStream e; + e << (this->Makefile.GetPolicies()->GetPolicyWarning( + cmPolicies::CMP0054)) << "\n"; + e << "Quoted variables like \"" << argument.GetValue() << + "\" will no longer be dereferenced " + "when the policy is set to NEW. " + "Since the policy is not set the OLD behavior will be used."; + + this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str()); + } } return def; } +//========================================================================= +const char* cmConditionEvaluator::GetVariableOrString( + const cmExpandedCommandArgument& argument) const +{ + const char* def = this->GetDefinitionIfUnquoted(argument); + + if(!def) + { + def = argument.c_str(); + } + + return def; +} + +//========================================================================= +bool cmConditionEvaluator::IsKeyword(std::string const& keyword, + cmExpandedCommandArgument& argument) const +{ + if((this->Policy54Status != cmPolicies::WARN && + this->Policy54Status != cmPolicies::OLD) && + argument.WasQuoted()) + { + return false; + } + + bool isKeyword = argument.GetValue() == keyword; + + if(isKeyword && argument.WasQuoted() && + this->Policy54Status == cmPolicies::WARN) + { + bool hasBeenReported = this->Makefile.HasCMP0054AlreadyBeenReported( + this->Makefile.GetBacktrace()[0]); + + if(!hasBeenReported) + { + cmOStringStream e; + e << (this->Makefile.GetPolicies()->GetPolicyWarning( + cmPolicies::CMP0054)) << "\n"; + e << "Quoted keywords like \"" << argument.GetValue() << + "\" will no longer be interpreted as keywords " + "when the policy is set to NEW. " + "Since the policy is not set the OLD behavior will be used."; + + this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str()); + } + } + + return isKeyword; +} + //========================================================================= bool cmConditionEvaluator::GetBooleanValue( - std::string& arg) const + cmExpandedCommandArgument& arg) const { // Check basic constants. if (arg == "0") @@ -149,14 +221,14 @@ bool cmConditionEvaluator::GetBooleanValue( } // Check definition. - const char* def = this->Makefile.GetDefinition(arg); + const char* def = this->GetDefinitionIfUnquoted(arg); return !cmSystemTools::IsOff(def); } //========================================================================= // Boolean value behavior from CMake 2.6.4 and below. bool cmConditionEvaluator::GetBooleanValueOld( - std::string const& arg, bool one) const + cmExpandedCommandArgument const& arg, bool one) const { if(one) { @@ -166,12 +238,15 @@ bool cmConditionEvaluator::GetBooleanValueOld( else if(arg == "1") { return true; } else - { return !cmSystemTools::IsOff(this->Makefile.GetDefinition(arg)); } + { + const char* def = this->GetDefinitionIfUnquoted(arg); + return !cmSystemTools::IsOff(def); + } } else { // Old GetVariableOrNumber behavior. - const char* def = this->Makefile.GetDefinition(arg); + const char* def = this->GetDefinitionIfUnquoted(arg); if(!def && atoi(arg.c_str())) { def = arg.c_str(); @@ -183,7 +258,7 @@ bool cmConditionEvaluator::GetBooleanValueOld( //========================================================================= // returns the resulting boolean value bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( - std::string &newArg, + cmExpandedCommandArgument &newArg, std::string &errorString, cmake::MessageType &status, bool oneArg) const @@ -208,7 +283,7 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( case cmPolicies::WARN: { cmPolicies* policies = this->Makefile.GetPolicies(); - errorString = "An argument named \"" + newArg + errorString = "An argument named \"" + newArg.GetValue() + "\" appears in a conditional statement. " + policies->GetPolicyWarning(cmPolicies::CMP0012); status = cmake::AUTHOR_WARNING; @@ -219,7 +294,7 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( case cmPolicies::REQUIRED_ALWAYS: { cmPolicies* policies = this->Makefile.GetPolicies(); - errorString = "An argument named \"" + newArg + errorString = "An argument named \"" + newArg.GetValue() + "\" appears in a conditional statement. " + policies->GetRequiredPolicyError(cmPolicies::CMP0012); status = cmake::FATAL_ERROR; @@ -257,11 +332,11 @@ void cmConditionEvaluator::HandlePredicate(bool value, int &reducible, { if(value) { - *arg = "1"; + *arg = cmExpandedCommandArgument("1", true); } else { - *arg = "0"; + *arg = cmExpandedCommandArgument("0", true); } newArgs.erase(argP1); argP1 = arg; @@ -279,11 +354,11 @@ void cmConditionEvaluator::HandleBinaryOp(bool value, int &reducible, { if(value) { - *arg = "1"; + *arg = cmExpandedCommandArgument("1", true); } else { - *arg = "0"; + *arg = cmExpandedCommandArgument("0", true); } newArgs.erase(argP2); newArgs.erase(argP1); @@ -302,23 +377,23 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList &newArgs, do { reducible = 0; - std::list::iterator arg = newArgs.begin(); + cmArgumentList::iterator arg = newArgs.begin(); while (arg != newArgs.end()) { - if (*arg == "(") + if (IsKeyword("(", *arg)) { // search for the closing paren for this opening one - std::list::iterator argClose; + cmArgumentList::iterator argClose; argClose = arg; argClose++; unsigned int depth = 1; while (argClose != newArgs.end() && depth) { - if (*argClose == "(") + if (this->IsKeyword("(", *argClose)) { depth++; } - if (*argClose == ")") + if (this->IsKeyword(")", *argClose)) { depth--; } @@ -331,10 +406,10 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList &newArgs, return false; } // store the reduced args in this vector - std::vector newArgs2; + std::vector newArgs2; // copy to the list structure - std::list::iterator argP1 = arg; + cmArgumentList::iterator argP1 = arg; argP1++; for(; argP1 != argClose; argP1++) { @@ -347,11 +422,11 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList &newArgs, this->IsTrue(newArgs2, errorString, status); if(value) { - *arg = "1"; + *arg = cmExpandedCommandArgument("1", true); } else { - *arg = "0"; + *arg = cmExpandedCommandArgument("0", true); } argP1 = arg; argP1++; @@ -374,77 +449,78 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList &newArgs, do { reducible = 0; - std::list::iterator arg = newArgs.begin(); - std::list::iterator argP1; - std::list::iterator argP2; + cmArgumentList::iterator arg = newArgs.begin(); + cmArgumentList::iterator argP1; + cmArgumentList::iterator argP2; while (arg != newArgs.end()) { argP1 = arg; this->IncrementArguments(newArgs,argP1,argP2); // does a file exist - if (*arg == "EXISTS" && argP1 != newArgs.end()) + if (this->IsKeyword("EXISTS", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - cmSystemTools::FileExists((argP1)->c_str()), + cmSystemTools::FileExists(argP1->c_str()), reducible, arg, newArgs, argP1, argP2); } // does a directory with this name exist - if (*arg == "IS_DIRECTORY" && argP1 != newArgs.end()) + if (this->IsKeyword("IS_DIRECTORY", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - cmSystemTools::FileIsDirectory((argP1)->c_str()), + cmSystemTools::FileIsDirectory(argP1->c_str()), reducible, arg, newArgs, argP1, argP2); } // does a symlink with this name exist - if (*arg == "IS_SYMLINK" && argP1 != newArgs.end()) + if (this->IsKeyword("IS_SYMLINK", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - cmSystemTools::FileIsSymlink((argP1)->c_str()), + cmSystemTools::FileIsSymlink(argP1->c_str()), reducible, arg, newArgs, argP1, argP2); } // is the given path an absolute path ? - if (*arg == "IS_ABSOLUTE" && argP1 != newArgs.end()) + if (this->IsKeyword("IS_ABSOLUTE", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - cmSystemTools::FileIsFullPath((argP1)->c_str()), + cmSystemTools::FileIsFullPath(argP1->c_str()), reducible, arg, newArgs, argP1, argP2); } // does a command exist - if (*arg == "COMMAND" && argP1 != newArgs.end()) + if (this->IsKeyword("COMMAND", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - this->Makefile.CommandExists((argP1)->c_str()), + this->Makefile.CommandExists(argP1->c_str()), reducible, arg, newArgs, argP1, argP2); } // does a policy exist - if (*arg == "POLICY" && argP1 != newArgs.end()) + if (this->IsKeyword("POLICY", *arg) && argP1 != newArgs.end()) { cmPolicies::PolicyID pid; this->HandlePredicate( - this->Makefile.GetPolicies()->GetPolicyID((argP1)->c_str(), pid), - reducible, arg, newArgs, argP1, argP2); + this->Makefile.GetPolicies()->GetPolicyID( + argP1->c_str(), pid), + reducible, arg, newArgs, argP1, argP2); } // does a target exist - if (*arg == "TARGET" && argP1 != newArgs.end()) + if (this->IsKeyword("TARGET", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - this->Makefile.FindTargetToUse(*argP1)?true:false, + this->Makefile.FindTargetToUse(argP1->GetValue())?true:false, reducible, arg, newArgs, argP1, argP2); } // is a variable defined - if (*arg == "DEFINED" && argP1 != newArgs.end()) + if (this->IsKeyword("DEFINED", *arg) && argP1 != newArgs.end()) { - size_t argP1len = argP1->size(); + size_t argP1len = argP1->GetValue().size(); bool bdef = false; - if(argP1len > 4 && argP1->substr(0, 4) == "ENV{" && - argP1->operator[](argP1len-1) == '}') + if(argP1len > 4 && argP1->GetValue().substr(0, 4) == "ENV{" && + argP1->GetValue().operator[](argP1len-1) == '}') { - std::string env = argP1->substr(4, argP1len-5); + std::string env = argP1->GetValue().substr(4, argP1len-5); bdef = cmSystemTools::GetEnv(env.c_str())?true:false; } else { - bdef = this->Makefile.IsDefinitionSet(*(argP1)); + bdef = this->Makefile.IsDefinitionSet(argP1->GetValue()); } this->HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2); } @@ -467,18 +543,18 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, do { reducible = 0; - std::list::iterator arg = newArgs.begin(); - std::list::iterator argP1; - std::list::iterator argP2; + cmArgumentList::iterator arg = newArgs.begin(); + cmArgumentList::iterator argP1; + cmArgumentList::iterator argP2; while (arg != newArgs.end()) { argP1 = arg; this->IncrementArguments(newArgs,argP1,argP2); if (argP1 != newArgs.end() && argP2 != newArgs.end() && - *(argP1) == "MATCHES") + IsKeyword("MATCHES", *argP1)) { def = this->GetVariableOrString(*arg); - const char* rex = (argP2)->c_str(); + const char* rex = argP2->c_str(); this->Makefile.ClearMatches(); cmsys::RegularExpression regEntry; if ( !regEntry.compile(rex) ) @@ -492,11 +568,11 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, if (regEntry.find(def)) { this->Makefile.StoreMatches(regEntry); - *arg = "1"; + *arg = cmExpandedCommandArgument("1", true); } else { - *arg = "0"; + *arg = cmExpandedCommandArgument("0", true); } newArgs.erase(argP2); newArgs.erase(argP1); @@ -505,9 +581,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, reducible = 1; } - if (argP1 != newArgs.end() && *arg == "MATCHES") + if (argP1 != newArgs.end() && this->IsKeyword("MATCHES", *arg)) { - *arg = "0"; + *arg = cmExpandedCommandArgument("0", true); newArgs.erase(argP1); argP1 = arg; this->IncrementArguments(newArgs,argP1,argP2); @@ -515,8 +591,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, } if (argP1 != newArgs.end() && argP2 != newArgs.end() && - (*(argP1) == "LESS" || *(argP1) == "GREATER" || - *(argP1) == "EQUAL")) + (this->IsKeyword("LESS", *argP1) || + this->IsKeyword("GREATER", *argP1) || + this->IsKeyword("EQUAL", *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); @@ -540,14 +617,14 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, { result = (lhs == rhs); } - HandleBinaryOp(result, + this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); } if (argP1 != newArgs.end() && argP2 != newArgs.end() && - (*(argP1) == "STRLESS" || - *(argP1) == "STREQUAL" || - *(argP1) == "STRGREATER")) + (this->IsKeyword("STRLESS", *argP1) || + this->IsKeyword("STREQUAL", *argP1) || + this->IsKeyword("STRGREATER", *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); @@ -570,8 +647,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, } if (argP1 != newArgs.end() && argP2 != newArgs.end() && - (*(argP1) == "VERSION_LESS" || *(argP1) == "VERSION_GREATER" || - *(argP1) == "VERSION_EQUAL")) + (this->IsKeyword("VERSION_LESS", *argP1) || + this->IsKeyword("VERSION_GREATER", *argP1) || + this->IsKeyword("VERSION_EQUAL", *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); @@ -591,11 +669,11 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, // is file A newer than file B if (argP1 != newArgs.end() && argP2 != newArgs.end() && - *(argP1) == "IS_NEWER_THAN") + this->IsKeyword("IS_NEWER_THAN", *argP1)) { int fileIsNewer=0; - bool success=cmSystemTools::FileTimeCompare(arg->c_str(), - (argP2)->c_str(), + bool success=cmSystemTools::FileTimeCompare(arg->GetValue(), + (argP2)->GetValue(), &fileIsNewer); this->HandleBinaryOp( (success==false || fileIsNewer==1 || fileIsNewer==0), @@ -619,14 +697,14 @@ bool cmConditionEvaluator::HandleLevel3(cmArgumentList &newArgs, do { reducible = 0; - std::list::iterator arg = newArgs.begin(); - std::list::iterator argP1; - std::list::iterator argP2; + cmArgumentList::iterator arg = newArgs.begin(); + cmArgumentList::iterator argP1; + cmArgumentList::iterator argP2; while (arg != newArgs.end()) { argP1 = arg; IncrementArguments(newArgs,argP1,argP2); - if (argP1 != newArgs.end() && *arg == "NOT") + if (argP1 != newArgs.end() && IsKeyword("NOT", *arg)) { bool rhs = this->GetBooleanValueWithAutoDereference(*argP1, errorString, @@ -652,14 +730,14 @@ bool cmConditionEvaluator::HandleLevel4(cmArgumentList &newArgs, do { reducible = 0; - std::list::iterator arg = newArgs.begin(); - std::list::iterator argP1; - std::list::iterator argP2; + cmArgumentList::iterator arg = newArgs.begin(); + cmArgumentList::iterator argP1; + cmArgumentList::iterator argP2; while (arg != newArgs.end()) { argP1 = arg; IncrementArguments(newArgs,argP1,argP2); - if (argP1 != newArgs.end() && *(argP1) == "AND" && + if (argP1 != newArgs.end() && IsKeyword("AND", *argP1) && argP2 != newArgs.end()) { lhs = this->GetBooleanValueWithAutoDereference(*arg, @@ -672,7 +750,7 @@ bool cmConditionEvaluator::HandleLevel4(cmArgumentList &newArgs, reducible, arg, newArgs, argP1, argP2); } - if (argP1 != newArgs.end() && *(argP1) == "OR" && + if (argP1 != newArgs.end() && this->IsKeyword("OR", *argP1) && argP2 != newArgs.end()) { lhs = this->GetBooleanValueWithAutoDereference(*arg, diff --git a/Source/cmConditionEvaluator.h b/Source/cmConditionEvaluator.h index 9076988e5..01624f92c 100644 --- a/Source/cmConditionEvaluator.h +++ b/Source/cmConditionEvaluator.h @@ -13,36 +13,41 @@ #define cmConditionEvaluator_h #include "cmCommand.h" +#include "cmExpandedCommandArgument.h" class cmConditionEvaluator { public: - typedef std::list cmArgumentList; + typedef std::list cmArgumentList; cmConditionEvaluator(cmMakefile& makefile); // this is a shared function for both If and Else to determine if the // arguments were valid, and if so, was the response true. If there is // an error, the errorString will be set. - bool IsTrue(const std::vector &args, + bool IsTrue(const std::vector &args, std::string &errorString, cmake::MessageType &status); private: + // Filter the given variable definition based on policy CMP0054. + const char* GetDefinitionIfUnquoted( + const cmExpandedCommandArgument& argument) const; + const char* GetVariableOrString( - const std::string& argument) const; + const cmExpandedCommandArgument& argument) const; bool IsKeyword(std::string const& keyword, - std::string& argument) const; + cmExpandedCommandArgument& argument) const; bool GetBooleanValue( - std::string& arg) const; + cmExpandedCommandArgument& arg) const; bool GetBooleanValueOld( - std::string const& arg, bool one) const; + cmExpandedCommandArgument const& arg, bool one) const; bool GetBooleanValueWithAutoDereference( - std::string &newArg, + cmExpandedCommandArgument &newArg, std::string &errorString, cmake::MessageType &status, bool oneArg = false) const; @@ -85,6 +90,7 @@ private: cmMakefile& Makefile; cmPolicies::PolicyStatus Policy12Status; + cmPolicies::PolicyStatus Policy54Status; }; #endif diff --git a/Source/cmExpandedCommandArgument.cxx b/Source/cmExpandedCommandArgument.cxx new file mode 100644 index 000000000..4477cf5a0 --- /dev/null +++ b/Source/cmExpandedCommandArgument.cxx @@ -0,0 +1,51 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmExpandedCommandArgument.h" + +cmExpandedCommandArgument::cmExpandedCommandArgument(): + Quoted(false) +{ + +} + +cmExpandedCommandArgument::cmExpandedCommandArgument( + std::string const& value, bool quoted): + Value(value), Quoted(quoted) +{ + +} + +std::string const& cmExpandedCommandArgument::GetValue() const +{ + return this->Value; +} + +bool cmExpandedCommandArgument::WasQuoted() const +{ + return this->Quoted; +} + +bool cmExpandedCommandArgument::operator== (std::string const& value) const +{ + return this->Value == value; +} + +bool cmExpandedCommandArgument::empty() const +{ + return this->Value.empty(); +} + +const char* cmExpandedCommandArgument::c_str() const +{ + return this->Value.c_str(); +} diff --git a/Source/cmExpandedCommandArgument.h b/Source/cmExpandedCommandArgument.h new file mode 100644 index 000000000..f4e151704 --- /dev/null +++ b/Source/cmExpandedCommandArgument.h @@ -0,0 +1,45 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmExpandedCommandArgument_h +#define cmExpandedCommandArgument_h + +#include "cmStandardIncludes.h" + +/** \class cmExpandedCommandArgument + * \brief Represents an expanded command argument + * + * cmCommandArgument stores a string representing an expanded + * command argument and context information. + */ + +class cmExpandedCommandArgument +{ +public: + cmExpandedCommandArgument(); + cmExpandedCommandArgument(std::string const& value, bool quoted); + + std::string const& GetValue() const; + + bool WasQuoted() const; + + bool operator== (std::string const& value) const; + + bool empty() const; + + const char* c_str() const; + +private: + std::string Value; + bool Quoted; +}; + +#endif diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 25ee25a04..f728c15e3 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -20,15 +20,15 @@ static std::string cmIfCommandError( - cmMakefile* mf, std::vector const& args) + cmMakefile* mf, std::vector const& args) { cmLocalGenerator* lg = mf->GetLocalGenerator(); std::string err = "given arguments:\n "; - for(std::vector::const_iterator i = args.begin(); + for(std::vector::const_iterator i = args.begin(); i != args.end(); ++i) { err += " "; - err += lg->EscapeForCMake(*i); + err += lg->EscapeForCMake(i->GetValue()); } err += "\n"; return err; @@ -105,7 +105,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, std::string errorString; - std::vector expandedArguments; + std::vector expandedArguments; mf.ExpandArguments(this->Functions[c].Arguments, expandedArguments); @@ -189,7 +189,7 @@ bool cmIfCommand { std::string errorString; - std::vector expandedArguments; + std::vector expandedArguments; this->Makefile->ExpandArguments(args, expandedArguments); cmake::MessageType status; diff --git a/Source/cmIfCommand.h b/Source/cmIfCommand.h index ea2a68fcb..689efce65 100644 --- a/Source/cmIfCommand.h +++ b/Source/cmIfCommand.h @@ -70,6 +70,10 @@ public: */ virtual bool IsScriptable() const { return true; } + // Filter the given variable definition based on policy CMP0054. + static const char* GetDefinitionIfUnquoted( + const cmMakefile* mf, cmExpandedCommandArgument const& argument); + cmTypeMacro(cmIfCommand, cmCommand); }; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 04b2d2786..3017d154f 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3292,6 +3292,7 @@ void cmMakefile::PopFunctionBlockerBarrier(bool reportError) this->FunctionBlockerBarriers.pop_back(); } +//---------------------------------------------------------------------------- bool cmMakefile::ExpandArguments( std::vector const& inArgs, std::vector& outArgs) const @@ -3327,6 +3328,47 @@ bool cmMakefile::ExpandArguments( return !cmSystemTools::GetFatalErrorOccured(); } +//---------------------------------------------------------------------------- +bool cmMakefile::ExpandArguments( + std::vector const& inArgs, + std::vector& outArgs) const +{ + std::vector::const_iterator i; + std::string value; + outArgs.reserve(inArgs.size()); + for(i = inArgs.begin(); i != inArgs.end(); ++i) + { + // No expansion in a bracket argument. + if(i->Delim == cmListFileArgument::Bracket) + { + outArgs.push_back(cmExpandedCommandArgument(i->Value, true)); + continue; + } + // Expand the variables in the argument. + value = i->Value; + this->ExpandVariablesInString(value, false, false, false, + i->FilePath, i->Line, + false, false); + + // If the argument is quoted, it should be one argument. + // Otherwise, it may be a list of arguments. + if(i->Delim == cmListFileArgument::Quoted) + { + outArgs.push_back(cmExpandedCommandArgument(value, true)); + } + else + { + std::vector stringArgs; + cmSystemTools::ExpandListArgument(value, stringArgs); + for(size_t j = 0; j < stringArgs.size(); ++j) + { + outArgs.push_back(cmExpandedCommandArgument(stringArgs[j], false)); + } + } + } + return !cmSystemTools::GetFatalErrorOccured(); +} + //---------------------------------------------------------------------------- void cmMakefile::AddFunctionBlocker(cmFunctionBlocker* fb) { @@ -4938,12 +4980,14 @@ void cmMakefile::PopPolicyBarrier(bool reportError) this->PolicyBarriers.pop_back(); } +//---------------------------------------------------------------------------- bool cmMakefile::SetPolicyVersion(const char *version) { return this->GetCMakeInstance()->GetPolicies()-> ApplyPolicyVersion(this,version); } +//---------------------------------------------------------------------------- cmPolicies *cmMakefile::GetPolicies() const { if (!this->GetCMakeInstance()) @@ -4953,6 +4997,23 @@ cmPolicies *cmMakefile::GetPolicies() const return this->GetCMakeInstance()->GetPolicies(); } +//---------------------------------------------------------------------------- +bool cmMakefile::HasCMP0054AlreadyBeenReported( + cmListFileContext context) const +{ + cmCMP0054Id id(context); + + bool alreadyReported = + this->CMP0054ReportedIds.find(id) != this->CMP0054ReportedIds.end(); + + if(!alreadyReported) + { + this->CMP0054ReportedIds.insert(id); + } + + return alreadyReported; +} + //---------------------------------------------------------------------------- void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index d728a62a2..164290aa9 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -21,6 +21,7 @@ #include "cmTarget.h" #include "cmNewLineStyle.h" #include "cmGeneratorTarget.h" +#include "cmExpandedCommandArgument.h" #include "cmake.h" #if defined(CMAKE_BUILD_WITH_CMAKE) @@ -375,7 +376,35 @@ public: /** * Get the Policies Instance */ - cmPolicies *GetPolicies() const; + cmPolicies *GetPolicies() const; + + struct cmCMP0054Id + { + cmCMP0054Id(cmListFileContext const& context): + Context(context) + { + + } + + bool operator< (cmCMP0054Id const& id) const + { + if(this->Context.FilePath != id.Context.FilePath) + return this->Context.FilePath < id.Context.FilePath; + + return this->Context.Line < id.Context.Line; + } + + cmListFileContext Context; + }; + + mutable std::set CMP0054ReportedIds; + + /** + * Determine if the given context, name pair has already been reported + * in context of CMP0054. + */ + bool HasCMP0054AlreadyBeenReported( + cmListFileContext context) const; /** * Add an auxiliary directory to the build. @@ -770,6 +799,10 @@ public: */ bool ExpandArguments(std::vector const& inArgs, std::vector& outArgs) const; + + bool ExpandArguments(std::vector const& inArgs, + std::vector& outArgs) const; + /** * Get the instance */ diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 693945d97..a420f5958 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -359,6 +359,11 @@ cmPolicies::cmPolicies() CMP0053, "CMP0053", "Simplify variable reference and escape sequence evaluation.", 3,1,0, cmPolicies::WARN); + + this->DefinePolicy( + CMP0054, "CMP0054", + "Only interpret if() arguments as variables or keywords when unquoted.", + 3,1,0, cmPolicies::WARN); } cmPolicies::~cmPolicies() diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 5d69d14c2..7c73da82b 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -109,6 +109,8 @@ public: /// INTERFACE_INCLUDE_DIRECTORIES CMP0053, ///< Simplify variable reference and escape sequence evaluation + CMP0054, ///< Only interpret if() arguments as variables + /// or keywords when unquoted. /** \brief Always the last entry. * diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 5565b8a05..851c4cb20 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -34,7 +34,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf, std::string errorString; - std::vector expandedArguments; + std::vector expandedArguments; mf.ExpandArguments(this->Args, expandedArguments); cmake::MessageType messageType; diff --git a/Tests/RunCMake/CMP0054/CMP0054-NEW-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-NEW-stderr.txt new file mode 100644 index 000000000..f5a8fbe6e --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-NEW-stderr.txt @@ -0,0 +1 @@ +$^ diff --git a/Tests/RunCMake/CMP0054/CMP0054-NEW.cmake b/Tests/RunCMake/CMP0054/CMP0054-NEW.cmake new file mode 100644 index 000000000..23a912476 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-NEW.cmake @@ -0,0 +1,47 @@ +cmake_policy(SET CMP0054 NEW) + +set(FOO "BAR") +set(BAZ "ZZZ") +set(MYTRUE ON) +set(MYNUMBER 3) +set(MYVERSION 3.0) + +function(assert_unquoted PREFIX FIRST) + string(REPLACE ";" " " ARGN_SP "${ARGN}") + if(${PREFIX} ${FIRST} ${ARGN}) + message(FATAL_ERROR "Assertion failed [${PREFIX} ${FIRST} ${ARGN_SP}]") + endif() +endfunction() + +function(assert_quoted PREFIX FIRST) + string(REPLACE ";" " " ARGN_SP "${ARGN}") + if(${PREFIX} "${FIRST}" ${ARGN}) + message(FATAL_ERROR "Assertion failed [${PREFIX} \"${FIRST}\" ${ARGN_SP}]") + endif() +endfunction() + +function(assert FIRST) + assert_unquoted(NOT ${FIRST} ${ARGN}) + assert_quoted("" ${FIRST} ${ARGN}) +endfunction() + +assert(MYTRUE) + +assert(FOO MATCHES "^BAR$") + +assert(MYNUMBER LESS 4) +assert(MYNUMBER GREATER 2) +assert(MYNUMBER EQUAL 3) + +assert(FOO STRLESS CCC) +assert(BAZ STRGREATER CCC) +assert(FOO STREQUAL BAR) + +assert_unquoted(NOT MYVERSION VERSION_LESS 3.1) +assert_unquoted("" MYVERSION VERSION_LESS 2.9) + +assert_quoted(NOT MYVERSION VERSION_LESS 2.9) +assert_quoted(NOT MYVERSION VERSION_LESS 3.1) + +assert(MYVERSION VERSION_GREATER 2.9) +assert(MYVERSION VERSION_EQUAL 3.0) diff --git a/Tests/RunCMake/CMP0054/CMP0054-OLD-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-OLD-stderr.txt new file mode 100644 index 000000000..f5a8fbe6e --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-OLD-stderr.txt @@ -0,0 +1 @@ +$^ diff --git a/Tests/RunCMake/CMP0054/CMP0054-OLD.cmake b/Tests/RunCMake/CMP0054/CMP0054-OLD.cmake new file mode 100644 index 000000000..0c4cede6b --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-OLD.cmake @@ -0,0 +1,47 @@ +cmake_policy(SET CMP0054 OLD) + +set(FOO "BAR") +set(BAZ "ZZZ") +set(MYTRUE ON) +set(MYNUMBER 3) +set(MYVERSION 3.0) + +function(assert_unquoted PREFIX FIRST) + string(REPLACE ";" " " ARGN_SP "${ARGN}") + if(${PREFIX} ${FIRST} ${ARGN}) + message(FATAL_ERROR "Assertion failed [${PREFIX} ${FIRST} ${ARGN_SP}]") + endif() +endfunction() + +function(assert_quoted PREFIX FIRST) + string(REPLACE ";" " " ARGN_SP "${ARGN}") + if(${PREFIX} "${FIRST}" ${ARGN}) + message(FATAL_ERROR "Assertion failed [${PREFIX} \"${FIRST}\" ${ARGN_SP}]") + endif() +endfunction() + +function(assert FIRST) + assert_unquoted(NOT ${FIRST} ${ARGN}) + assert_quoted(NOT ${FIRST} ${ARGN}) +endfunction() + +assert(MYTRUE) + +assert(FOO MATCHES "^BAR$") + +assert(MYNUMBER LESS 4) +assert(MYNUMBER GREATER 2) +assert(MYNUMBER EQUAL 3) + +assert(FOO STRLESS CCC) +assert(BAZ STRGREATER CCC) +assert(FOO STREQUAL BAR) + +assert_unquoted(NOT MYVERSION VERSION_LESS 3.1) +assert_unquoted("" MYVERSION VERSION_LESS 2.9) + +assert_quoted("" MYVERSION VERSION_LESS 2.9) +assert_quoted(NOT MYVERSION VERSION_LESS 3.1) + +assert(MYVERSION VERSION_GREATER 2.9) +assert(MYVERSION VERSION_EQUAL 3.0) diff --git a/Tests/RunCMake/CMP0054/CMP0054-WARN-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-WARN-stderr.txt new file mode 100644 index 000000000..3d875ae1b --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-WARN-stderr.txt @@ -0,0 +1,11 @@ +CMake Warning \(dev\) at CMP0054-WARN.cmake:3 \(if\): + Policy CMP0054 is not set: Only interpret if\(\) arguments as variables or + keywords when unquoted. Run "cmake --help-policy CMP0054" for policy + details. Use the cmake_policy command to set the policy and suppress this + warning. + + Quoted variables like "FOO" will no longer be dereferenced when the policy + is set to NEW. Since the policy is not set the OLD behavior will be used. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CMP0054/CMP0054-WARN.cmake b/Tests/RunCMake/CMP0054/CMP0054-WARN.cmake new file mode 100644 index 000000000..37855fc26 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-WARN.cmake @@ -0,0 +1,5 @@ +set(FOO "BAR") + +if(NOT "FOO" STREQUAL "BAR") + message(FATAL_ERROR "The given literals should match") +endif() diff --git a/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings-stderr.txt new file mode 100644 index 000000000..485db527d --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings-stderr.txt @@ -0,0 +1,24 @@ +CMake Warning \(dev\) at CMP0054-duplicate-warnings.cmake:4 \(if\): + Policy CMP0054 is not set: Only interpret if\(\) arguments as variables or + keywords when unquoted. Run "cmake --help-policy CMP0054" for policy + details. Use the cmake_policy command to set the policy and suppress this + warning. + + Quoted variables like "FOO" will no longer be dereferenced when the policy + is set to NEW. Since the policy is not set the OLD behavior will be used. +Call Stack \(most recent call first\): + CMP0054-duplicate-warnings.cmake:8 \(generate_warning\) + CMakeLists.txt:3 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\) at CMP0054-duplicate-warnings.cmake:11 \(if\): + Policy CMP0054 is not set: Only interpret if\(\) arguments as variables or + keywords when unquoted. Run "cmake --help-policy CMP0054" for policy + details. Use the cmake_policy command to set the policy and suppress this + warning. + + Quoted variables like "FOO" will no longer be dereferenced when the policy + is set to NEW. Since the policy is not set the OLD behavior will be used. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings.cmake b/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings.cmake new file mode 100644 index 000000000..04fbe14e6 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings.cmake @@ -0,0 +1,12 @@ +set(FOO "BAR") + +function(generate_warning) + if("FOO" STREQUAL "BAR") + endif() +endfunction() + +generate_warning() +generate_warning() + +if("FOO" STREQUAL "BAR") +endif() diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-result.txt b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-stderr.txt new file mode 100644 index 000000000..f44468449 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at CMP0054-keywords-NEW.cmake:23 \(if\): + if given arguments: + + "NOT" "1" + + Unknown arguments specified +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW.cmake b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW.cmake new file mode 100644 index 000000000..b957658b0 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW.cmake @@ -0,0 +1,25 @@ +cmake_policy(SET CMP0054 NEW) + +function(assert KEYWORD) + if("${KEYWORD}" STREQUAL "${KEYWORD}") + else() + message(FATAL_ERROR + "Assertion failed [\"${KEYWORD}\" STREQUAL \"${KEYWORD}\"]") + endif() +endfunction() + +assert("NOT") +assert("COMMAND") +assert("POLICY") +assert("TARGET") +assert("EXISTS") +assert("IS_DIRECTORY") +assert("IS_SYMLINK") +assert("IS_ABSOLUTE") +assert("DEFINED") +assert("(") +assert(")") + +if("NOT" 1) + message(FATAL_ERROR "[\"NOT\" 1] evaluated true") +endif() diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD-stderr.txt new file mode 100644 index 000000000..f5a8fbe6e --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD-stderr.txt @@ -0,0 +1 @@ +$^ diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD.cmake b/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD.cmake new file mode 100644 index 000000000..a2a7f5183 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD.cmake @@ -0,0 +1,9 @@ +cmake_policy(SET CMP0054 OLD) + +if(NOT 1) + message(FATAL_ERROR "[NOT 1] evaluated true") +endif() + +if("NOT" 1) + message(FATAL_ERROR "[\"NOT\" 1] evaluated true") +endif() diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN-stderr.txt new file mode 100644 index 000000000..b1ebd49de --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN-stderr.txt @@ -0,0 +1,12 @@ +CMake Warning \(dev\) at CMP0054-keywords-WARN.cmake:1 \(if\): + Policy CMP0054 is not set: Only interpret if\(\) arguments as variables or + keywords when unquoted. Run "cmake --help-policy CMP0054" for policy + details. Use the cmake_policy command to set the policy and suppress this + warning. + + Quoted keywords like "NOT" will no longer be interpreted as keywords when + the policy is set to NEW. Since the policy is not set the OLD behavior + will be used. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN.cmake b/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN.cmake new file mode 100644 index 000000000..ee0a62315 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN.cmake @@ -0,0 +1,3 @@ +if("NOT" 1) + message(FATAL_ERROR "[\"NOT\" 1] evaluated true") +endif() diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope-stderr.txt new file mode 100644 index 000000000..f5a8fbe6e --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope-stderr.txt @@ -0,0 +1 @@ +$^ diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope.cmake b/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope.cmake new file mode 100644 index 000000000..b6b243caa --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope.cmake @@ -0,0 +1,53 @@ +set(FOO BAR) + +cmake_policy(SET CMP0054 NEW) + +function(function_defined_new_called_old) + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") + endif() +endfunction() + +macro(macro_defined_new_called_old) + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") + endif() +endmacro() + +cmake_policy(SET CMP0054 OLD) + +function_defined_new_called_old() +macro_defined_new_called_old() + +function(function_defined_old_called_new) + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") + endif() +endfunction() + +macro(macro_defined_old_called_new) + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") + endif() +endmacro() + +cmake_policy(SET CMP0054 NEW) + +function_defined_old_called_new() +macro_defined_old_called_new() diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope-stderr.txt new file mode 100644 index 000000000..f5a8fbe6e --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope-stderr.txt @@ -0,0 +1 @@ +$^ diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope.cmake b/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope.cmake new file mode 100644 index 000000000..87c968a06 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope.cmake @@ -0,0 +1,49 @@ +set(FOO BAR) + +cmake_policy(SET CMP0054 NEW) + +foreach(loop_var arg1 arg2) + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") + endif() + + cmake_policy(SET CMP0054 OLD) + + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") + endif() + + cmake_policy(SET CMP0054 NEW) +endforeach() + +cmake_policy(SET CMP0054 OLD) + +foreach(loop_var arg1 arg2) + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") + endif() + + cmake_policy(SET CMP0054 NEW) + + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") + endif() + + cmake_policy(SET CMP0054 OLD) +endforeach() diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if-stderr.txt new file mode 100644 index 000000000..f5a8fbe6e --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if-stderr.txt @@ -0,0 +1 @@ +$^ diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if.cmake b/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if.cmake new file mode 100644 index 000000000..dd7434d73 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if.cmake @@ -0,0 +1,41 @@ +set(FOO BAR) + +cmake_policy(SET CMP0054 NEW) + +if("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") + + if("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") + endif() + + cmake_policy(SET CMP0054 OLD) + + if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") + endif() +endif() + +if("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") +endif() + +cmake_policy(SET CMP0054 OLD) + +if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") + + if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") + endif() + + cmake_policy(SET CMP0054 NEW) + + if("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") + endif() +endif() + +if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") +endif() diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope-stderr.txt new file mode 100644 index 000000000..f5a8fbe6e --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope-stderr.txt @@ -0,0 +1 @@ +$^ diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope.cmake b/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope.cmake new file mode 100644 index 000000000..2b22778b5 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope.cmake @@ -0,0 +1,65 @@ +set(FOO BAR) + +set(LOOP_VAR "") + +cmake_policy(SET CMP0054 NEW) + +while(NOT LOOP_VAR STREQUAL "xx") + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") + endif() + + cmake_policy(SET CMP0054 OLD) + + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") + endif() + + cmake_policy(SET CMP0054 NEW) + + set(LOOP_VAR "${LOOP_VAR}x") +endwhile() + +while("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") +endwhile() + +set(LOOP_VAR "") + +cmake_policy(SET CMP0054 OLD) + +while(NOT LOOP_VAR STREQUAL "xx") + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") + endif() + + cmake_policy(SET CMP0054 NEW) + + if(NOT FOO STREQUAL BAR) + message(FATAL_ERROR "The variable should match the string") + endif() + + if("FOO" STREQUAL BAR) + message(FATAL_ERROR "The strings should not match") + endif() + + cmake_policy(SET CMP0054 OLD) + + set(LOOP_VAR "${LOOP_VAR}x") +endwhile() + +if(NOT "FOO" STREQUAL BAR) + message(FATAL_ERROR "The quoted variable should match the string") +endif() diff --git a/Tests/RunCMake/CMP0054/CMakeLists.txt b/Tests/RunCMake/CMP0054/CMakeLists.txt new file mode 100644 index 000000000..289710955 --- /dev/null +++ b/Tests/RunCMake/CMP0054/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.0) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CMP0054/RunCMakeTest.cmake b/Tests/RunCMake/CMP0054/RunCMakeTest.cmake new file mode 100644 index 000000000..2f2fb765d --- /dev/null +++ b/Tests/RunCMake/CMP0054/RunCMakeTest.cmake @@ -0,0 +1,13 @@ +include(RunCMake) + +run_cmake(CMP0054-OLD) +run_cmake(CMP0054-NEW) +run_cmake(CMP0054-WARN) +run_cmake(CMP0054-keywords-NEW) +run_cmake(CMP0054-keywords-OLD) +run_cmake(CMP0054-keywords-WARN) +run_cmake(CMP0054-duplicate-warnings) +run_cmake(CMP0054-policy-command-scope) +run_cmake(CMP0054-policy-foreach-scope) +run_cmake(CMP0054-policy-while-scope) +run_cmake(CMP0054-policy-nested-if) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 3cd9947c1..8f09c5f1c 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -47,6 +47,7 @@ add_RunCMake_test(CMP0049) add_RunCMake_test(CMP0050) add_RunCMake_test(CMP0051) add_RunCMake_test(CMP0053) +add_RunCMake_test(CMP0054) add_RunCMake_test(CTest) if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") add_RunCMake_test(CompilerChange)