我正在使用基于 Tcl 的框架来构建包 (MacPorts),并且希望实现类似 atexit 的功能,在构建失败和框架中止的情况下,我可以打印一些信息。
一个简单的 atexit 机制就可以工作,带有一个回调,该回调打印我在构建之前设置的消息,并在所谓的
post-build
块中取消设置(仅在成功的情况下执行)。
除了我的代码在隐藏退出命令的安全解释器中运行,因此我无法重命名/覆盖它。
我想我只是重命名/覆盖
return
函数,改编来自 https://wiki.tcl-lang.org/page/AtExit+handlers 的“MS”代码:
namespace eval AtReturn {
variable atReturnScripts [list]
proc atReturn script {
variable atReturnScripts
lappend atReturnScripts \
[uplevel 1 [list namespace code $script]]
}
namespace export atReturn
}
rename return AtReturn::ReturnOrig
proc return {{arg {}} {code 0} {args {}}} {
variable AtReturn::atReturnScripts
set n [llength $atReturnScripts]
while {$n} {
catch [lindex $atReturnScripts [incr n -1]]
}
# rename return {}
# rename AtReturn::ReturnOrig return
# namespace delete AtReturn
if {${arg} eq "-code"} {
AtReturn::ReturnOrig -code ${code} {*}${args}
} elseif {${arg} ne {}} {
AtReturn::ReturnOrig ${arg}
} else {
AtReturn::ReturnOrig ${code}
}
}
但由于某种原因,这让我陷入了无限递归。 (同上,当我使用原始代码恢复 stock
return
函数,然后调用该函数时)。
我是否忽略了某些事情或尝试了不可能的事情?
像
trace add execution return enter YourCleanupProc
这样的东西怎么样?
有多种方法可以在退出过程时运行某些代码,所有方法都使用
trace
实现。有能力修改程序的结果是不正常的。
trace add execution procName leave
注册一个跟踪,可以查看结果是什么,但在作用域退出后运行。它的结果是在该过程的每个出口上运行(当然,直到显式取消注册)。trace add variable someUnusedLocalVarName unset
注册清理范围时运行的跟踪。它允许您观察特定范围的退出,但需要在该范围的运行期间应用;在程序开始运行之前无法设置。如果你想修改结果,你应该在一些包装命令中运行代码,可能是用
try
或 catch
构建的,这至少有点侵入性。 (不过,可以使用uplevel
来让入侵量看起来更少。)
除了替换 exit
命令(仅真正适用于进程的主解释器)之外,Tcl 不会在解释器退出时暴露任何执行该操作的内容,即使是部分可靠的。原因是,如果解释器已开始被删除,则不再安全地在其中运行命令。 (C 中的退出处理程序通常不应该调用解释器。)如果安全解释器想要提供类似的东西,它需要其受信任的父级来处理它的回调,可能是通过在开始之前调用安全解释器正式删除流程。
覆盖
return
根本不保证有效。过程中成功或错误的退出路径都不一定使用它。