AutoRecompile

General Tips

Auto-Compile Package

auto-compile provides two minor modes auto-compile-global-mode and auto-compile-on-load-mode which keep byte code files up-to-date with their Emacs Lisp source files.

auto-compile-global-mode automatically compiles Emacs Lisp code when the visiting buffers are saved to their source files, provided that the respective byte code files already exists. If the byte code file does not already exist nothing is done.

Even when using auto-compile-global-mode it can sometimes happen that the source file is newer than the byte compile destination. This can for example happen when performing version control operations. To ensure that byte code files are always up-to-date when being loaded using require and load enable auto-compile-on-load-mode which advises these functions to recompile the source files when needed.

An earlier version of this package tried to incorporate all ideas from the other packages and snippets mentioned on this page, and then some. It turned out that all those features are not actually needed. So now there are (no longer) any options to control what files are compiled (instead a .el is compiled when a .elc files already exists otherwise it is not), no cache (this seems fragile and also quite useless) and compilation does not happen asynchronously (speed never was a problem for me and I want authors to be bothered by warnings, so that they actually fix them). – JonasBernoulli

Byte Compile on Buffer Save

AutoAsyncByteCompile compiles elisp files when you save them. It works asynchronously, so you do not have to wait for compilation finish. – rubikitch

auto-recomp.el is the simplest solution to the problem at hand. It compiles every .el file when it is saved, no questions asked. It used to be available here but now you have to get it from the web archive .

Byte Code Cache

These packages store .elc files in a cache and load them from there.

elisp-cache advices functions that load libraries to that they look in a special directory containing .elc files. It does not appear to byte compile if the .elc file is missing instead “Freshness of the cache is only checked every once in a while”.

byte-code-cache.el attempts to automatically compile .el files as they are loaded. This no longer work in recent versions of Emacs (22, 23, 24) because it uses load-source-file-function to prevent an .elc file from being loaded. Unfortunately this special hook isn’t run when loading an .elc file (just as the name suggests).

Dirty Little Snippets

I strongly recommend you stop reading here! I don’t claim that my auto-compile.el is perfect, but some of the following snippets are just to ugly and broken. – JonasBernoulli

on save

Here is my slightly modified version of the byte compile on buffer save solution. Compared to the one in auto-recomp.el this one tries to be less distracting by pre-splitting the window with a smaller *Compile-Log* buffer, auto-scroll to the last line to quickly show a potential error and then auto-close the *Compile-Log* window. It would be better to have a real error detection with a notification message rather than a dumb auto-scroll. Next time perhaps. – PierreJeanTurpeau?

(defun pj/auto-recompile-file-always ()
  (when (equal mode-name "Emacs-Lisp")
    (let ((maximum-compile-log-height 8)
          (old-window-start (window-start))
          (old-window-point (window-point)))
      ;; pre-split for compile log buffer so that it does not modify the layout
      (set-window-buffer (split-window-vertically (- (window-height) maximum-compile-log-height)) (get-buffer-create "*Compile-Log*"))
      ;; byte compile the buffer
      (byte-compile-file buffer-file-name)
      (let ((buf (get-buffer "*Compile-Log*")))
        ;; scroll to the end to see if there's an error
        (set-window-point (get-buffer-window buf) (buffer-size buf))
        ;; auto close the compile log window and restore original display position
        (run-at-time 1.0 nil (lambda (buf)
                               (delete-windows-on buf)
                               (set-window-point (selected-window) old-window-point)
                               (set-window-start (selected-window) old-window-start))
                     buf)))))

on kill

And here’s the way I do it… I only want to compile when I kill a buffer, not when I save it (which I do obsessively). – ScottEvans

(defun gse-prompt-to-compile-init-file ()
  (interactive)
  (if (and
       (string-equal buffer-file-name (expand-file-name "~/.xemacs/init.el"))
       (file-newer-than-file-p "~/.xemacs/init.el" "~/.xemacs/init.elc")
       (y-or-n-p "byte-compile init.el? "))
      (byte-compile-file "~/.xemacs/init.el")))

