如何在SBCL中显示错误的行号和源文件



我的~/.sbclrc看起来像这样:

(sb-ext:restrict-compiler-policy 'debug 3)
(setf *debugger-hook* #'(lambda (condition original-hook)
(declare (ignore original-hook))
(print-backtrace)
(format *error-output* "~%~A~%" condition)
(finish-output *error-output*)
(abort)))

假设我有一个程序my-program.lisp,其中包含一个坏函数:

;; ...
(defun calculate (x)
(/ x 0))
;; ...

如果我运行:

$ sbcl --load my-program.lisp
* (calculate 100)

我得到这个错误:

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10005E85B3}>
0: (SB-KERNEL::INTEGER-/-INTEGER 100 0)
1: (CALCULATE 100)
2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (CALCULATE 100) #<NULL-LEXENV>)
3: (EVAL (CALCULATE 100))
4: (INTERACTIVE-EVAL (CALCULATE 100) :EVAL NIL)
5: (SB-IMPL::REPL-FUN NIL)
6: ((LAMBDA NIL :IN SB-IMPL::TOPLEVEL-REPL))
7: (SB-IMPL::%WITH-REBOUND-IO-SYNTAX #<CLOSURE (LAMBDA NIL :IN SB-IMPL::TOPLEVEL-REPL) {10046268FB}>)
8: (SB-IMPL::TOPLEVEL-REPL NIL)
9: (SB-IMPL::TOPLEVEL-INIT)
10: ((FLET SB-UNIX::BODY :IN SAVE-LISP-AND-DIE))
11: ((FLET "WITHOUT-INTERRUPTS-BODY-36" :IN SAVE-LISP-AND-DIE))
12: ((LABELS SB-IMPL::RESTART-LISP :IN SAVE-LISP-AND-DIE))
arithmetic error DIVISION-BY-ZERO signalled
Operation was (/ 100 0).

但是,运行时错误的行号和源文件在哪里?想象一下,如果我有数百个文件和数千个函数。知道错误的文件、行号和列号不是很有帮助吗?如何显示错误的行号和源文件?

我感到惊讶的是,当几乎所有其他解释器和编译器都能轻松做到这一点时,这种编程语言默认情况下没有这一功能。

我通常将SLIME+GNU Emacs与SBCL一起使用。

然后,我编译/加载一个调试级别为3的文件。

然后,我可以在帧的回溯窗口中按下v,编辑器跳到源代码。

从Slime(或Sly(工作提供了开箱即用的功能,但实际上这是可能的,因为底层环境已经存储了足够的信息。如果您查看代码是如何实现的(通过在Emacs中使用M-.导航,您可以看到在SBCL中,源代码的位置部分取决于sb-introspect

在您的示例中,加载包含calculate的文件后,如果您require此模块,如下所示:

* (require 'sb-introspect)
("SB-INTROSPECT")

您可以通过调用find-definition-source:找到所有相关信息

* (sb-introspect:find-definition-source #'calculate)
#S(SB-INTROSPECT:DEFINITION-SOURCE
:PATHNAME #P"/tmp/mp.lisp"
:FORM-PATH (2)
:FORM-NUMBER 0
:CHARACTER-OFFSET 51
:FILE-WRITE-DATE 3817139822
:PLIST NIL
:DESCRIPTION NIL)

除了文件外,SBCL还将位置存储为字符偏移量,以及该文件中的表单数量(因此,如果在其前面添加空白或注释,即使在修改文件后,编辑器仍然可以找到它的位置(。

回溯打印机功能还可以选择包含更多或更少的信息。

最新更新