diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 5c8f07aa3..dfdbc8634 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -213,84 +213,69 @@ bool cmIfCommand namespace { //========================================================================= - // returns true if succesfull, the resulting bool parsed is stored in result - bool GetBooleanValue(std::string &newArg, - cmMakefile *makefile, - bool &result, - std::string &errorString, - cmPolicies::PolicyStatus Policy12Status, - cmake::MessageType &status) + bool GetBooleanValue(std::string& arg, cmMakefile* mf) { - if (Policy12Status != cmPolicies::OLD && - Policy12Status != cmPolicies::WARN) - { - // please note IsOn(var) does not always equal !IsOff(var) - // that is why each is called - if (cmSystemTools::IsOn(newArg.c_str())) - { - result = true; - return true; - } - if (cmSystemTools::IsOff(newArg.c_str())) - { - result = false; - return true; - } - return false; - } - - // Old policy is more complex... - // 0 and 1 are very common, test for them first quickly - if (newArg == "0") + // Check basic constants. + if (arg == "0") { - result = false; - return true; - } - if (newArg == "1") - { - result = true; - return true; - } - - // old behavior is to dereference the var - if (Policy12Status == cmPolicies::OLD) - { - return false; - } - - // now test for values that may be the name of a variable - // warn if used - if (cmSystemTools::IsOn(newArg.c_str())) - { - // only warn if the value would change - const char *def = makefile->GetDefinition(newArg.c_str()); - if (cmSystemTools::IsOff(def)) - { - cmPolicies* policies = makefile->GetPolicies(); - errorString = "A variable or argument named \"" - + newArg - + "\" appears in a conditional statement. " - + policies->GetPolicyWarning(cmPolicies::CMP0012); - status = cmake::AUTHOR_WARNING; - } - return false; - } - if (cmSystemTools::IsOff(newArg.c_str())) - { - // only warn if the value would change - const char *def = makefile->GetDefinition(newArg.c_str()); - if (!cmSystemTools::IsOff(def)) - { - cmPolicies* policies = makefile->GetPolicies(); - errorString = "A variable or argument named \"" - + newArg - + "\" appears in a conditional statement. " - + policies->GetPolicyWarning(cmPolicies::CMP0012); - status = cmake::AUTHOR_WARNING; - } - return false; - } return false; + } + if (arg == "1") + { + return true; + } + + // Check named constants. + if (cmSystemTools::IsOn(arg.c_str())) + { + return true; + } + if (cmSystemTools::IsOff(arg.c_str())) + { + return false; + } + + // Check for numbers. + if(!arg.empty()) + { + char* end; + double d = strtod(arg.c_str(), &end); + if(*end == '\0') + { + // The whole string is a number. Use C conversion to bool. + return d? true:false; + } + } + + // Check definition. + const char* def = mf->GetDefinition(arg.c_str()); + return !cmSystemTools::IsOff(def); + } + + //========================================================================= + // Boolean value behavior from CMake 2.6.4 and below. + bool GetBooleanValueOld(std::string const& arg, cmMakefile* mf, bool one) + { + if(one) + { + // Old IsTrue behavior for single argument. + if(arg == "0") + { return false; } + else if(arg == "1") + { return true; } + else + { return !cmSystemTools::IsOff(mf->GetDefinition(arg.c_str())); } + } + else + { + // Old GetVariableOrNumber behavior. + const char* def = mf->GetDefinition(arg.c_str()); + if(!def && atoi(arg.c_str())) + { + def = arg.c_str(); + } + return !cmSystemTools::IsOff(def); + } } //========================================================================= @@ -300,16 +285,51 @@ namespace cmMakefile *makefile, std::string &errorString, cmPolicies::PolicyStatus Policy12Status, - cmake::MessageType &status) + cmake::MessageType &status, + bool oneArg = false) { - bool result = false; - if (GetBooleanValue(newArg, makefile, result, - errorString, Policy12Status, status)) + // Use the policy if it is set. + if (Policy12Status == cmPolicies::NEW) { - return result; + return GetBooleanValue(newArg, makefile); } - const char *def = makefile->GetDefinition(newArg.c_str()); - return !cmSystemTools::IsOff(def); + else if (Policy12Status == cmPolicies::OLD) + { + return GetBooleanValueOld(newArg, makefile, oneArg); + } + + // Check policy only if old and new results differ. + bool newResult = GetBooleanValue(newArg, makefile); + bool oldResult = GetBooleanValueOld(newArg, makefile, oneArg); + if(newResult != oldResult) + { + switch(Policy12Status) + { + case cmPolicies::WARN: + { + cmPolicies* policies = makefile->GetPolicies(); + errorString = "An argument named \"" + newArg + + "\" appears in a conditional statement. " + + policies->GetPolicyWarning(cmPolicies::CMP0012); + status = cmake::AUTHOR_WARNING; + } + case cmPolicies::OLD: + return oldResult; + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + { + cmPolicies* policies = makefile->GetPolicies(); + errorString = "An argument named \"" + newArg + + "\" appears in a conditional statement. " + + policies->GetRequiredPolicyError(cmPolicies::CMP0012); + status = cmake::FATAL_ERROR; + } + case cmPolicies::NEW: + break; + } + } + return newResult; } //========================================================================= @@ -898,7 +918,7 @@ bool cmIfCommand::IsTrue(const std::vector &args, makefile, errorString, Policy12Status, - status); + status, true); } //========================================================================= diff --git a/Source/cmIfCommand.h b/Source/cmIfCommand.h index f48022028..107a8923b 100644 --- a/Source/cmIfCommand.h +++ b/Source/cmIfCommand.h @@ -121,16 +121,24 @@ public: "Then any EQUAL, LESS, GREATER, STRLESS, STRGREATER, STREQUAL, MATCHES " "will be evaluated. Then NOT operators and finally AND, OR operators " "will be evaluated. Possible expressions are:\n" - " if(variable)\n" - "True if the variable's value is not empty, 0, N, NO, OFF, FALSE, " - "NOTFOUND, or -NOTFOUND.\n" - " if(NOT variable)\n" - "True if the variable's value is empty, 0, N, NO, OFF, FALSE, " - "NOTFOUND, or -NOTFOUND.\n" - " if(variable1 AND variable2)\n" - "True if both variables would be considered true individually.\n" - " if(variable1 OR variable2)\n" - "True if either variable would be considered true individually.\n" + " if()\n" + "True if the constant is 1, ON, YES, TRUE, Y, or a non-zero number. " + "False if the constant is 0, OFF, NO, FALSE, N, IGNORE, \"\", " + "or ends in the suffix '-NOTFOUND'. " + "Named boolean constants are case-insensitive." + "\n" + " if()\n" + "True if the variable's value is not a false constant." + "\n" + " if(NOT )\n" + "True if the expression is not true." + "\n" + " if( AND )\n" + "True if both expressions would be considered true individually." + "\n" + " if( OR )\n" + "True if either expression would be considered true individually." + "\n" " if(COMMAND command-name)\n" "True if the given name is a command, macro or function that can be " "invoked.\n" diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 0d35b6567..6b35b5b05 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -358,19 +358,24 @@ cmPolicies::cmPolicies() this->DefinePolicy( CMP0012, "CMP0012", - "The if() command can recognize named boolean constants.", - "In CMake versions 2.6.4 and lower the only boolean constants were 0 " - "and 1. Other boolean constants such as true, false, yes, no, " + "if() recognizes numbers and boolean constants.", + "In CMake versions 2.6.4 and lower the if() command implicitly " + "dereferenced arguments corresponding to variables, even those named " + "like numbers or boolean constants, except for 0 and 1. " + "Numbers and boolean constants such as true, false, yes, no, " "on, off, y, n, notfound, ignore (all case insensitive) were recognized " "in some cases but not all. " "For example, the code \"if(TRUE)\" might have evaluated as false. " - "In later versions of cmake these values are " - "treated as boolean constants more consistently and should not be used " - "as variable names. " - "The OLD behavior for this policy is to allow variables to have names " - "such as true and to dereference them. " - "The NEW behavior for this policy is to treat strings like true as a " - "boolean constant.", + "Numbers such as 2 were recognized only in " + "boolean expressions like \"if(NOT 2)\" (leading to false) " + "but not as a single-argument like \"if(2)\" (also leading to false). " + "Later versions of CMake prefer to treat numbers and boolean constants " + "literally, so they should not be used as variable names." + "\n" + "The OLD behavior for this policy is to implicitly dereference variables " + "named like numbers and boolean constants. " + "The NEW behavior for this policy is to recognize numbers and " + "boolean constants without dereferencing variables with such names.", 2,8,0, cmPolicies::WARN); this->DefinePolicy( diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index cf808bd4c..4d1c3fc89 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -47,7 +47,7 @@ public: CMP0009, // GLOB_RECURSE should not follow symlinks by default CMP0010, // Bad variable reference syntax is an error CMP0011, // Strong policy scope for include and find_package - CMP0012, // Strong handling of boolean constants + CMP0012, // Recognize numbers and boolean constants in if() CMP0013, // Duplicate binary directories not allowed CMP0014, // Input directories must have CMakeLists.txt