diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index 410058f1c1..d955ff7e08 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -127,7 +127,7 @@ char* cmCommandArgumentParserHelper::ExpandVariable(const char* var) // check to see if we need to print a warning // if strict mode is on and the variable has // not been "cleared"/initialized with a set(foo ) call - if(this->StrictMode && !this->Makefile->VariableCleared(var)) + if(this->StrictMode && !this->Makefile->VariableInitialized(var)) { cmOStringStream msg; msg << this->FileName << ":" << this->FileLine << ":" << diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index c56641c91c..d89168df07 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -43,13 +43,17 @@ class cmMakefile::Internals { public: std::stack > VarStack; + std::stack > VarInitStack; std::set VarRemoved; }; // default is not to be building executables cmMakefile::cmMakefile(): Internal(new Internals) { - this->Internal->VarStack.push(cmDefinitions()); + const cmDefinitions& defs = cmDefinitions(); + const std::set globalKeys = defs.LocalKeys(); + this->Internal->VarStack.push(defs); + this->Internal->VarInitStack.push(globalKeys); // Setup the default include file regular expression (match everything). this->IncludeFileRegularExpression = "^.*$"; @@ -1685,6 +1689,7 @@ void cmMakefile::AddCacheDefinition(const char* name, const char* value, void cmMakefile::AddDefinition(const char* name, bool value) { this->Internal->VarStack.top().Set(name, value? "ON" : "OFF"); + this->Internal->VarInitStack.top().insert(name); #ifdef CMAKE_BUILD_WITH_CMAKE cmVariableWatch* vv = this->GetVariableWatch(); if ( vv ) @@ -1695,6 +1700,15 @@ void cmMakefile::AddDefinition(const char* name, bool value) #endif } +bool cmMakefile::VariableInitialized(const char* var) const +{ + if(this->Internal->VarInitStack.top().find(var) != this->Internal->VarInitStack.top().end()) + { + return true; + } + return false; +} + bool cmMakefile::VariableCleared(const char* var) const { if(this->Internal->VarRemoved.find(var) != this->Internal->VarRemoved.end()) @@ -1708,6 +1722,7 @@ void cmMakefile::RemoveDefinition(const char* name) { this->Internal->VarStack.top().Set(name, 0); this->Internal->VarRemoved.insert(name); + this->Internal->VarInitStack.top().insert(name); #ifdef CMAKE_BUILD_WITH_CMAKE cmVariableWatch* vv = this->GetVariableWatch(); if ( vv ) @@ -3316,12 +3331,30 @@ std::string cmMakefile::GetListFileStack() void cmMakefile::PushScope() { cmDefinitions* parent = &this->Internal->VarStack.top(); + const std::set& init = this->Internal->VarInitStack.top(); this->Internal->VarStack.push(cmDefinitions(parent)); + this->Internal->VarInitStack.push(init); } void cmMakefile::PopScope() { + cmDefinitions* current = &this->Internal->VarStack.top(); + std::set init = this->Internal->VarInitStack.top(); + const std::set& locals = current->LocalKeys(); + // Remove initialization information for variables in the local scope. + std::set::const_iterator it = locals.begin(); + for (; it != locals.end(); ++it) + { + init.erase(*it); + } this->Internal->VarStack.pop(); + this->Internal->VarInitStack.pop(); + // Push initialization up to the parent scope. + it = init.begin(); + for (; it != init.end(); ++it) + { + this->Internal->VarInitStack.top().insert(*it); + } } void cmMakefile::RaiseScope(const char *var, const char *varDef) diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index daeab8392c..cec273805b 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -61,6 +61,8 @@ public: unsigned int GetCacheMajorVersion(); unsigned int GetCacheMinorVersion(); + /* return true if a variable has been initialized */ + bool VariableInitialized(const char* ) const; /* return true if a variable has been set with set(foo ) */