根据不同的条件,将不同的代码片段写入已编译的(.elc)文件中

时间:2016-02-14 13:15:43

标签: emacs lisp elisp

我想有条件地将不同的代码片段写入我的elisp文件(.elc)的编译版本,我可以使用函数定义来执行此操作:

(defalias 'my-test
  (eval-when-compile
    (if nil 
      (lambda ()
        (message "True"))
      (lambda ()
        (message "False")))))

使用上面的代码,我可以根据不同的条件为my-test分配不同的匿名函数,结果将写入编译的.elc文件。但我想写的是文件范围中的函数调用。像这样:

(eval-when-compile
  (if nil
      (add-to-list 'auto-mode-alist '("\\.gitconfig\\'" . A-mode))
    (add-to-list 'auto-mode-alist '("\\.gitconfig\\'" . B-mode))))

;; or using `when' to either write a call or do nothing:
(eval-when-compile
  (when (not (eq (user-uid) 0))           ; if uid != 0
    (dangerous-call)))

代码在编译时进行评估,评估结果只能在编译过程中使用,之后没有任何内容转到.elc,因为我没有将它分配给任何东西,但我怎么能实际将if控件的字节编译结果(对于add-to-list函数是调用)编写到已编译的.elc文件中?在这种情况下,我希望(add-to-list 'auto-mode-alist '("\\.gitconfig\\'" . B-mode))写入.elc文件。

2 个答案:

答案 0 :(得分:1)

我认为对此的答案是宏:如果你编写一个扩展为你想要的代码的宏,那么只需将宏调用放在顶层,那么宏的扩展将在编译时结束文件。

所以:

(defmacro foo ()
  (if <compile-time-condition>
      `(setq ...)
      `(setq ...)))

(foo)

警告:您只能在编译时对您知道的事情进行条件化:您在UID上调度的示例可能无法达到预期效果。

答案 1 :(得分:1)

tfb的答案通常是更好的选择,但对于一次性案例,您可能更愿意这样做

(if (eval-when-compile (my-test))
    (add-to-list 'auto-mode-alist '("\\.gitconfig\\'" . A-mode))
  (add-to-list 'auto-mode-alist '("\\.gitconfig\\'" . B-mode)))

甚至可以改写为

(add-to-list 'auto-mode-alist 
             `("\\.gitconfig\\'"
             . ,(if (eval-when-compile (my-test)) 'A-mode 'B-mode)))

这取决于编译器优化,根据常量将(if <constant> a b)变为ab