(add-hook 'kill-buffer-hook 'gse-prompt-to-compile-init-file)

I like the idea of compile the file when kill the buffer. So I write a more general way to recompile .el file.

(defvar auto-recompile nil)
(put 'auto-recompile 'safe-local-variable 'booleanp)
(defvar auto-recompile-query t
  "if non-nil, ask user before byte compile.")
(defun auto-recompile-file-maybe ()
  (interactive)
  (when (and buffer-file-name (string-match "\\.el\\(\\.gz\\)?\\'" buffer-file-name))
    (let ((byte-file (concat buffer-file-name "c")))
      (if (and
           (file-exists-p byte-file)
           (file-newer-than-file-p buffer-file-name byte-file)
           (or auto-recompile
               (null auto-recompile-query)
               (called-interactively-p)
               (y-or-n-p (format "byte-compile %s" buffer-file-name))))
          (byte-compile-file buffer-file-name)))))
(defun auto-recompile-save-hook ()
  (add-hook 'kill-buffer-hook 'auto-recompile-file-maybe nil t))

(add-hook 'emacs-lisp-mode-hook 'auto-recompile-save-hook)

dotemacs

How many ways to skin this cat? Still I tend to edit my dotemacs in a vc repo which is linked to, hence:

;; Auto-compile my .emacs
;
; Given that I tend to edit in my vc-repo (to which .emacs links) we
; straight awaywant to resolve where ~/.emacs resolves to first

(defun autocompile nil
  "compile itself if ~/.emacs"
  (interactive)
  (require 'bytecomp)
  (let ((dotemacs (expand-file-name "~/.emacs")))
    (if (string= (buffer-file-name) (file-chase-links dotemacs))
      (byte-compile-file dotemacs))))

(add-hook 'after-save-hook 'autocompile)

I use this code at the end of my .emacs to automatically compile my .emacs if the file .emacs.elc exists and if it’s older than the .emacs. Of course this is only useful if you regularly start emacs.

;; I always compile my .emacs, saves me about two seconds
;; startuptime. But that only helps if the .emacs.elc is newer
;; than the .emacs. So compile .emacs if it's not.
(when (and user-init-file
	   (equal (file-name-extension user-init-file) "elc"))
  (let* ((source (file-name-sans-extension user-init-file))
	 (alt (concat source ".el")))
    (setq source (cond ((file-exists-p alt) alt)
		       ((file-exists-p source) source)
		       (t nil)))
    (when source
      (when (file-newer-than-file-p source user-init-file)
	(byte-compile-file source)
	(load-file source)
	(eval-buffer nil nil)
        (delete-other-windows) ))))

The only possible problem is that removed functions are not removed until the next start of emacs.


An Emacs init file can get big, very big. When it gets large or has a lot of function definitions, you should consider compiling it: it will load faster when Emacs starts, and its functions will execute faster.

But keeping the compiled .emacs.elc file up-to-date with the .emacs source file can be a hassle. So here is a way to automate that, by compiling your InitFile each time you save it:

    (defun byte-compile-user-init-file ()
      (let ((byte-compile-warnings '(unresolved)))
        ;; in case compilation fails, don't leave the old .elc around:
        (when (file-exists-p (concat user-init-file ".elc"))
          (delete-file (concat user-init-file ".elc")))
        (byte-compile-file user-init-file)
        ;; (message "%s compiled" user-init-file)
        ))
    (defun my-emacs-lisp-mode-hook ()
      (when (equal buffer-file-name user-init-file)
        (add-hook 'after-save-hook 'byte-compile-user-init-file t t)))
    ;; (add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
    (add-hook 'emacs-lisp-mode-hook 'my-emacs-lisp-mode-hook)

Of course, this is not the only way. You could instead compile it each time you quit Emacs (see ‘kill-emacs-hook’), or when you close the .emacs buffer (see ‘kill-buffer-hook’), or when you start Emacs and the .emacs source file is more recent than the compiled .emacs.elc file, and so on. For more information, see AutoRecompile.


The following version doesn’t require the byte compiled version of the file to exist. However, it clutters up ‘after-save-hook for all buffers, irrespective of the name/type of the file. You can look at the earlier section for an example of how to add the hook to a buffer-local ‘after-save-hook. If your user-init-file is named .emacs.el, replace (concat user-init-file ".elc") with (concat user-init-file "c").

 (defun byte-compile-init-file ()
   (when (equal user-init-file buffer-file-name)
     (when (file-exists-p (concat user-init-file ".elc"))
       (delete-file (concat user-init-file ".elc")))
     (byte-compile-file user-init-file)))
 (add-hook 'after-save-hook 'byte-compile-init-file)

I use following function, when visit file, remove <filename>.elc, after save, create <filename>.elc – coldnew

(defun remove-elc-when-visit ()
  "When visit, remove <filename>.elc"
  (make-local-variable 'find-file-hook)
  (add-hook 'find-file-hook
            (lambda ()
              (if (file-exists-p (concat buffer-file-name "c"))
                  (delete-file (concat buffer-file-name "c"))))))
(add-hook 'emacs-lisp-mode-hook 'remove-elc-when-visit)

(defun byte-compile-when-save()
  "When save, recompile it"
  (make-local-variable 'after-save-hook)
  (add-hook 'after-save-hook
	    (lambda ()
	      (if (buffer-file-name)
	      (byte-compile-file buffer-file-name)))))
(add-hook 'emacs-lisp-mode-hook 'byte-compile-when-save)


I use the following, rather massive piece of code to automatically compile my .emacs and .gnus files.

 (require 'bytecomp)
 (defvar auto-byte-compile-files-list
   (let ((ghd (or (and (boundp 'gnus-home-directory) gnus-home-directory)
                  (expand-file-name "~"))))
     (cond
      ((string-match "\\.elc$" user-init-file)
       (list (substring user-init-file 0 -4)
             (substring user-init-file 0 -1)
             (concat ghd "/.gnus")
             (concat ghd "/.gnus.el")))
      (t
       (list user-init-file
             (concat ghd "/.gnus")
             (concat ghd "/.gnus.el")))))
   "List of files to auto compile")
 (defun auto-byte-compile-file (&optional file match regexp)
   "file can be
 - nil in which case value returned by `buffer-file-name' will be used
   unless it returns nil in which case no action will be taken;
 - a string which is equivalent to passing list with that string as the
   only element;
 - a list of strings representing file names; or
 - anything else which is equivalent to passing
   `auto-byte-compile-files-list'.
 Entries equal to \".\", \"..\" or ending with \"/.\" or \"/..\"
 are ignored.  If element is a directory it will be processed
 recursively but if regexp is nil only files ending with \".el\"
 will be processed.
 match can be
 - nil which is equivalent to passing `auto-byte-compile-files-list';
 - a string which is equivalent to passing list with that string as the
   only element;
 - a list in which case file have to be in that list to be processed; or
 - anything else in which case file will be processed regardless of name.
 If any element of match is a string ending with a slash ('/') it
 is treated as directory name (no checking is done if it is really
 a directory or even if it exists) and file is said to match such
 entry if it begins with it thus all files in given directory will
 match.
 If called interacivelly without prefix arg will behave as with
 match equal t.  With prefix arg will behave as with match equal
 nil.
 regexp must be nil which is equivalent with passing a list
 containing only empty string or a list of regular expressions
 which file have to match to be processed.
 So the default is to auto-compile the current file iff it exists
 in `auto-byte-compile-files-list'.
 Non-string elements in list will be ignored.
 Auto-compilation means that file will be byte-compiled iff the
 compiled version does not exits or is older then the file
 itself."
   (interactive (list (read-file-name "Auto byte compile file:" nil nil t)
                      (not current-prefix-arg)))
   (if (not (or file (setq file (buffer-file-name))))
       0
     (setq file  (cond ((stringp file)  (list file))
                       ((listp   file)  file)
                       (t               auto-byte-compile-files-list))
           match (mapcar (function (lambda (i) (expand-file-name i)))
                         (cond ((not match)     auto-byte-compile-files-list)
                               ((stringp match) (list match))
                               ((listp match)   match)
                               (t               nil))))
     (let (f (n 0))
       (while (setq f (car file))
         (setq file (cdr file) f (expand-file-name f))
         (cond
          ((string-match f "\\(^\\|/\\)\\.\\.?$"))
          ((file-directory-p f)
           (if regexp
               (setq file (append (directory-files f t nil t) file))
             (setq n (+ n (auto-byte-compile-file (directory-files f t nil t)
                                                  (or match t) '("\\.el$"))))))
          ((and (file-newer-than-file-p f (byte-compile-dest-file f))
                (or (not match)
                    (catch 'found
                      (dolist (m match)
                        (if (string= m (if (string-match "/$" m)
                                           (substring f 0 (length m)) f))
                            (throw 'found t)))))
                (or (not regexp)
                    (catch 'found (dolist (r regexp)
                                    (if (string-match r f) (throw 'found t)))))
                (byte-compile-file f)
                (setq n (1+ n))))))
       n)))
 (defun auto-byte-compile-buffer (&optional match buffer)
   "Auto compiles file in given buffer (if buffer is nil current
 buffer is used) providing that major mode of the buffer is
 lisp-mode or emacs-lisp-mode.  match has the same meaning as in
 `auto-byte-compile-file'.
 If called interacivelly will behave as with match equal t and
 buffer equal nil unless prefix argument was given in which case
 match will equal nil."
   (interactive (list (not current-prefix-arg) nil))
   (and (buffer-file-name buffer)
        (memq (if buffer (save-current-buffer (set-buffer buffer)
                                              major-mode) major-mode)
                '(lisp-mode emacs-lisp-mode))
        (auto-byte-compile-file (buffer-file-name buffer) match)))
 (add-hook 'kill-buffer-hook 'auto-byte-compile-buffer)
 (add-hook 'kill-emacs-hook (function (lambda () (auto-byte-compile-file t))))

When buffer (or emacs) is killed, it byte compiles file if it’s on the auto-byte-compile-files-list. By altering that list it can be configured to auto byte compile all files in given directory like directery with user’s own elisp files. – mina86

dotgnus

You can also do something like this:

;;* GnusWait! Try to speed up Gnus by using a .Gnus.elc/.gnus
;;* ================================
(defun GnusWait! ()
  "If ~/.Gnus.el exists and is newer than ~/.gnus, recompile it to
  ~/.Gnus.elc and move the compiled version to ~/.gnus."
  (cond
   ((file-newer-than-file-p "~/.Gnus.el" "~/.gnus")
	(let ((mode-line-format
	       "*** PLEASE STANDBY: RECOMPILING .Gnus.el **"))
	  (yow)
	  (sit-for 1)
	  (byte-compile-file "~/.Gnus.el")
	  (message ".gnus recompiled --- reloading ...")
	  (rename-file "~/.Gnus.elc" "~/.gnus" t))
	(load "~/.gnus" t t t)
	;;  (sit-for 2)
	(message "Gnus.el recompiled")
	)))
(GnusWait!)

tangle and compile org config witihout loading org-mode

  (let ((src "~/org/dotemacs.org")
        (dst "~/.dotemacs.el"))
    (when (file-newer-than-file-p src dst)
      (call-process
       (concat invocation-directory invocation-name)
       nil nil t
       "-q" "--batch" "--eval" "(require 'ob-tangle)"
       "--eval" (format "(org-babel-tangle-file \"%s\" \"%s\")" src dst)))
    (require 'bytecomp)
    (byte-recompile-file dst nil 0 t))
So, who originally wrote this, anyway? I’ve seen it in several .emacs files…

CategoryCode, CategoryDotEmacs