Reputation: 16125
In one executable TCL script I'm defining a variable that I'd like to import in another executable TCL script. In Python one can make a combined library and executable by using the following idiom at the bottom of one's script:
# Library
if __name__ == "__main__":
# Executable that depends on library
pass
Is there something equivalent for TCL? There is for Perl.
Edit: The answer given by Donal Fellows is entirely sufficient, but for completion the comments below are gathered into one final answer here:
if {[info exists ::argv0] && $::argv0 eq [file normalize [info script]]} {
# Do the things for if the script is run as a program...
}
Upvotes: 5
Views: 794
Reputation: 77
I recently wanted this functionality to set up some unit tests for my HDL build scripts suite. This is what i ended up with for Vivado:
proc is_main_script {} { ;# +1 frame
set frame [info frame [expr [info frame] -3]]
if {![dict exists $frame file]} {
set command [file normalize [lindex [dict get $frame cmd] 1]]
set script [file normalize [info script]]
if {$script eq $command} {
return 1
} else {
return 0
}
} else {
return 0
}
}
if {is_main_script} { ;# +1 frame
puts "do your thing"
}
As I consider this for test/demo i consider the main use case to be something in the line with if {is_main_script} {puts "do something"}
"un nested" at the end of the file.
If a need to make it more general a dynamic handle for the frame
reference -3
could probably be developed. All though this has covered all my use cases so far.
frame
-3
is used as proc
and if
creates extra frames and to evaluate this we want to check the call before.
dict exists
is used to check if file
exists within the frame. This would indicate the call was from a higher hierarchical level script and would there for not be the "main_script"
The solution if {[info exists ::argv0] && $::argv0 eq [info script]}
works great if run as vivado -source TCLSCRIPT.tcl
but the solution above covers source TCLSCRIPT.tcl
in gui or tcl mode (this is something i often se my self doing when debugging a automation tcl).
I guess this is a niche case. But since I couldn't find any other solution for this problem I wanted to leave this here.
Upvotes: 1
Reputation: 137667
The equivalent for Tcl is to compare the ::argv0
global variable to the result of the info script
command.
if {$::argv0 eq [info script]} {
# Do the things for if the script is run as a program...
}
The ::argv0
global (technically a feature of the standard tclsh
and wish
shells, or anything else that calls Tcl_Main
or Tk_Main
at the C level) has the name of the main script, or is the empty string if there is no main script. The info script
command returns the name of the file currently being evaluated, whether that's by source
or because of the main shell is running it as a script. They'll be the same thing when the current script is the main script.
As mrcalvin notes in the comments below, if your library script is sometimes used in contexts where argv0
is not set (custom shells, child interpreters, embedded interpreters, some application servers, etc.) then you should add a bit more of a check first:
if {[info exists ::argv0] && $::argv0 eq [info script]} {
# Do the things for if the script is run as a program...
}
Upvotes: 8