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"
|
||||
"Each PUSH must have a matching POP to erase any changes. "
|
||||
"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
|
||||
newC->Args = this->Args;
|
||||
newC->Functions = this->Functions;
|
||||
newC->Policies = this->Policies;
|
||||
return newC;
|
||||
}
|
||||
|
||||
|
@ -81,6 +82,7 @@ public:
|
|||
|
||||
std::vector<std::string> Args;
|
||||
std::vector<cmListFileFunction> Functions;
|
||||
cmPolicies::PolicyMap Policies;
|
||||
};
|
||||
|
||||
|
||||
|
@ -108,6 +110,10 @@ bool cmFunctionHelperCommand::InvokeInitialPass
|
|||
cmMakefile::ScopePushPop varScope(this->Makefile);
|
||||
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
|
||||
cmOStringStream strStream;
|
||||
strStream << expandedArgs.size();
|
||||
|
@ -165,6 +171,7 @@ bool cmFunctionHelperCommand::InvokeInitialPass
|
|||
// The error message should have already included the call stack
|
||||
// so we do not need to report an error here.
|
||||
lexScope.Quiet();
|
||||
polScope.Quiet();
|
||||
inStatus.SetNestedError(true);
|
||||
return false;
|
||||
}
|
||||
|
@ -206,6 +213,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
|
|||
cmFunctionHelperCommand *f = new cmFunctionHelperCommand();
|
||||
f->Args = this->Args;
|
||||
f->Functions = this->Functions;
|
||||
mf.RecordPolicies(f->Policies);
|
||||
|
||||
// Set the FilePath on the arguments to match the function since it is
|
||||
// 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 "
|
||||
"facilitates creating functions with optional arguments. Additionally "
|
||||
"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);
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
// we must copy when we clone
|
||||
newC->Args = this->Args;
|
||||
newC->Functions = this->Functions;
|
||||
newC->Policies = this->Policies;
|
||||
return newC;
|
||||
}
|
||||
|
||||
|
@ -81,6 +82,7 @@ public:
|
|||
|
||||
std::vector<std::string> Args;
|
||||
std::vector<cmListFileFunction> Functions;
|
||||
cmPolicies::PolicyMap Policies;
|
||||
};
|
||||
|
||||
|
||||
|
@ -110,6 +112,10 @@ bool cmMacroHelperCommand::InvokeInitialPass
|
|||
// Enforce matching logical blocks inside the macro.
|
||||
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
|
||||
cmOStringStream argcDefStream;
|
||||
argcDefStream << expandedArgs.size();
|
||||
|
@ -219,6 +225,7 @@ bool cmMacroHelperCommand::InvokeInitialPass
|
|||
// The error message should have already included the call stack
|
||||
// so we do not need to report an error here.
|
||||
lexScope.Quiet();
|
||||
polScope.Quiet();
|
||||
inStatus.SetNestedError(true);
|
||||
return false;
|
||||
}
|
||||
|
@ -264,6 +271,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
|
|||
cmMacroHelperCommand *f = new cmMacroHelperCommand();
|
||||
f->Args = this->Args;
|
||||
f->Functions = this->Functions;
|
||||
mf.RecordPolicies(f->Policies);
|
||||
std::string newName = "_" + this->Args[0];
|
||||
mf.GetCMakeInstance()->RenameCommand(this->Args[0].c_str(),
|
||||
newName.c_str());
|
||||
|
|
|
@ -111,7 +111,11 @@ public:
|
|||
"are not variables in the usual CMake sense. They are string "
|
||||
"replacements much like the c preprocessor would do with a "
|
||||
"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);
|
||||
|
|
|
@ -3774,3 +3774,15 @@ cmPolicies *cmMakefile::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);
|
||||
cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id);
|
||||
bool SetPolicyVersion(const char *version);
|
||||
void RecordPolicies(cmPolicies::PolicyMap& pm);
|
||||
//@}
|
||||
|
||||
/** Helper class to push and pop policies automatically. */
|
||||
|
|
|
@ -102,6 +102,7 @@ IF(BUILD_TESTING)
|
|||
ADD_TEST_MACRO(Preprocess Preprocess)
|
||||
ADD_TEST_MACRO(ExportImport ExportImport)
|
||||
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_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