ENH: Better policies for functions and macros
This teaches functions and macros to use policies recorded at creation time when they are invoked. It restores the policies as a weak policy stack entry so that any policies set by a function escape to its caller as before.
This commit is contained in:
parent
18eadebc4c
commit
3028ca756c
|
@ -123,6 +123,12 @@ public:
|
||||||
" cmake_policy(POP)\n"
|
" cmake_policy(POP)\n"
|
||||||
"Each PUSH must have a matching POP to erase any changes. "
|
"Each PUSH must have a matching POP to erase any changes. "
|
||||||
"This is useful to make temporary changes to policy settings."
|
"This is useful to make temporary changes to policy settings."
|
||||||
|
"\n"
|
||||||
|
"Functions and macros record policy settings when they are created "
|
||||||
|
"and use the pre-record policies when they are invoked. "
|
||||||
|
"If the function or macro implementation sets policies, the changes "
|
||||||
|
"automatically propagate up through callers until they reach the "
|
||||||
|
"closest nested policy stack entry."
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ public:
|
||||||
// we must copy when we clone
|
// we must copy when we clone
|
||||||
newC->Args = this->Args;
|
newC->Args = this->Args;
|
||||||
newC->Functions = this->Functions;
|
newC->Functions = this->Functions;
|
||||||
|
newC->Policies = this->Policies;
|
||||||
return newC;
|
return newC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +82,7 @@ public:
|
||||||
|
|
||||||
std::vector<std::string> Args;
|
std::vector<std::string> Args;
|
||||||
std::vector<cmListFileFunction> Functions;
|
std::vector<cmListFileFunction> Functions;
|
||||||
|
cmPolicies::PolicyMap Policies;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,6 +110,10 @@ bool cmFunctionHelperCommand::InvokeInitialPass
|
||||||
cmMakefile::ScopePushPop varScope(this->Makefile);
|
cmMakefile::ScopePushPop varScope(this->Makefile);
|
||||||
static_cast<void>(varScope);
|
static_cast<void>(varScope);
|
||||||
|
|
||||||
|
// Push a weak policy scope which restores the policies recorded at
|
||||||
|
// function creation.
|
||||||
|
cmMakefile::PolicyPushPop polScope(this->Makefile, true, this->Policies);
|
||||||
|
|
||||||
// set the value of argc
|
// set the value of argc
|
||||||
cmOStringStream strStream;
|
cmOStringStream strStream;
|
||||||
strStream << expandedArgs.size();
|
strStream << expandedArgs.size();
|
||||||
|
@ -165,6 +171,7 @@ bool cmFunctionHelperCommand::InvokeInitialPass
|
||||||
// The error message should have already included the call stack
|
// The error message should have already included the call stack
|
||||||
// so we do not need to report an error here.
|
// so we do not need to report an error here.
|
||||||
lexScope.Quiet();
|
lexScope.Quiet();
|
||||||
|
polScope.Quiet();
|
||||||
inStatus.SetNestedError(true);
|
inStatus.SetNestedError(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -206,6 +213,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
|
||||||
cmFunctionHelperCommand *f = new cmFunctionHelperCommand();
|
cmFunctionHelperCommand *f = new cmFunctionHelperCommand();
|
||||||
f->Args = this->Args;
|
f->Args = this->Args;
|
||||||
f->Functions = this->Functions;
|
f->Functions = this->Functions;
|
||||||
|
mf.RecordPolicies(f->Policies);
|
||||||
|
|
||||||
// Set the FilePath on the arguments to match the function since it is
|
// Set the FilePath on the arguments to match the function since it is
|
||||||
// not stored and the original values may be freed
|
// not stored and the original values may be freed
|
||||||
|
|
|
@ -104,7 +104,11 @@ public:
|
||||||
"will have the actual values of the arguments passed in. This "
|
"will have the actual values of the arguments passed in. This "
|
||||||
"facilitates creating functions with optional arguments. Additionally "
|
"facilitates creating functions with optional arguments. Additionally "
|
||||||
"ARGV holds the list of all arguments given to the function and ARGN "
|
"ARGV holds the list of all arguments given to the function and ARGN "
|
||||||
"holds the list of argument pass the last expected argument.";
|
"holds the list of argument pass the last expected argument."
|
||||||
|
"\n"
|
||||||
|
"See the cmake_policy() command documentation for the behavior of "
|
||||||
|
"policies inside functions."
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmTypeMacro(cmFunctionCommand, cmCommand);
|
cmTypeMacro(cmFunctionCommand, cmCommand);
|
||||||
|
|
|
@ -36,6 +36,7 @@ public:
|
||||||
// we must copy when we clone
|
// we must copy when we clone
|
||||||
newC->Args = this->Args;
|
newC->Args = this->Args;
|
||||||
newC->Functions = this->Functions;
|
newC->Functions = this->Functions;
|
||||||
|
newC->Policies = this->Policies;
|
||||||
return newC;
|
return newC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +82,7 @@ public:
|
||||||
|
|
||||||
std::vector<std::string> Args;
|
std::vector<std::string> Args;
|
||||||
std::vector<cmListFileFunction> Functions;
|
std::vector<cmListFileFunction> Functions;
|
||||||
|
cmPolicies::PolicyMap Policies;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,6 +112,10 @@ bool cmMacroHelperCommand::InvokeInitialPass
|
||||||
// Enforce matching logical blocks inside the macro.
|
// Enforce matching logical blocks inside the macro.
|
||||||
cmMakefile::LexicalPushPop lexScope(this->Makefile);
|
cmMakefile::LexicalPushPop lexScope(this->Makefile);
|
||||||
|
|
||||||
|
// Push a weak policy scope which restores the policies recorded at
|
||||||
|
// macro creation.
|
||||||
|
cmMakefile::PolicyPushPop polScope(this->Makefile, true, this->Policies);
|
||||||
|
|
||||||
// set the value of argc
|
// set the value of argc
|
||||||
cmOStringStream argcDefStream;
|
cmOStringStream argcDefStream;
|
||||||
argcDefStream << expandedArgs.size();
|
argcDefStream << expandedArgs.size();
|
||||||
|
@ -219,6 +225,7 @@ bool cmMacroHelperCommand::InvokeInitialPass
|
||||||
// The error message should have already included the call stack
|
// The error message should have already included the call stack
|
||||||
// so we do not need to report an error here.
|
// so we do not need to report an error here.
|
||||||
lexScope.Quiet();
|
lexScope.Quiet();
|
||||||
|
polScope.Quiet();
|
||||||
inStatus.SetNestedError(true);
|
inStatus.SetNestedError(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -264,6 +271,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
|
||||||
cmMacroHelperCommand *f = new cmMacroHelperCommand();
|
cmMacroHelperCommand *f = new cmMacroHelperCommand();
|
||||||
f->Args = this->Args;
|
f->Args = this->Args;
|
||||||
f->Functions = this->Functions;
|
f->Functions = this->Functions;
|
||||||
|
mf.RecordPolicies(f->Policies);
|
||||||
std::string newName = "_" + this->Args[0];
|
std::string newName = "_" + this->Args[0];
|
||||||
mf.GetCMakeInstance()->RenameCommand(this->Args[0].c_str(),
|
mf.GetCMakeInstance()->RenameCommand(this->Args[0].c_str(),
|
||||||
newName.c_str());
|
newName.c_str());
|
||||||
|
|
|
@ -111,7 +111,11 @@ public:
|
||||||
"are not variables in the usual CMake sense. They are string "
|
"are not variables in the usual CMake sense. They are string "
|
||||||
"replacements much like the c preprocessor would do with a "
|
"replacements much like the c preprocessor would do with a "
|
||||||
"macro. If you want true CMake variables you should look at "
|
"macro. If you want true CMake variables you should look at "
|
||||||
"the function command.";
|
"the function command."
|
||||||
|
"\n"
|
||||||
|
"See the cmake_policy() command documentation for the behavior of "
|
||||||
|
"policies inside macros."
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmTypeMacro(cmMacroCommand, cmCommand);
|
cmTypeMacro(cmMacroCommand, cmCommand);
|
||||||
|
|
|
@ -3774,3 +3774,15 @@ cmPolicies *cmMakefile::GetPolicies()
|
||||||
}
|
}
|
||||||
return this->GetCMakeInstance()->GetPolicies();
|
return this->GetCMakeInstance()->GetPolicies();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm)
|
||||||
|
{
|
||||||
|
/* Record the setting of every policy. */
|
||||||
|
typedef cmPolicies::PolicyID PolicyID;
|
||||||
|
for(PolicyID pid = cmPolicies::CMP0000;
|
||||||
|
pid != cmPolicies::CMPCOUNT; pid = PolicyID(pid+1))
|
||||||
|
{
|
||||||
|
pm[pid] = this->GetPolicyStatus(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -343,6 +343,7 @@ public:
|
||||||
bool SetPolicy(const char *id, cmPolicies::PolicyStatus status);
|
bool SetPolicy(const char *id, cmPolicies::PolicyStatus status);
|
||||||
cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id);
|
cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id);
|
||||||
bool SetPolicyVersion(const char *version);
|
bool SetPolicyVersion(const char *version);
|
||||||
|
void RecordPolicies(cmPolicies::PolicyMap& pm);
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/** Helper class to push and pop policies automatically. */
|
/** Helper class to push and pop policies automatically. */
|
||||||
|
|
|
@ -102,6 +102,7 @@ IF(BUILD_TESTING)
|
||||||
ADD_TEST_MACRO(Preprocess Preprocess)
|
ADD_TEST_MACRO(Preprocess Preprocess)
|
||||||
ADD_TEST_MACRO(ExportImport ExportImport)
|
ADD_TEST_MACRO(ExportImport ExportImport)
|
||||||
ADD_TEST_MACRO(Unset Unset)
|
ADD_TEST_MACRO(Unset Unset)
|
||||||
|
ADD_TEST_MACRO(PolicyScope PolicyScope)
|
||||||
|
|
||||||
SET(CMAKE_BUILD_TEST_SOURCE_DIR "${CMake_SOURCE_DIR}/Tests/COnly")
|
SET(CMAKE_BUILD_TEST_SOURCE_DIR "${CMake_SOURCE_DIR}/Tests/COnly")
|
||||||
SET(CMAKE_BUILD_TEST_BINARY_DIR "${CMake_BINARY_DIR}/Tests/CMakeBuildCOnly")
|
SET(CMAKE_BUILD_TEST_BINARY_DIR "${CMake_BINARY_DIR}/Tests/CMakeBuildCOnly")
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
cmake_minimum_required(VERSION 2.6.3)
|
||||||
|
project(PolicyScope C)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Helper function to report results.
|
||||||
|
function(check msg lhs rhs)
|
||||||
|
if(NOT "${lhs}" STREQUAL "${rhs}")
|
||||||
|
message(FATAL_ERROR "${msg}: expected [${lhs}], got [${rhs}]")
|
||||||
|
endif()
|
||||||
|
endfunction(check)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Test function and macro policy recording.
|
||||||
|
|
||||||
|
# Create the functions in an isolated scope in which we change policies.
|
||||||
|
cmake_policy(PUSH)
|
||||||
|
if(1)
|
||||||
|
# Change CMP0002
|
||||||
|
cmake_policy(SET CMP0002 OLD)
|
||||||
|
function(func1)
|
||||||
|
# CMP0002 should be changed when this function is invoked
|
||||||
|
cmake_policy(GET CMP0002 cmp)
|
||||||
|
check(CMP0002 "OLD" "${cmp}")
|
||||||
|
endfunction(func1)
|
||||||
|
|
||||||
|
# Unset CMP0002
|
||||||
|
cmake_policy(VERSION 2.4)
|
||||||
|
macro(macro1)
|
||||||
|
# CMP0002 should be unset when this macro is invoked
|
||||||
|
cmake_policy(GET CMP0002 cmp)
|
||||||
|
check(CMP0002 "" "${cmp}")
|
||||||
|
|
||||||
|
# Setting the policy should work here and also in the caller.
|
||||||
|
cmake_policy(SET CMP0002 OLD)
|
||||||
|
cmake_policy(GET CMP0002 cmp)
|
||||||
|
check(CMP0002 "OLD" "${cmp}")
|
||||||
|
endmacro(macro1)
|
||||||
|
endif(1)
|
||||||
|
cmake_policy(POP)
|
||||||
|
|
||||||
|
# CMP0002 should still be NEW in this context.
|
||||||
|
cmake_policy(GET CMP0002 cmp)
|
||||||
|
check(CMP0002 "NEW" "${cmp}")
|
||||||
|
|
||||||
|
# Check the recorded policies
|
||||||
|
func1()
|
||||||
|
macro1()
|
||||||
|
|
||||||
|
# The macro should have changed CMP0002.
|
||||||
|
cmake_policy(GET CMP0002 cmp)
|
||||||
|
check(CMP0002 "OLD" "${cmp}")
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Dummy executable so the project can build and run.
|
||||||
|
add_executable(PolicyScope main.c)
|
|
@ -0,0 +1,4 @@
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue