Looking for a cure for weird scope/memory of variables

Gustaf Neumann neumann at wu.ac.at
Tue Jul 9 13:00:27 PDT 2013


Am 09.07.13 19:56, schrieb Clemens Lang:
> On Tue, Jul 09, 2013 at 07:32:03PM +0200, Gustaf Neumann wrote:
>> foreach {foo.version foo.string} ${foo.versions} {
>>      subport foo-${foo.version} [subst {
>>          pre-fetch {
>>              system "echo ${foo.version}"
>>          }
>>          fetch {}
>>          extract {}
>>          use_configure no
>>          build {}
>>          destroot {}
>>      }]
>> }
> I assume there is no sane way to guess what the user wants
that's always hard to guess :)

actually "proc subproc" does already an uplevel, so it
sees the foo.* variables.

The problem is pre-fetch, which seems to be defined with a quite
a bundle of complexity (look at target_provides and makeuserproc),
not sure why. makeuserproc imports already all global variables
so a potential uplevel from the prefetch-body would loose
the access to the global vars.

The code

=====================================================
proc makeuserproc {name body} {
     regsub -- "^\{(.*?)" $body "\{ \n import_globals; \n \\1" body
     eval "proc $name {} $body"
}

makeuserproc foo {{puts "hello world $argv0"}}
=====================================================

could be e.g. replaced by

=====================================================
proc import_globals {} {
   foreach g [info globals] {uplevel 1 [list global $g]}
}

proc makeuserproc {name body} {
     proc $name {} "import_globals;\n$body"
}

makeuserproc foo {puts "hello world $argv0"}
=====================================================

or even by

=====================================================
proc makeuserproc {name body} {
   proc $name {} [list uplevel #0 $body]
}

makeuserproc foo {puts "hello world $argv0"}
=====================================================

The last version has maybe the problem that it does not clean
up potential proc-locals. In all cases, i am not sure
that it is wanted that the body can overwrite the globals.

Now i understand the result of:

> The command "port -v fetch foo-2.0" prints "4.1". How can I fix this?

The constructed program imports at invocation time the values
of the global vars, therefore it gets the last settings.

So, in case all global variables are already set up at definition
time of pre-fetch, one could copy these variables to the
proc scope instead of linking it:

=====================================================
proc copy_globals {} {
   set imports ""
   foreach g [info globals] {
     if {[array exists ::$g]} continue
     append imports "set $g [list [set ::$g]]\n"
   }
   return $imports
}

proc makeuserproc {name body} {
   proc $name {} "[copy_globals];$body"
}
makeuserproc foo {puts "hello world $argv0"}
=====================================================

With that, pre-fetch would see the correct foo.* vars,
and the original code would work. In case, not all
globals are available at proc-definition-time,
it would as well be possible to import some
vars and to copy some vars to the local
scope of the proc, e.g. based on some
pattern (e.g. copy all vars with dots in its names).

-g



More information about the macports-dev mailing list