字节编译时发出警告:可能无法在运行时定义函数'whitespace-mode'

时间:2012-01-17 22:28:17

标签: 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-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

当然whitespace-mode在运行时可以是未定义的,但除非成功加载空格,否则永远不应该执行它。如果空白加载,则将定义whitespace-mode

这个警告是emacs编译器限制的结果还是我做错了什么?

3 个答案:

答案 0 :(得分:3)

我在这里添加了上面作为评论的回复,仅供记录。

编译器说的是该函数是在编译时定义的,但是当您运行代码时它可能不存在(它告诉您以前在运行代码时必须要求它)。因此,如果您只需要在该程序包中定义的宏,那么eval-when-compile 可能是一个好习惯。如果您还需要函数和/或变量,则只需require包,而不是eval-when-compile,但始终。{/ p>

答案 1 :(得分:2)

编辑:在这种情况下,代码中没有错误,只是字节编译器不知道函数的定义位置。它不知道whitespace-mode中定义了whitespace.el,因为没有什么可以告诉它的。 (联合国)幸运的是,它并不像你现在那么聪明。 : - )

使用require通常更倾向于使用autoload。然后你可以忘记require的所有内容,因为emacs(和字节编译器)将在第一次调用函数时知道如何加载函数。

(autoload 'whitespace-mode "whitespace" nil t)

如果您知道该函数已经加载,您可以使用declare-function告诉字节编译器在某个文件中定义了一个函数。语法为(declare-function FUNCTION FILE ARGLIST)。对于你的情况,它将是

(declare-function whitespace-mode "whitespace" (&optional ARG))

我通常在使用它们的defun之前将它们放在正确的位置,但这只是出于组织目的。

当然,如果您放置的内容实际上不是真的(文件没有定义函数),这些中的任何一个都可以掩盖错误,但我认为由于whitespace.el可能会被删除或改变和加载会失败。我不认为在大多数情况下这种可能性是值得保护的。

答案 2 :(得分:1)

您可以在代码中添加显式检查:

(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)))

但这可能会在一段时间后变得麻烦。