el-get-byte-compile.el 4.96 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
;;; el-get --- Manage the external elisp bits and pieces you depend upon
;;
;; Copyright (C) 2010-2011 Dimitri Fontaine
;;
;; Author: Dimitri Fontaine <dim@tapoueh.org>
;; URL: http://www.emacswiki.org/emacs/el-get
;; GIT: https://github.com/dimitri/el-get
;; Licence: WTFPL, grab your copy here: http://sam.zoy.org/wtfpl/
;;
;; This file is NOT part of GNU Emacs.
;;
;; Install
;;     Please see the README.asciidoc file from the same distribution

15
(require 'cl)				; yes I like loop
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
(require 'bytecomp)

;; Emacs < 24
(eval-and-compile
  (if (fboundp 'byte-recompile-file)
      (defsubst el-get-byte-compile-file (el)
        ;; Byte-compile runs emacs-lisp-mode-hook; disable it
        (let (emacs-lisp-mode-hook)
          (byte-recompile-file el)))
    (defun el-get-byte-compile-file (el)
      "Same as `byte-compile-file', but skips unnecessary compilation.

Specifically, if the compiled elc file already exists and is
newer, then compilation will be skipped."
      (let ((elc (concat (file-name-sans-extension el) ".elc"))
            ;; Byte-compile runs emacs-lisp-mode-hook; disable it
            emacs-lisp-mode-hook)
        (when (or (not (file-exists-p elc))
                  (file-newer-than-file-p el elc))
          (condition-case err
              (byte-compile-file el)
            ((debug error) ;; catch-all, allow for debugging
             (message "%S" (error-message-string err)))))))))

(defun el-get-byte-compile-file-or-directory (file)
  "Byte-compile FILE or all files within it if it is a directory."
  (let ((byte-compile-warnings nil)
        ;; Byte-compile runs emacs-lisp-mode-hook; disable it
        emacs-lisp-mode-hook)
    (if (file-directory-p file)
        (byte-recompile-directory file 0)
      (el-get-byte-compile-file file))))

(defun el-get-assemble-files-for-byte-compilation (package)
  "Assemble a list of *absolute* paths to byte-compile for PACKAGE."
  (when el-get-byte-compile
    (let* ((source   (el-get-package-def package))
           (comp-prop (plist-get source :compile))
           (compile (el-get-as-list comp-prop))
           ;; nocomp is true only if :compile is explicitly set to nil.
           (explicit-nocomp (and (plist-member source :compile)
                                 (not comp-prop)))
	   (method   (el-get-package-method source))
	   (pdir     (el-get-package-directory package))
	   (el-path  (el-get-load-path package))
	   (files '()))
      (cond
       (compile
        ;; only byte-compile what's in the :compile property of the recipe
        (dolist (path compile)
          (let ((fullpath (expand-file-name path pdir)))
            (if (file-exists-p fullpath)
                ;; path is a file/dir, so add it literally
                (add-to-list 'files fullpath)
              ;; path is a regexp, so add matching file names in package dir
              (mapc (apply-partially 'add-to-list 'files)
		    (directory-files pdir nil fullpath))))))

       ;; If package has (:compile nil), or package has its own build
       ;; instructions, or package is already pre-compiled by the
       ;; installation method, then don't compile anything.
       ((or explicit-nocomp
            (el-get-build-commands package)
            (member method '(apt-get fink pacman)))
        nil)

       ;; Default: compile the package's entire load-path
       (t
        (mapc (apply-partially 'add-to-list 'files) el-path)))
      files)))

(defun el-get-byte-compile-from-stdin ()
  "byte compile files read on STDIN

This is run as a subprocess with an `emacs -Q -batch -f
el-get-byte-compile` command and with the file list as stdin,
written by `prin1-to-string' so that `read' is able to process
it."
  (let ((files (read)))
    (loop for f in files
	  do (progn
	       (message "el-get-byte-compile-from-stdin: %s" f)
	       (el-get-byte-compile-file-or-directory f)))))

(defun el-get-byte-compile-process (package buffer working-dir sync files)
  "return the 'el-get-start-process-list' entry to byte compile PACKAGE"
  (let ((bytecomp-command
	 (list el-get-emacs
	       "-Q" "-batch" "-f" "toggle-debug-on-error"
	       "-l" (shell-quote-argument
		     (file-name-sans-extension
		      (symbol-file 'el-get-byte-compile-from-stdin 'defun)))
	       "-f" "el-get-byte-compile-from-stdin")))
    `(:command-name "byte-compile"
		    :buffer-name ,buffer
		    :default-directory ,working-dir
		    :shell t
		    :sync ,sync
		    :stdin ,files
		    :program ,(car bytecomp-command)
		    :args ,(cdr bytecomp-command)
		    :message ,(format "el-get-build %s: byte-compile ok." package)
		    :error ,(format
			     "el-get could not byte-compile %s" package))))

(defun el-get-byte-compile (package)
  "byte compile files for given package"
  (let ((pdir  (el-get-package-directory package))
	(buf   "*el-get-byte-compile*")
	(files (el-get-assemble-files-for-byte-compilation package)))
    (when files
      (el-get-start-process-list
       package
       (list (el-get-byte-compile-process package buf pdir t files))
       nil))))


(provide 'el-get-byte-compile)