Sorry to interject--but beware of append_path, set_path, and prepend_path. I
spent some time putting in support for embedded spaces (easy) and trying to
"auto-magically" support differences between "c:\" and "/cygdrive/c" formats
(problematic at best).
Keep in mind that certain paths like CLASSPATH must always be in OS-specific
format--even when spawning the affected application under a *NIX-like shell.
During this port I did some perf testings on
append_path/set_path/prepend_path vs. pure-TCL, fully expecting it to be
much faster than, say:
setenv PATH "$env(PATH):some_new_path"
After all--it's compiled C code.
However, it was not faster. It was measurably slower than using the all-TCL
code listed above. (Sorry, I don't have the numbers anymore, but I could
redo the test if there's interest.)
Instead of using the modules-specific xxx_path extensions, I found it to be
faster to use the above syntax and write a routine that can post-process a
path variable, removing duplicates.
I've attached some scripts that I use for this purpose--I hope they are
useful for you. Once again, I was surprised that they were actually faster
than using the built-ins.
Maybe I'm missing something obvious here, but these work well for me on all
the platforms we use.
proc safepath_create { var } {
global env
if {![info exists env($var)]} {
setenv $var ""
}
}
proc safepath_append { var value } {
global env
safepath_create $var
setenv $var "$env($var):$value"
}
proc safepath_prepend { var value } {
global env
safepath_create $var
setenv $var "$value:$env($var)"
}
proc reducepath { optimized args result } {
# get these from the global namespace
global argv
global env
# assume that the user passes the path to analyze to us
foreach arg [split $args :] {
# if empty, continue
if { ![string compare $arg {}] } { continue }
# normalize the string
set pathName "$arg" ;
# first, replace HOME refs with a tilde
if { $optimized } {
# yuck, this may not work on all shells...
regsub ^$env(HOME)/ $pathName ~/ pathName
} else {
# even though this makes the path passed in longer
# it makes the directory reference resolvable by
# all programs (can you say "ld loader?").
regsub ^~/ $pathName $env(HOME)/ pathName
}
# TCL puts a curly-brace around things...
regsub ^{ $pathName {} pathName
regsub }$ $pathName {} pathName
# now, replace spaces with an underscore
regsub -all { } $pathName _ arName
# in the array?
if { ! [info exists pathsByName($arName)] } {
set pathsByName($arName) $pathName
lappend paths $pathName
}
}
# and join 'em together
if { [info exists paths] } {
set newPath [join "$paths" :]
} else {
set newPath ""
}
upvar $result _result
set _result $newPath
}
-----Original Message-----
From: Leo Butler [mailto:lb...@br...]
Sent: Friday, October 11, 2002 14:42
To: 'Nancy E. Davis'
Cc: mod...@li...
Subject: RE: [Modules] Fwd: question regarding env var manipulation
Nancy E. Davis (ne...@fa...) wrote:
> Leo,
>
> Thanks much! This works well as below:
>
> set flags_add {
> -L/usr/shlib -L/usr/ccs/lib -L/usr/lib/cmplrs/cc -L/usr/lib
> -L/usr/local/lib -L/
> var/shlib
> }
>
> if {([module-info mode load] || [module-info mode switch2]) && [info
exists env(DEC_CC)]} {
> setenv _SAVE_DEC_CC $env(DEC_CC)
> set flags_use [concat $flags_add $env(DEC_CC)]
> setenv DEC_CC $flags_use
> } else {
> set flags_end " | "
> set flags_use [concat $flags_add $flags_end]
> setenv DEC_CC $flags_use
> }
>
> For now, this is enough. Once I learn more tcl, I can think about
> replacing the saved env var. I would also like to figure out
> how to do some sanity checking on the list and avoid replicate
> entries. Some users are coming in with no flags set, others have
> a very specific list that include some or all of the flags I want
> them to be certain to have.
>
> Thanks to all for your help.
Hello, Nancy.
If you can think of a way to make use of "append-path", it would
be easiest to work with in modules. So you'd end up with the usual
colon-delimited list, but perhaps you could process that into a
space-delimited list in your compile process.
We have a setup in our modulefiles that allows us to set a particular
env var if not already set, but when unloading one of the modulefiles
that sets the env var we have some Tcl that prevents the var from being
unsetenv *unless* the modulefile is the last of the bunch that needs it
set. It will then be allowed to unsetenv the var. It's essentially
a "last one out of the house shuts the door" function.
This works very well, but currently requires that each modulefile
know about the others (use of env vars indicating certain modulefiles
have been loaded). Depending upon how many modulefiles would need
to set the same set of libraries in your environment, this might work
for you or could get very messy very fast. If most of the lib paths
are mutually exclusive, it should be okay.
Just some thoughts. Good luck!
- Leo Butler
|