1 ;;; async-bytecomp.el --- Async functions to compile elisp files async
3 ;; Copyright (C) 2014 John Wiegley
4 ;; Copyright (C) 2014 Thierry Volpiatto
6 ;; Authors: John Wiegley <jwiegley@gmail.com>
7 ;; Thierry Volpiatto <thierry.volpiatto@gmail.com>
9 ;; Keywords: dired async byte-compile
10 ;; X-URL: https://github.com/jwiegley/dired-async
12 ;; This program is free software; you can redistribute it and/or
13 ;; modify it under the terms of the GNU General Public License as
14 ;; published by the Free Software Foundation; either version 2, or (at
15 ;; your option) any later version.
17 ;; This program is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ;; General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
29 ;; This package provide the `async-byte-recompile-directory' function
30 ;; which allows, as the name says to recompile a directory outside of
31 ;; your running emacs.
32 ;; The benefit is your files will be compiled in a clean environment without
33 ;; the old *.el files loaded.
34 ;; Among other things, this fix a bug in package.el which recompile
35 ;; the new files in the current environment with the old files loaded, creating
36 ;; errors in most packages after upgrades.
38 ;; NB: This package is advicing the function `package--compile'.
45 (defcustom async-bytecomp-allowed-packages '(async helm)
46 "Packages in this list will be compiled asynchronously by `package--compile'.
47 All the dependencies of these packages will be compiled async too,
48 so no need to add dependencies to this list.
49 The value of this variable can also be the symbol `all', in this case
50 packages are always compiled asynchronously."
52 :type '(repeat (choice symbol)))
54 (defvar async-byte-compile-log-file "~/.emacs.d/async-bytecomp.log")
56 (defun async-byte-recompile-directory (directory &optional quiet)
57 "Compile all *.el files in DIRECTORY asynchronously.
58 All *.elc files are systematically deleted before proceeding."
59 (cl-loop with dir = (directory-files directory t "\\.elc\\'")
62 when (file-exists-p f) do (delete-file f))
63 ;; Ensure async is reloaded when async.elc is deleted.
64 ;; This happen when recompiling its own directory.
67 `(lambda (&optional ignore)
68 (if (file-exists-p async-byte-compile-log-file)
69 (let ((buf (get-buffer-create byte-compile-log-buffer))
71 (with-current-buffer buf
72 (goto-char (point-max))
73 (let ((inhibit-read-only t))
74 (insert-file-contents async-byte-compile-log-file)
77 (delete-file async-byte-compile-log-file)
80 (goto-char (point-min))
81 (while (re-search-forward "^.*:Error:" nil t)
84 (message "Failed to compile %d files in directory `%s'" n ,directory)
85 (message "Directory `%s' compiled asynchronously with warnings" ,directory)))))
87 (message "Directory `%s' compiled asynchronously with success" ,directory))))))
91 ,(async-inject-variables "\\`\\(load-path\\)\\|byte\\'")
92 (let ((default-directory (file-name-as-directory ,directory))
94 (add-to-list 'load-path default-directory)
95 (byte-recompile-directory ,directory 0 t)
96 (when (get-buffer byte-compile-log-buffer)
97 (setq error-data (with-current-buffer byte-compile-log-buffer
98 (buffer-substring-no-properties (point-min) (point-max))))
99 (unless (string= error-data "")
100 (with-temp-file ,async-byte-compile-log-file
102 (insert error-data))))))
104 (message "Started compiling asynchronously directory %s" directory)))
106 (defvar package-archive-contents)
107 (declare-function package-desc-reqs "package.el" (cl-x))
109 (defun async-bytecomp--get-package-deps (pkg &optional only)
110 (let* ((pkg-desc (cadr (assq pkg package-archive-contents)))
111 (direct-deps (cl-loop for p in (package-desc-reqs pkg-desc)
113 when (assq name package-archive-contents)
115 (indirect-deps (unless (eq only 'direct)
117 (cl-loop for p in direct-deps append
118 (async-bytecomp--get-package-deps p))))))
121 (separate (list direct-deps indirect-deps))
122 (indirect indirect-deps)
123 (t (delete-dups (append direct-deps indirect-deps))))))
125 (defun async-bytecomp-get-allowed-pkgs ()
126 (when (and async-bytecomp-allowed-packages
127 (listp async-bytecomp-allowed-packages))
128 (cl-loop for p in async-bytecomp-allowed-packages
129 append (async-bytecomp--get-package-deps p) into reqs
132 (append async-bytecomp-allowed-packages reqs)))))
134 (defadvice package--compile (around byte-compile-async activate)
135 (let ((cur-package (package-desc-name pkg-desc)))
136 (if (or (eq async-bytecomp-allowed-packages 'all)
137 (memq cur-package (async-bytecomp-get-allowed-pkgs)))
139 (when (eq cur-package 'async)
140 (fmakunbound 'async-byte-recompile-directory))
141 (package-activate-1 pkg-desc)
142 (load "async-bytecomp") ; emacs-24.3 don't reload new files.
143 (async-byte-recompile-directory (package-desc-dir pkg-desc) t))
147 (provide 'async-bytecomp)
149 ;;; async-bytecomp.el ends here