Por que o `eval-when-compile` é executado no carregamento do arquivo e compilado em bytes para .elc?

9

Idioma comum para solucionar a expansão de macro ou resolver o aviso sobre variáveis ​​indefinidas durante a compilação de bytes:

(eval-when-compile
  (require 'cl-lib))

Mas isso require ...compilado em .elcarquivo! Eu achei que cl-eval-whentem semântica adequada (de acordo com o nome).

Normalmente não precisamos requirecomo arquivo do site epackage.el

Por exemplo, eu quero compilar em bytes o meu, .emacsque usa algumas macros externas, mas passa silenciosamente se não houver esse pacote:

(cl-eval-when 'compile
  (condition-case err
      (require 'w3m-util)
    (error (byte-compile-warn "Failed by: %S" err))))
(w3m-util-DEPENDENT-CODE ...)

Outra maneira de fazer isso é:

(ignore-error
   (require 'w3m-util)
   (w3m-util-DEPENDENT-CODE ...))

Mas agora não somos um formulário de nível superior ...

Devo preencher adequadamente esse eval-when-compilenome e fazer algo que não é esperado dele?

gavenkoa
fonte
FWIW, os dois últimos trechos não têm o mesmo comportamento. O primeiro não protege w3m-DEPENDENT-CODEde uma falta w3m-util.
Tirou
(when (require 'w3m-util nil t) (w3m-util-DEPENDENT-CODE...))
Tirou
(when (require 'w3m-util nil t) ...)é um bom idioma! Mas tento criar um .emacsarquivo perfeito , não uma biblioteca. Portanto, lembre-se do atraso no carregamento do código (mediante solicitação) com a ajuda do carregamento automático. Por esse motivo que uso extensivamente eval-after-load, o solicitado requireprecisa apenas obter êxito na compilação de bytes com a expansão de macros.
gavenkoa

Respostas:

9

Você perguntou ao Emacs o que eval-when-compiledeveria fazer?

C-h f eval-when-compile informa que ele avalia o argumento também no tempo de carregamento:

eval-when-compile is a Lisp macro in `byte-run.el'.

(eval-when-compile &rest BODY)

Like ‘progn’, but evaluates the body at compile time if you’re compiling.
Thus, the result of the body appears to the compiler as a quoted
constant.  In interpreted code, this is entirely equivalent to
‘progn’, except that the value of the expression may be (but is
not necessarily) computed at load time if eager macro expansion
is enabled.

Diz que se interpretado é como progn. E isso repete explicitamente isso.

Um nome de função ou macro raramente reflete o comportamento perfeitamente. Mas, neste caso, parece que você está procurando um comportamento diferente, que pode ser chamado eval-only-when-compile.

Desenhou
fonte
1
eval-only-when-compilename me ajude a entender point to name eval-when-compile, obrigado!
gavenkoa
3

Para avaliar o código apenas no estágio de compilação, use eval-whenmacros datadas pelo RMS em 1993-07-30.

cl-eval-when apareceu em 2012-06-03 de Stefan Monnier e não está disponível para o Emacs 22.x (se você se importa, eu sim).

Por exemplo, você gosta de se livrar de Warning: assignment to free variable:

(setq auto-revert-interval 2)

basta adicionar acima dessa linha:

(eval-when 'compile (require 'autorevert))

Observe que isso é útil apenas para compilação de bytes do .emacsarquivo. Se você desenvolver uma biblioteca, faça requireou divida o arquivo da biblioteca em separado e carregue apenas os recursos necessários.

gavenkoa
fonte
Para evitar avisos variáveis, você só precisa(defvar auto-revert-interval)
npostavs
1
Eu uso defvarsolução em muitos casos, mas também procuro uma solução mais forte . Posso digitar o nome errado ou o pacote pode remover a definição e o verificador de compilação ficaria em silêncio nesses casos.
precisa saber é o seguinte