Emacs 字节编译时警告:函数';空白模式';可能未在运行时定义
如果我将以下内容放入Emacs 字节编译时警告:函数';空白模式';可能未在运行时定义,emacs,elisp,Emacs,Elisp,如果我将以下内容放入foo.el: (defun whitespace-redraw () (eval-when-compile (require 'whitespace nil t)) (when (require 'whitespace nil t) (if whitespace-mode (whitespace-mode 0)) (whitespace-mode 1))) 然后编译它: emacs -Q --batch --eval '(byte-
foo.el
:
(defun whitespace-redraw ()
(eval-when-compile (require 'whitespace nil t))
(when (require 'whitespace nil t)
(if whitespace-mode
(whitespace-mode 0))
(whitespace-mode 1)))
然后编译它:
emacs -Q --batch --eval '(byte-compile-file "foo.el")'
我得到以下警告:
In end of data:
foo.el:7:1:Warning: the function `whitespace-mode' might not be defined at
runtime.
Wrote foo.elc
当然,可以在运行时取消定义空白模式
,但除非成功加载空白,否则不应执行该模式。如果加载空白,则将定义空白模式
此警告是emacs编译器限制的结果还是我做错了什么?您可以在代码中添加显式检查:
(defun whitespace-redraw ()
(eval-when-compile (require 'whitespace nil t))
(when (and (require 'whitespace nil t)
(fboundp 'whitespace-mode))
(if whitespace-mode
(whitespace-mode 0))
(whitespace-mode 1)))
但过一段时间后,这可能会变得很麻烦。编辑:在这种情况下,代码中没有错误,只是字节编译器不知道函数的定义位置。它不知道
空白模式
是在whitespace.el
中定义的,因为没有什么可以告诉它。(联合国)幸运的是,它还没有你聪明。:-)
与其使用require
,不如使用autoload
。然后您可以忘记所有关于require
ing的内容,因为emacs(和字节编译器)将知道如何在首次调用函数时加载它
(autoload 'whitespace-mode "whitespace" nil t)
如果您知道函数将被加载,可以使用declare function
告诉字节编译器某个函数是在某个文件中定义的。语法是(声明函数文件ARGLIST)
。就你的情况来说
(declare-function whitespace-mode "whitespace" (&optional ARG))
我通常把这些放在使用它们的defun之前,但这只是为了组织目的
当然,如果您输入的内容实际上不是真的(文件没有定义函数),那么这两种方法都可以掩盖一个bug,但我认为没有办法解决这个问题,因为
whitespace.el
可能会被删除或更改,并且加载会失败。不过,我认为在大多数情况下,不值得防范这种可能性。我在这里添加了我在上面作为评论的回应,只是为了记录在案
编译器说的是,函数是在编译时定义的,但在运行代码时它可能不存在(它告诉您在运行代码之前必须使用它)。因此,只有当您只需要在该包中定义宏时,才可以在编译时
求值。如果您还需要函数和/或变量,您应该只需要
包,而不是在编译时在eval下
,而是始终如此。我经常想知道这一点。虽然从未遇到过任何问题,但无知有时是一种幸福。只是一个更新:从Emacs24.4开始,我没有看到这段代码上的警告;我认为编译器现在更聪明了。我已经在我的实际代码中这样做了,但我想了解发生了什么。我担心添加显式检查可能会隐藏我的代码的实际问题。如果在运行时没有定义函数,您可能确实会遇到问题。警告就是这么说的。它的发布是因为编译器在编译时不知道函数“whitespacemode”,所以他只是向您指出,您最好确保它存在。如果按如下方式进行字节编译:emacs-Q--batch--eval“(需要'whitespace nil t)(字节编译文件\'foo.el\”)
,那么编译器在编译时知道函数,不会发出警告。Thomas,我还是不明白。如果你明确地说(编译时求值(需要“空白”)
,为什么编译器在编译时不知道空白模式?好的,我想我现在明白了。编译器说的是,函数是在编译时定义的,但在运行代码时它可能不存在(它告诉您在运行代码之前必须使用它)。因此,只有当您只需要在该包中定义宏时,才可以在编译时求值。如果您还需要函数和/或变量,则只需require
程序包,而不是在编译时eval下,而是始终。但在运行时它是require
d;请注意操作中的(当(需要'whitespace nil t)…
时)。在调用该函数时,该函数应始终可用,因为Emacs能够成功加载空白
功能。因此,要么我有一个非常微妙的bug,要么编译器无法理解如果要调用该函数,该函数将保证可用。我想知道哪个。是的,它在运行时是必需的,这就是为什么我告诉你只要require
(编译时不带eval
),当你需要该函数在编译时和运行时都可用时。还要考虑到时的是一个宏,因此它可能不会计算其参数,因此编译器实际上无法知道将要生成的require。我希望它在编译时可用,以使警告静音,但在运行时是可选的(因此时的和nil t
)。如果我总是需要空白
,那么在安装时如果没有空白
,它就会中断。你关于何时
成为宏的观点很有趣。但是,当我执行(当(fboundp'空白模式)
时,编译器不会打印警告,因此编译器必须了解何时执行。对吧?我想这只是因为当
是一个宏时。然后编译器无法猜测何时对其求值(如果有)。这会使警告静音,但不会回答我的问题。我担心代码中有一个bug。如果有bug,使用declare函数将屏蔽它。如果没有bug,那么编译器为什么要打印警告?哦,对不起,我误解了。代码中没有bug,这是字节编译器的一个限制。它无法知道require
ingwhitespace
将定义函数空白模式