该脚本已经提供了N个文件..,
source file 1
source file 2
.
.
source file N
当特定程序A调用。时,它实际存在于大多数源文件中。无论如何,包含该proc A的最后一个源文件将执行该函数。 当我调用proc时,如何找到包含proc的文件? 我可以使用任何代码来实现它吗?
答案 0 :(得分:1)
最简单的方法(假设Tcl 8.5或8.6)是使用执行跟踪调用info frame
来获取调用堆栈的详细信息。
trace add execution A enter callingA
proc callingA args {
set ctxt [info frame -1]
if {[dict exists $ctxt file] && [dict exists $ctxt proc]} {
puts "Called [lindex $args 0 0] from [dict get $ctxt proc] in [dict get $ctxt file]"
} elseif {[dict exists $ctxt proc]} {
puts "Called [lindex $args 0 0] from [dict get $ctxt proc] (unknown location)"
} else {
# Fallback
puts "Called [lindex $args 0 0] from within [file normalize [info script]]"
}
}
info frame
返回的词典中还有很多其他信息。
在Tcl 8.4中,您没有info frame
,Tcl也不记得默认情况下定义了哪些程序。你仍然有执行痕迹(它们是Tcl 8.4的新功能),这样就可以了。 (对于info script
,我们必须要小心谨慎,因为 source
期间只有{em>有效,而不是在完成之后;过程往往会在稍后调用。)
要获得定义每个过程的位置,您必须拦截proc
本身,并在脚本执行的早期执行此操作! (在设置拦截器之前定义的过程没有被注意到; Tcl的语义纯粹是可操作的。)幸运的是,你可以使用执行跟踪。
proc procCalled {cmd code args} {
if {$code==0} {
global procInFile
set procName [uplevel 1 [list namespace which [lindex $cmd 1]]]
set procInFile($procName) [file normalize [info script]]
}
}
# We use a leave trace for maximum correctness
trace add execution proc leave procCalled
然后,在您想知道调用者的命令上使用另一个执行跟踪,以查找该命令的调用内容,从而查找定义的位置。
proc callingA args {
# Wrap in a catch so a lookup failure doesn't cause problems
if {[catch {
set caller [lindex [info level -1] 0]
global procInFile
set file $procInFile($caller)
puts "Calling [lindex $args 0 0] from $caller in $file"
}]} {
# Not called from procedure!
puts "Calling [lindex $args 0 0] from within [file normalize [info script]]"
}
}
trace add execution A enter callingA