diff options
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | doc/guix.texi | 13 | ||||
| -rw-r--r-- | guix/build-system/emacs.scm | 141 | ||||
| -rw-r--r-- | guix/build/emacs-build-system.scm | 200 |
4 files changed, 356 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index 63be2228a49..ea809be4222 100644 --- a/Makefile.am +++ b/Makefile.am | |||
| @@ -51,6 +51,7 @@ MODULES = \ | |||
| 51 | guix/licenses.scm \ | 51 | guix/licenses.scm \ |
| 52 | guix/build-system.scm \ | 52 | guix/build-system.scm \ |
| 53 | guix/build-system/cmake.scm \ | 53 | guix/build-system/cmake.scm \ |
| 54 | guix/build-system/emacs.scm \ | ||
| 54 | guix/build-system/glib-or-gtk.scm \ | 55 | guix/build-system/glib-or-gtk.scm \ |
| 55 | guix/build-system/gnu.scm \ | 56 | guix/build-system/gnu.scm \ |
| 56 | guix/build-system/haskell.scm \ | 57 | guix/build-system/haskell.scm \ |
| @@ -69,6 +70,7 @@ MODULES = \ | |||
| 69 | guix/ui.scm \ | 70 | guix/ui.scm \ |
| 70 | guix/build/download.scm \ | 71 | guix/build/download.scm \ |
| 71 | guix/build/cmake-build-system.scm \ | 72 | guix/build/cmake-build-system.scm \ |
| 73 | guix/build/emacs-build-system.scm \ | ||
| 72 | guix/build/git.scm \ | 74 | guix/build/git.scm \ |
| 73 | guix/build/glib-or-gtk-build-system.scm \ | 75 | guix/build/glib-or-gtk-build-system.scm \ |
| 74 | guix/build/gnu-build-system.scm \ | 76 | guix/build/gnu-build-system.scm \ |
diff --git a/doc/guix.texi b/doc/guix.texi index d10279e992f..585017f5cff 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -2454,6 +2454,19 @@ Which Haskell compiler is used can be specified with the @code{#:haskell} | |||
| 2454 | parameter which defaults to @code{ghc}. | 2454 | parameter which defaults to @code{ghc}. |
| 2455 | @end defvr | 2455 | @end defvr |
| 2456 | 2456 | ||
| 2457 | @defvr {Scheme Variable} emacs-build-system | ||
| 2458 | This variable is exported by @code{(guix build-system emacs)}. It | ||
| 2459 | implements an installation procedure similar to the one of Emacs' own | ||
| 2460 | packaging system (@pxref{Packages,,, emacs, The GNU Emacs Manual}). | ||
| 2461 | |||
| 2462 | It first creates the @code{@var{package}-autoloads.el} file, then it | ||
| 2463 | byte compiles all Emacs Lisp files. Differently from the Emacs | ||
| 2464 | packaging system, the Info documentation files are moved to the standard | ||
| 2465 | documentation directory and the @file{dir} file is deleted. Each | ||
| 2466 | package is installed in its own directory under | ||
| 2467 | @file{share/emacs/site-lisp/guix.d}. | ||
| 2468 | @end defvr | ||
| 2469 | |||
| 2457 | Lastly, for packages that do not need anything as sophisticated, a | 2470 | Lastly, for packages that do not need anything as sophisticated, a |
| 2458 | ``trivial'' build system is provided. It is trivial in the sense that | 2471 | ``trivial'' build system is provided. It is trivial in the sense that |
| 2459 | it provides basically no support: it does not pull any implicit inputs, | 2472 | it provides basically no support: it does not pull any implicit inputs, |
diff --git a/guix/build-system/emacs.scm b/guix/build-system/emacs.scm new file mode 100644 index 00000000000..03c1eb2bafa --- /dev/null +++ b/guix/build-system/emacs.scm | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (guix build-system emacs) | ||
| 20 | #:use-module (guix store) | ||
| 21 | #:use-module (guix utils) | ||
| 22 | #:use-module (guix packages) | ||
| 23 | #:use-module (guix derivations) | ||
| 24 | #:use-module (guix search-paths) | ||
| 25 | #:use-module (guix build-system) | ||
| 26 | #:use-module (guix build-system gnu) | ||
| 27 | #:use-module (ice-9 match) | ||
| 28 | #:use-module (srfi srfi-26) | ||
| 29 | #:export (%emacs-build-system-modules | ||
| 30 | emacs-build | ||
| 31 | emacs-build-system)) | ||
| 32 | |||
| 33 | ;; Commentary: | ||
| 34 | ;; | ||
| 35 | ;; Standard build procedure for Emacs packages. This is implemented as an | ||
| 36 | ;; extension of 'gnu-build-system'. | ||
| 37 | ;; | ||
| 38 | ;; Code: | ||
| 39 | |||
| 40 | (define %emacs-build-system-modules | ||
| 41 | ;; Build-side modules imported by default. | ||
| 42 | `((guix build emacs-build-system) | ||
| 43 | (guix build emacs-utils) | ||
| 44 | ,@%gnu-build-system-modules)) | ||
| 45 | |||
| 46 | (define (default-emacs) | ||
| 47 | "Return the default Emacs package." | ||
| 48 | ;; Lazily resolve the binding to avoid a circular dependency. | ||
| 49 | (let ((emacs-mod (resolve-interface '(gnu packages emacs)))) | ||
| 50 | ;; we use 'emacs' instead of 'emacs-no-x' because the latter appears not | ||
| 51 | ;; to be loading some macros and causes problems to some packages. For | ||
| 52 | ;; example, with the latter AUCTeX gives the error message: | ||
| 53 | ;; "(invalid-function dbus-ignore-errors)". | ||
| 54 | (module-ref emacs-mod 'emacs))) | ||
| 55 | |||
| 56 | (define* (lower name | ||
| 57 | #:key source inputs native-inputs outputs system target | ||
| 58 | (emacs (default-emacs)) | ||
| 59 | #:allow-other-keys | ||
| 60 | #:rest arguments) | ||
| 61 | "Return a bag for NAME." | ||
| 62 | (define private-keywords | ||
| 63 | '(#:target #:emacs #:inputs #:native-inputs)) | ||
| 64 | |||
| 65 | (and (not target) ;XXX: no cross-compilation | ||
| 66 | (bag | ||
| 67 | (name name) | ||
| 68 | (system system) | ||
| 69 | (host-inputs `(,@(if source | ||
| 70 | `(("source" ,source)) | ||
| 71 | '()) | ||
| 72 | ,@inputs | ||
| 73 | |||
| 74 | ;; Keep the standard inputs of 'gnu-build-system'. | ||
| 75 | ,@(standard-packages))) | ||
| 76 | (build-inputs `(("emacs" ,emacs) | ||
| 77 | ,@native-inputs)) | ||
| 78 | (outputs outputs) | ||
| 79 | (build emacs-build) | ||
| 80 | (arguments (strip-keyword-arguments private-keywords arguments))))) | ||
| 81 | |||
| 82 | (define* (emacs-build store name inputs | ||
| 83 | #:key source | ||
| 84 | (tests? #t) | ||
| 85 | (test-target "test") | ||
| 86 | (configure-flags ''()) | ||
| 87 | (phases '(@ (guix build emacs-build-system) | ||
| 88 | %standard-phases)) | ||
| 89 | (outputs '("out")) | ||
| 90 | (search-paths '()) | ||
| 91 | (system (%current-system)) | ||
| 92 | (guile #f) | ||
| 93 | (imported-modules %emacs-build-system-modules) | ||
| 94 | (modules '((guix build emacs-build-system) | ||
| 95 | (guix build utils) | ||
| 96 | (guix build emacs-utils)))) | ||
| 97 | "Build SOURCE using EMACS, and with INPUTS." | ||
| 98 | (define builder | ||
| 99 | `(begin | ||
| 100 | (use-modules ,@modules) | ||
| 101 | (emacs-build #:name ,name | ||
| 102 | #:source ,(match (assoc-ref inputs "source") | ||
| 103 | (((? derivation? source)) | ||
| 104 | (derivation->output-path source)) | ||
| 105 | ((source) | ||
| 106 | source) | ||
| 107 | (source | ||
| 108 | source)) | ||
| 109 | #:configure-flags ,configure-flags | ||
| 110 | #:system ,system | ||
| 111 | #:test-target ,test-target | ||
| 112 | #:tests? ,tests? | ||
| 113 | #:phases ,phases | ||
| 114 | #:outputs %outputs | ||
| 115 | #:search-paths ',(map search-path-specification->sexp | ||
| 116 | search-paths) | ||
| 117 | #:inputs %build-inputs))) | ||
| 118 | |||
| 119 | (define guile-for-build | ||
| 120 | (match guile | ||
| 121 | ((? package?) | ||
| 122 | (package-derivation store guile system #:graft? #f)) | ||
| 123 | (#f ; the default | ||
| 124 | (let* ((distro (resolve-interface '(gnu packages commencement))) | ||
| 125 | (guile (module-ref distro 'guile-final))) | ||
| 126 | (package-derivation store guile system #:graft? #f))))) | ||
| 127 | |||
| 128 | (build-expression->derivation store name builder | ||
| 129 | #:inputs inputs | ||
| 130 | #:system system | ||
| 131 | #:modules imported-modules | ||
| 132 | #:outputs outputs | ||
| 133 | #:guile-for-build guile-for-build)) | ||
| 134 | |||
| 135 | (define emacs-build-system | ||
| 136 | (build-system | ||
| 137 | (name 'emacs) | ||
| 138 | (description "The build system for Emacs packages") | ||
| 139 | (lower lower))) | ||
| 140 | |||
| 141 | ;;; emacs.scm ends here | ||
diff --git a/guix/build/emacs-build-system.scm b/guix/build/emacs-build-system.scm new file mode 100644 index 00000000000..dd3cfc47ac9 --- /dev/null +++ b/guix/build/emacs-build-system.scm | |||
| @@ -0,0 +1,200 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (guix build emacs-build-system) | ||
| 20 | #:use-module ((guix build gnu-build-system) #:prefix gnu:) | ||
| 21 | #:use-module (guix build utils) | ||
| 22 | #:use-module (guix build emacs-utils) | ||
| 23 | #:use-module (srfi srfi-1) | ||
| 24 | #:use-module (srfi srfi-26) | ||
| 25 | #:use-module (ice-9 rdelim) | ||
| 26 | #:use-module (ice-9 regex) | ||
| 27 | #:use-module (ice-9 match) | ||
| 28 | #:export (%standard-phases | ||
| 29 | emacs-build)) | ||
| 30 | |||
| 31 | ;; Commentary: | ||
| 32 | ;; | ||
| 33 | ;; Builder-side code of the build procedure for ELPA Emacs packages. | ||
| 34 | ;; | ||
| 35 | ;; Code: | ||
| 36 | |||
| 37 | ;; Directory suffix where we install ELPA packages. We avoid ".../elpa" as | ||
| 38 | ;; Emacs expects to find the ELPA repository 'archive-contents' file and the | ||
| 39 | ;; archive signature. | ||
| 40 | (define %install-suffix "/share/emacs/site-lisp/guix.d") | ||
| 41 | |||
| 42 | (define* (build #:key outputs inputs #:allow-other-keys) | ||
| 43 | "Compile .el files." | ||
| 44 | (let* ((emacs (string-append (assoc-ref inputs "emacs") "/bin/emacs")) | ||
| 45 | (out (assoc-ref outputs "out")) | ||
| 46 | (elpa-name-ver (store-directory->elpa-name-version out)) | ||
| 47 | (el-dir (string-append out %install-suffix "/" elpa-name-ver)) | ||
| 48 | (deps-dirs (emacs-inputs-directories inputs))) | ||
| 49 | (setenv "SHELL" "sh") | ||
| 50 | (parameterize ((%emacs emacs)) | ||
| 51 | (emacs-byte-compile-directory el-dir | ||
| 52 | (emacs-inputs-el-directories deps-dirs))))) | ||
| 53 | |||
| 54 | (define* (patch-el-files #:key outputs #:allow-other-keys) | ||
| 55 | "Substitute the absolute \"/bin/\" directory with the right location in the | ||
| 56 | store in '.el' files." | ||
| 57 | (let* ((out (assoc-ref outputs "out")) | ||
| 58 | (elpa-name-ver (store-directory->elpa-name-version out)) | ||
| 59 | (el-dir (string-append out %install-suffix "/" elpa-name-ver)) | ||
| 60 | (substitute-cmd (lambda () | ||
| 61 | (substitute* (find-files "." "\\.el$") | ||
| 62 | (("\"/bin/(.*)\"" _ cmd) | ||
| 63 | (string-append "\"" (which cmd) "\"")))))) | ||
| 64 | (with-directory-excursion el-dir | ||
| 65 | ;; Some old '.el' files (e.g., tex-buf.el in AUCTeX) are still encoded | ||
| 66 | ;; with the "ISO-8859-1" locale. | ||
| 67 | (unless (false-if-exception (substitute-cmd)) | ||
| 68 | (with-fluids ((%default-port-encoding "ISO-8859-1")) | ||
| 69 | (substitute-cmd)))) | ||
| 70 | #t)) | ||
| 71 | |||
| 72 | (define* (install #:key outputs #:allow-other-keys) | ||
| 73 | "Install the package contents." | ||
| 74 | (let* ((out (assoc-ref outputs "out")) | ||
| 75 | (elpa-name-ver (store-directory->elpa-name-version out)) | ||
| 76 | (src-dir (getcwd)) | ||
| 77 | (tgt-dir (string-append out %install-suffix "/" elpa-name-ver))) | ||
| 78 | (copy-recursively src-dir tgt-dir) | ||
| 79 | #t)) | ||
| 80 | |||
| 81 | (define* (move-doc #:key outputs #:allow-other-keys) | ||
| 82 | "Move info files from the ELPA package directory to the info directory." | ||
| 83 | (let* ((out (assoc-ref outputs "out")) | ||
| 84 | (elpa-name-ver (store-directory->elpa-name-version out)) | ||
| 85 | (el-dir (string-append out %install-suffix "/" elpa-name-ver)) | ||
| 86 | (name-ver (store-directory->name-version out)) | ||
| 87 | (info-dir (string-append out "/share/info/" name-ver)) | ||
| 88 | (info-files (find-files el-dir "\\.info$"))) | ||
| 89 | (unless (null? info-files) | ||
| 90 | (mkdir-p info-dir) | ||
| 91 | (with-directory-excursion el-dir | ||
| 92 | (when (file-exists? "dir") (delete-file "dir")) | ||
| 93 | (for-each (lambda (f) | ||
| 94 | (copy-file f (string-append info-dir "/" (basename f))) | ||
| 95 | (delete-file f)) | ||
| 96 | info-files))) | ||
| 97 | #t)) | ||
| 98 | |||
| 99 | (define* (make-autoloads #:key outputs inputs #:allow-other-keys) | ||
| 100 | "Generate the autoloads file." | ||
| 101 | (let* ((emacs (string-append (assoc-ref inputs "emacs") "/bin/emacs")) | ||
| 102 | (out (assoc-ref outputs "out")) | ||
| 103 | (elpa-name-ver (store-directory->elpa-name-version out)) | ||
| 104 | (elpa-name (package-name->name+version elpa-name-ver)) | ||
| 105 | (el-dir (string-append out %install-suffix "/" elpa-name-ver))) | ||
| 106 | (parameterize ((%emacs emacs)) | ||
| 107 | (emacs-generate-autoloads elpa-name el-dir)) | ||
| 108 | #t)) | ||
| 109 | |||
| 110 | (define (emacs-package? name) | ||
| 111 | "Check if NAME correspond to the name of an Emacs package." | ||
| 112 | (string-prefix? "emacs-" name)) | ||
| 113 | |||
| 114 | (define (emacs-inputs inputs) | ||
| 115 | "Retrieve the list of Emacs packages from INPUTS." | ||
| 116 | (filter (match-lambda | ||
| 117 | ((label directory) | ||
| 118 | (emacs-package? ((compose package-name->name+version | ||
| 119 | store-directory->name-version) | ||
| 120 | directory))) | ||
| 121 | (_ #f)) | ||
| 122 | inputs)) | ||
| 123 | |||
| 124 | (define (emacs-inputs-directories inputs) | ||
| 125 | "Extract the list of Emacs package directories from INPUTS." | ||
| 126 | (let ((inputs (emacs-inputs inputs))) | ||
| 127 | (match inputs | ||
| 128 | (((names . directories) ...) directories)))) | ||
| 129 | |||
| 130 | (define (emacs-inputs-el-directories dirs) | ||
| 131 | "Build the list of Emacs Lisp directories from the Emacs package directory | ||
| 132 | DIRS." | ||
| 133 | (map (lambda (d) | ||
| 134 | (string-append d %install-suffix "/" | ||
| 135 | (store-directory->elpa-name-version d))) | ||
| 136 | dirs)) | ||
| 137 | |||
| 138 | (define (package-name-version->elpa-name-version name-ver) | ||
| 139 | "Convert the Guix package NAME-VER to the corresponding ELPA name-version | ||
| 140 | format. Essnetially drop the prefix used in Guix." | ||
| 141 | (let ((name (store-directory->name-version name-ver))) | ||
| 142 | (if (emacs-package? name-ver) | ||
| 143 | (store-directory->name-version name-ver) | ||
| 144 | name-ver))) | ||
| 145 | |||
| 146 | (define (store-directory->elpa-name-version store-dir) | ||
| 147 | "Given a store directory STORE-DIR return the part of the basename after the | ||
| 148 | second hyphen. This corresponds to 'name-version' as used in ELPA packages." | ||
| 149 | ((compose package-name-version->elpa-name-version | ||
| 150 | store-directory->name-version) | ||
| 151 | store-dir)) | ||
| 152 | |||
| 153 | (define (store-directory->name-version store-dir) | ||
| 154 | "Given a store directory STORE-DIR return the part of the basename | ||
| 155 | after the first hyphen. This corresponds to 'name-version' of the package." | ||
| 156 | (let* ((base (basename store-dir))) | ||
| 157 | (string-drop base | ||
| 158 | (+ 1 (string-index base #\-))))) | ||
| 159 | |||
| 160 | ;; from (guix utils). Should we put it in (guix build utils)? | ||
| 161 | (define (package-name->name+version name) | ||
| 162 | "Given NAME, a package name like \"foo-0.9.1b\", return two values: | ||
| 163 | \"foo\" and \"0.9.1b\". When the version part is unavailable, NAME and | ||
| 164 | #f are returned. The first hyphen followed by a digit is considered to | ||
| 165 | introduce the version part." | ||
| 166 | ;; See also `DrvName' in Nix. | ||
| 167 | |||
| 168 | (define number? | ||
| 169 | (cut char-set-contains? char-set:digit <>)) | ||
| 170 | |||
| 171 | (let loop ((chars (string->list name)) | ||
| 172 | (prefix '())) | ||
| 173 | (match chars | ||
| 174 | (() | ||
| 175 | (values name #f)) | ||
| 176 | ((#\- (? number? n) rest ...) | ||
| 177 | (values (list->string (reverse prefix)) | ||
| 178 | (list->string (cons n rest)))) | ||
| 179 | ((head tail ...) | ||
| 180 | (loop tail (cons head prefix)))))) | ||
| 181 | |||
| 182 | (define %standard-phases | ||
| 183 | (modify-phases gnu:%standard-phases | ||
| 184 | (delete 'configure) | ||
| 185 | (delete 'check) | ||
| 186 | (delete 'install) | ||
| 187 | (replace 'build build) | ||
| 188 | (add-before 'build 'install install) | ||
| 189 | (add-after 'install 'make-autoloads make-autoloads) | ||
| 190 | (add-after 'make-autoloads 'patch-el-files patch-el-files) | ||
| 191 | (add-after 'make-autoloads 'move-doc move-doc))) | ||
| 192 | |||
| 193 | (define* (emacs-build #:key inputs (phases %standard-phases) | ||
| 194 | #:allow-other-keys #:rest args) | ||
| 195 | "Build the given Emacs package, applying all of PHASES in order." | ||
| 196 | (apply gnu:gnu-build | ||
| 197 | #:inputs inputs #:phases phases | ||
| 198 | args)) | ||
| 199 | |||
| 200 | ;;; emacs-build-system.scm ends here | ||
