给macro添加的advice在byte-compile时无效?

我认为用 setf/cl-letf 是更靠谱的做法:

;;; example.el

(eval-and-compile
  (defmacro mcr (&rest body)
    `(list "a" ,@body))

  (defalias 'mcr-orig
    `,(symbol-function 'mcr))

  (defmacro adv (&rest body)
    `(mcr-orig "z" ,@body))

  (setf (symbol-function 'mcr) 'adv))

;;; example-test.el

(require 'cl-lib)

;; 修改之后
(cl-assert (equal '("a" "z" b) (mcr 'b)))
;; 原始效果
(cl-assert (equal '("a" b)     (mcr-orig 'b)))
;; 临时还原
(cl-assert (equal '("a" b)     (cl-letf (((symbol-function 'mcr) 'mcr-orig))
                                 (mcr 'b))))

相关主题:


NOTE: 如果宏在 setf/cl-letf 之前就已于某个函数内使用,并且这个函数已编译,那么宏的行为也不会改变:

;; example.el
(eval-and-compile
  (defmacro mcr (&rest body)
    `(list "a" ,@body))

  (defalias 'mcr-orig
    `,(symbol-function 'mcr))

  (defmacro adv (&rest body)
    `(mcr-orig "z" ,@body))

  (require 'cl-lib)
  (defun call-mcr ()
    (let ((byte-compiled-p (byte-code-function-p (symbol-function 'call-mcr))))
      (message "==> byte-compiled-p: %s" byte-compiled-p)
      (cond
       ;; 已编译,行为不变
       (byte-compiled-p (cl-assert (equal '("a" b)     (mcr 'b))))
       ;; 未编译,行为改变
       (t               (cl-assert (equal '("a" "z" b) (mcr 'b)))))))

  (setf (symbol-function 'mcr) 'adv))
$ emacs -Q --batch -l /tmp/example.el -f call-mcr
==> byte-compiled-p: nil

$ emacs -Q --batch -l /tmp/example.elc -f call-mcr
==> byte-compiled-p: t