以下是设置:
(defun square (x)
(* x x))
;; square
(symbol-function 'square)
;; (lambda (x) (* x x))
(byte-compile 'square)
;; #[(x) "\211_\207" [x] 2]
(symbol-function 'square)
;; #[(x) "\211_\207" [x] 2]
在(lambda (x) (* x x))
进行字节编译后,有没有办法获取源square
?
我能想到的两个用途是内联当前的函数调用 并进行调试步骤。
我已经尝试弄乱find-definition-noselect
来获取源代码,
但我想知道是否有更好的方法,因为它有时会提高
(error "Don't know where ... is defined")
答案 0 :(得分:2)
Emacs会跟踪哪个名称定义在哪个文件中(此信息保存在load-history
中)。为了找到定义,Emacs查找load-history
,如果函数列在那里,它会查找相应的源文件,然后在该文件中查找看起来像函数的可能定义的东西(使用regexps)。这就是find-definition-noselect
所做的。
对于源代码,通常没有Emacs不保留源定义。如果使用cl-defsubst
定义函数,则源保持不变,但不是。对于Edebugging来说,源头无论如何都无济于事(因为Edebug不仅需要源码鳕鱼,还需要每个子表达式的精确位置);对于普通调试,也不需要源代码(你可以随时点击函数的名称跳转到源代码);也不需要内联源代码(字节编译器可以在源代码级别内联,实际上,它也可以在字节码级别内联)。
答案 1 :(得分:0)
无法获取函数对象的来源。字节编译不是内射函数,因此无法将其还原。即使忽略宏扩展,也没有从操作码到Lisp表达式的直接映射。
无论如何,我没有看到这个用例。
要进入调试功能,请导航到其定义(即find-definition
)并检测定义以进行调试(例如使用edebug)。这是合理调试Emacs Lisp函数的唯一方法。您不能使用函数单元格的内容进行调试,因为它受宏扩展的影响。
因此,功能单元看起来可能与实际定义完全不同。如果在函数单元格中发现错误,则很难在实际函数定义中找到相同的错误。
对于内联,使用宏或defsubst
在Emacs Lisp中定义内联函数。但是,请注意不要在库的公共接口上意外暴露这些,因为编译时内联函数会将编译时依赖性强加到库中,因此需要为库的每个版本重新编译依赖库。而且由于package.el尚不支持,宏和替换很容易造成破坏。