At 2/16/2008 02:13 PM, Alexander Neundorf wrote:
>
> I don't mean to remove the SET(PARENT_SCOPE) feature, where the main
> purpose is to set a global variable from within a function.
> But if SET( ... PARENT_SCOPE) is called outside a function, the effect is
> that the variable is set in the parent directory. This is the part where
> I'm not sure it's a good idea.

...this would be the patch, with the patch PARENT_SCOPE only raises the scope
out of a function, but not to the parent directory anymore.

Hey guys,

Honestly the PARENT_SCOPE "feature" is still limiting the way I'd like to use FUNCTION. I've whined about scope at Kitware for a while so FUNCTION was very welcome, but I'm wondering if I could have my cake and eat it too: I like my macros to call helper macros to divide my work in smaller units. Say, if I have a PARSE_COMPANION_CUBE_FILE macro that loads a file and parses it, it's very likely said macro will just load the file in a string, and call another PARSE_COMPANION_CUBE macro. This gives my fellow maintainers/developpers the ability to parse a file directly, or grab the file in a different way and parse the string later using the second macro (since, frankly, most of the logic will be in the parsing macro).

In that scenario, variable names are passed and propagated from macros to macros to store whatever result the macro is producing. Has worked fine for me so far for years (minus the usual "underscore all vars in a macro" trick). No such thing with FUNCTION:

FUNCTION(SET_VAR1 varname)
  SET(${varname} "There's science to do" PARENT_SCOPE)
ENDFUNCTION(SET_VAR1)

FUNCTION(SET_VAR2 varname)
  SET_VAR1(${varname})
ENDFUNCTION(SET_VAR2)

SET_VAR2(foo)
MESSAGE("${foo}")

Obviously foo is not set, since it is now set in SET_VAR2 scope. Bummer.
So now I have to do things like this:

FUNCTION(SET_VAR2 varname)
  SET_VAR1(varname_proxy)
  SET(${varname} ${varname_proxy} PARENT_SCOPE)
ENDFUNCTION(SET_VAR2)

Which I guess I could live with, except that it gets *old* as the number of parameters grows, and it kinda goes against my goal of sticking with small "understandable" macros...

But wait, it gets weird. In my macros it's not unusual that I *unset* variables (yes, I do), using SET(var). I was wondering if that would work. It kinda does, but not quite:

FUNCTION(SET_VAR1 varname)
  SET(${varname} "" PARENT_SCOPE)
ENDFUNCTION(SET_VAR1)

FUNCTION(SET_VAR2 varname)
  SET_VAR1(varname_proxy)
  SET(${varname} "${varname_proxy}" PARENT_SCOPE)
ENDFUNCTION(SET_VAR2)

SET_VAR2(foo)
IF(DEFINED foo)
  MESSAGE("foo is defined")
ELSE(DEFINED foo)
  MESSAGE("foo is NOT defined")
ENDIF(DEFINED foo)

This will display that foo is NOT defined, even though it should be defined, if you unroll all the functions into a simple script. Note that replacing SET(${varname} "" PARENT_SCOPE) by SET(${varname} PARENT_SCOPE) will also display that foo is not defined (which was the expected behavior). Also note that removing the quote around ${varname_proxy} doesn't make any difference here.

OK, back to PARENT_SCOPE. Well, Tcl/Tk has 'upvar' (which RAISE_SCOPE was inspired from), *and* 'global', which would pretty much declare variables inside a procedure/function to be of the "global scope" nature. I don't really like any of them. If I had to give a (crazy) suggestion though, before 2.6, is that SET would introspect its parameters a little more, i.e. before expansion. If the variable to be set is a regular variable name (say, SET(bar ..), then it is set at the current scope (i.e. local scope for a function). If it is a *deferenced* variable (i.e. SET(${bar}), then it should be set in the parent scope automatically, *eventually* at the global scope, *ideally* propagated back from parent scope to parent scope to the scope this "pointer to a variable" was first invoked (i.e. where I called SET_VAR2(foo), in my example).

I know about PROPERTIES, but I'm still not convinced, since they don't behave like variables. For a simple thing like working on a filename across scopes, I would have to: a) store the value in a prop, then (later on) b) transfer that prop value to a var, c) do whatever I usually do with a var (i.e. *everything in CMake pretty much*, inluding cleaning a path), d) transfer back the new value to the prop. That's a lot more lines and syntactic detours, which makes my varname_proxy trick in SET_VAR2 almost elegant :)

Thanks

_______________________________________________
CMake mailing list
[email protected]
http://www.cmake.org/mailman/listinfo/cmake

Reply via email to