build: Add 'emacs-build-system'.
* Makefile.am (MODULES): Add 'guix/build-system/emacs.scm' and 'guix/build/emacs-build-system.scm'. * guix/build-system/emacs.scm: New file. * guix/build/emacs-build-system.scm: New file. * doc/guix.texi (Build Systems): Document it.
This commit is contained in:
		
							parent
							
								
									1d44b4e544
								
							
						
					
					
						commit
						e9137a5310
					
				
					 4 changed files with 356 additions and 0 deletions
				
			
		|  | @ -51,6 +51,7 @@ MODULES =					\ | |||
|   guix/licenses.scm				\ | ||||
|   guix/build-system.scm				\ | ||||
|   guix/build-system/cmake.scm			\ | ||||
|   guix/build-system/emacs.scm			\ | ||||
|   guix/build-system/glib-or-gtk.scm		\ | ||||
|   guix/build-system/gnu.scm			\ | ||||
|   guix/build-system/haskell.scm			\ | ||||
|  | @ -69,6 +70,7 @@ MODULES =					\ | |||
|   guix/ui.scm					\ | ||||
|   guix/build/download.scm			\ | ||||
|   guix/build/cmake-build-system.scm		\ | ||||
|   guix/build/emacs-build-system.scm		\ | ||||
|   guix/build/git.scm				\ | ||||
|   guix/build/glib-or-gtk-build-system.scm	\ | ||||
|   guix/build/gnu-build-system.scm		\ | ||||
|  |  | |||
|  | @ -2454,6 +2454,19 @@ Which Haskell compiler is used can be specified with the @code{#:haskell} | |||
| parameter which defaults to @code{ghc}. | ||||
| @end defvr | ||||
| 
 | ||||
| @defvr {Scheme Variable} emacs-build-system | ||||
| This variable is exported by @code{(guix build-system emacs)}.  It | ||||
| implements an installation procedure similar to the one of Emacs' own | ||||
| packaging system (@pxref{Packages,,, emacs, The GNU Emacs Manual}). | ||||
| 
 | ||||
| It first creates the @code{@var{package}-autoloads.el} file, then it | ||||
| byte compiles all Emacs Lisp files.  Differently from the Emacs | ||||
| packaging system, the Info documentation files are moved to the standard | ||||
| documentation directory and the @file{dir} file is deleted.  Each | ||||
| package is installed in its own directory under | ||||
| @file{share/emacs/site-lisp/guix.d}. | ||||
| @end defvr | ||||
| 
 | ||||
| Lastly, for packages that do not need anything as sophisticated, a | ||||
| ``trivial'' build system is provided.  It is trivial in the sense that | ||||
| it provides basically no support: it does not pull any implicit inputs, | ||||
|  |  | |||
							
								
								
									
										141
									
								
								guix/build-system/emacs.scm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								guix/build-system/emacs.scm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,141 @@ | |||
| ;;; GNU Guix --- Functional package management for GNU | ||||
| ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch> | ||||
| ;;; | ||||
| ;;; This file is part of GNU Guix. | ||||
| ;;; | ||||
| ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||||
| ;;; under the terms of the GNU General Public License as published by | ||||
| ;;; the Free Software Foundation; either version 3 of the License, or (at | ||||
| ;;; your option) any later version. | ||||
| ;;; | ||||
| ;;; GNU Guix is distributed in the hope that it will be useful, but | ||||
| ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| ;;; GNU General Public License for more details. | ||||
| ;;; | ||||
| ;;; You should have received a copy of the GNU General Public License | ||||
| ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| (define-module (guix build-system emacs) | ||||
|   #:use-module (guix store) | ||||
|   #:use-module (guix utils) | ||||
|   #:use-module (guix packages) | ||||
|   #:use-module (guix derivations) | ||||
|   #:use-module (guix search-paths) | ||||
|   #:use-module (guix build-system) | ||||
|   #:use-module (guix build-system gnu) | ||||
|   #:use-module (ice-9 match) | ||||
|   #:use-module (srfi srfi-26) | ||||
|   #:export (%emacs-build-system-modules | ||||
|             emacs-build | ||||
|             emacs-build-system)) | ||||
| 
 | ||||
| ;; Commentary: | ||||
| ;; | ||||
| ;; Standard build procedure for Emacs packages.  This is implemented as an | ||||
| ;; extension of 'gnu-build-system'. | ||||
| ;; | ||||
| ;; Code: | ||||
| 
 | ||||
| (define %emacs-build-system-modules | ||||
|   ;; Build-side modules imported by default. | ||||
|   `((guix build emacs-build-system) | ||||
|     (guix build emacs-utils) | ||||
|     ,@%gnu-build-system-modules)) | ||||
| 
 | ||||
| (define (default-emacs) | ||||
|   "Return the default Emacs package." | ||||
|   ;; Lazily resolve the binding to avoid a circular dependency. | ||||
|   (let ((emacs-mod (resolve-interface '(gnu packages emacs)))) | ||||
|     ;; we use 'emacs' instead of 'emacs-no-x' because the latter appears not | ||||
|     ;; to be loading some macros and causes problems to some packages.  For | ||||
|     ;; example, with the latter AUCTeX gives the error message: | ||||
|     ;; "(invalid-function dbus-ignore-errors)". | ||||
|     (module-ref emacs-mod 'emacs))) | ||||
| 
 | ||||
| (define* (lower name | ||||
|                 #:key source inputs native-inputs outputs system target | ||||
|                 (emacs (default-emacs)) | ||||
|                 #:allow-other-keys | ||||
|                 #:rest arguments) | ||||
|   "Return a bag for NAME." | ||||
|   (define private-keywords | ||||
|     '(#:target #:emacs #:inputs #:native-inputs)) | ||||
| 
 | ||||
|   (and (not target)                               ;XXX: no cross-compilation | ||||
|        (bag | ||||
|          (name name) | ||||
|          (system system) | ||||
|          (host-inputs `(,@(if source | ||||
|                               `(("source" ,source)) | ||||
|                               '()) | ||||
|                         ,@inputs | ||||
| 
 | ||||
|                         ;; Keep the standard inputs of 'gnu-build-system'. | ||||
|                         ,@(standard-packages))) | ||||
|          (build-inputs `(("emacs" ,emacs) | ||||
|                          ,@native-inputs)) | ||||
|          (outputs outputs) | ||||
|          (build emacs-build) | ||||
|          (arguments (strip-keyword-arguments private-keywords arguments))))) | ||||
| 
 | ||||
| (define* (emacs-build store name inputs | ||||
|                       #:key source | ||||
|                       (tests? #t) | ||||
|                       (test-target "test") | ||||
|                       (configure-flags ''()) | ||||
|                       (phases '(@ (guix build emacs-build-system) | ||||
|                                   %standard-phases)) | ||||
|                       (outputs '("out")) | ||||
|                       (search-paths '()) | ||||
|                       (system (%current-system)) | ||||
|                       (guile #f) | ||||
|                       (imported-modules %emacs-build-system-modules) | ||||
|                       (modules '((guix build emacs-build-system) | ||||
|                                  (guix build utils) | ||||
|                                  (guix build emacs-utils)))) | ||||
|   "Build SOURCE using EMACS, and with INPUTS." | ||||
|   (define builder | ||||
|     `(begin | ||||
|        (use-modules ,@modules) | ||||
|        (emacs-build #:name ,name | ||||
|                     #:source ,(match (assoc-ref inputs "source") | ||||
|                                 (((? derivation? source)) | ||||
|                                  (derivation->output-path source)) | ||||
|                                 ((source) | ||||
|                                  source) | ||||
|                                 (source | ||||
|                                  source)) | ||||
|                     #:configure-flags ,configure-flags | ||||
|                     #:system ,system | ||||
|                     #:test-target ,test-target | ||||
|                     #:tests? ,tests? | ||||
|                     #:phases ,phases | ||||
|                     #:outputs %outputs | ||||
|                     #:search-paths ',(map search-path-specification->sexp | ||||
|                                           search-paths) | ||||
|                     #:inputs %build-inputs))) | ||||
| 
 | ||||
|   (define guile-for-build | ||||
|     (match guile | ||||
|       ((? package?) | ||||
|        (package-derivation store guile system #:graft? #f)) | ||||
|       (#f                                         ; the default | ||||
|        (let* ((distro (resolve-interface '(gnu packages commencement))) | ||||
|               (guile  (module-ref distro 'guile-final))) | ||||
|          (package-derivation store guile system #:graft? #f))))) | ||||
| 
 | ||||
|   (build-expression->derivation store name builder | ||||
|                                 #:inputs inputs | ||||
|                                 #:system system | ||||
|                                 #:modules imported-modules | ||||
|                                 #:outputs outputs | ||||
|                                 #:guile-for-build guile-for-build)) | ||||
| 
 | ||||
| (define emacs-build-system | ||||
|   (build-system | ||||
|     (name 'emacs) | ||||
|     (description "The build system for Emacs packages") | ||||
|     (lower lower))) | ||||
| 
 | ||||
| ;;; emacs.scm ends here | ||||
							
								
								
									
										200
									
								
								guix/build/emacs-build-system.scm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								guix/build/emacs-build-system.scm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,200 @@ | |||
| ;;; GNU Guix --- Functional package management for GNU | ||||
| ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch> | ||||
| ;;; | ||||
| ;;; This file is part of GNU Guix. | ||||
| ;;; | ||||
| ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||||
| ;;; under the terms of the GNU General Public License as published by | ||||
| ;;; the Free Software Foundation; either version 3 of the License, or (at | ||||
| ;;; your option) any later version. | ||||
| ;;; | ||||
| ;;; GNU Guix is distributed in the hope that it will be useful, but | ||||
| ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| ;;; GNU General Public License for more details. | ||||
| ;;; | ||||
| ;;; You should have received a copy of the GNU General Public License | ||||
| ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| (define-module (guix build emacs-build-system) | ||||
|   #:use-module ((guix build gnu-build-system) #:prefix gnu:) | ||||
|   #:use-module (guix build utils) | ||||
|   #:use-module (guix build emacs-utils) | ||||
|   #:use-module (srfi srfi-1) | ||||
|   #:use-module (srfi srfi-26) | ||||
|   #:use-module (ice-9 rdelim) | ||||
|   #:use-module (ice-9 regex) | ||||
|   #:use-module (ice-9 match) | ||||
|   #:export (%standard-phases | ||||
|             emacs-build)) | ||||
| 
 | ||||
| ;; Commentary: | ||||
| ;; | ||||
| ;; Builder-side code of the build procedure for ELPA Emacs packages. | ||||
| ;; | ||||
| ;; Code: | ||||
| 
 | ||||
| ;; Directory suffix where we install ELPA packages.  We avoid ".../elpa" as | ||||
| ;; Emacs expects to find the ELPA repository 'archive-contents' file and the | ||||
| ;; archive signature. | ||||
| (define %install-suffix "/share/emacs/site-lisp/guix.d") | ||||
| 
 | ||||
| (define* (build #:key outputs inputs #:allow-other-keys) | ||||
|   "Compile .el files." | ||||
|   (let* ((emacs (string-append (assoc-ref inputs "emacs") "/bin/emacs")) | ||||
|          (out (assoc-ref outputs "out")) | ||||
|          (elpa-name-ver (store-directory->elpa-name-version out)) | ||||
|          (el-dir (string-append out %install-suffix "/" elpa-name-ver)) | ||||
|          (deps-dirs (emacs-inputs-directories inputs))) | ||||
|     (setenv "SHELL" "sh") | ||||
|     (parameterize ((%emacs emacs)) | ||||
|       (emacs-byte-compile-directory el-dir | ||||
|                                     (emacs-inputs-el-directories deps-dirs))))) | ||||
| 
 | ||||
| (define* (patch-el-files #:key outputs #:allow-other-keys) | ||||
|   "Substitute the absolute \"/bin/\" directory with the right location in the | ||||
| store in '.el' files." | ||||
|   (let* ((out (assoc-ref outputs "out")) | ||||
|          (elpa-name-ver (store-directory->elpa-name-version out)) | ||||
|          (el-dir (string-append out %install-suffix "/" elpa-name-ver)) | ||||
|          (substitute-cmd (lambda () | ||||
|                            (substitute* (find-files "." "\\.el$") | ||||
|                              (("\"/bin/(.*)\"" _ cmd) | ||||
|                               (string-append "\"" (which cmd) "\"")))))) | ||||
|     (with-directory-excursion el-dir | ||||
|       ;; Some old '.el' files (e.g., tex-buf.el in AUCTeX) are still encoded | ||||
|       ;; with the "ISO-8859-1" locale. | ||||
|       (unless (false-if-exception (substitute-cmd)) | ||||
|         (with-fluids ((%default-port-encoding "ISO-8859-1")) | ||||
|           (substitute-cmd)))) | ||||
|     #t)) | ||||
| 
 | ||||
| (define* (install #:key outputs #:allow-other-keys) | ||||
|   "Install the package contents." | ||||
|   (let* ((out (assoc-ref outputs "out")) | ||||
|          (elpa-name-ver (store-directory->elpa-name-version out)) | ||||
|          (src-dir (getcwd)) | ||||
|          (tgt-dir (string-append out %install-suffix "/" elpa-name-ver))) | ||||
|     (copy-recursively src-dir tgt-dir) | ||||
|     #t)) | ||||
| 
 | ||||
| (define* (move-doc #:key outputs #:allow-other-keys) | ||||
|   "Move info files from the ELPA package directory to the info directory." | ||||
|   (let* ((out (assoc-ref outputs "out")) | ||||
|          (elpa-name-ver (store-directory->elpa-name-version out)) | ||||
|          (el-dir (string-append out %install-suffix "/" elpa-name-ver)) | ||||
|          (name-ver (store-directory->name-version out)) | ||||
|          (info-dir (string-append out "/share/info/" name-ver)) | ||||
|          (info-files (find-files el-dir "\\.info$"))) | ||||
|     (unless (null? info-files) | ||||
|       (mkdir-p info-dir) | ||||
|       (with-directory-excursion el-dir | ||||
|         (when (file-exists? "dir") (delete-file "dir")) | ||||
|         (for-each (lambda (f) | ||||
|                     (copy-file f (string-append info-dir "/" (basename f))) | ||||
|                     (delete-file f)) | ||||
|                   info-files))) | ||||
|     #t)) | ||||
| 
 | ||||
| (define* (make-autoloads #:key outputs inputs #:allow-other-keys) | ||||
|   "Generate the autoloads file." | ||||
|   (let* ((emacs (string-append (assoc-ref inputs "emacs") "/bin/emacs")) | ||||
|          (out (assoc-ref outputs "out")) | ||||
|          (elpa-name-ver (store-directory->elpa-name-version out)) | ||||
|          (elpa-name (package-name->name+version elpa-name-ver)) | ||||
|          (el-dir (string-append out %install-suffix "/" elpa-name-ver))) | ||||
|     (parameterize ((%emacs emacs)) | ||||
|       (emacs-generate-autoloads elpa-name el-dir)) | ||||
|     #t)) | ||||
| 
 | ||||
| (define (emacs-package? name) | ||||
|   "Check if NAME correspond to the name of an Emacs package." | ||||
|   (string-prefix? "emacs-" name)) | ||||
| 
 | ||||
| (define (emacs-inputs inputs) | ||||
|   "Retrieve the list of Emacs packages from INPUTS." | ||||
|   (filter (match-lambda | ||||
|             ((label directory) | ||||
|              (emacs-package? ((compose package-name->name+version | ||||
|                                        store-directory->name-version) | ||||
|                               directory))) | ||||
|             (_ #f)) | ||||
|           inputs)) | ||||
| 
 | ||||
| (define (emacs-inputs-directories inputs) | ||||
|   "Extract the list of Emacs package directories from INPUTS." | ||||
|   (let ((inputs (emacs-inputs inputs))) | ||||
|     (match inputs | ||||
|       (((names . directories) ...) directories)))) | ||||
| 
 | ||||
| (define (emacs-inputs-el-directories dirs) | ||||
|   "Build the list of Emacs Lisp directories from the Emacs package directory | ||||
| DIRS." | ||||
|   (map (lambda (d) | ||||
|          (string-append d %install-suffix "/" | ||||
|                         (store-directory->elpa-name-version d))) | ||||
|        dirs)) | ||||
| 
 | ||||
| (define (package-name-version->elpa-name-version name-ver) | ||||
|   "Convert the Guix package NAME-VER to the corresponding ELPA name-version | ||||
| format.  Essnetially drop the prefix used in Guix." | ||||
|   (let ((name (store-directory->name-version name-ver))) | ||||
|     (if (emacs-package? name-ver) | ||||
|         (store-directory->name-version name-ver) | ||||
|         name-ver))) | ||||
| 
 | ||||
| (define (store-directory->elpa-name-version store-dir) | ||||
|   "Given a store directory STORE-DIR return the part of the basename after the | ||||
| second hyphen.  This corresponds to 'name-version' as used in ELPA packages." | ||||
|   ((compose package-name-version->elpa-name-version | ||||
|             store-directory->name-version) | ||||
|    store-dir)) | ||||
| 
 | ||||
| (define (store-directory->name-version store-dir) | ||||
|   "Given a store directory STORE-DIR return the part of the basename | ||||
| after the first hyphen.  This corresponds to 'name-version' of the package." | ||||
|   (let* ((base (basename store-dir))) | ||||
|     (string-drop base | ||||
|                  (+ 1 (string-index base #\-))))) | ||||
| 
 | ||||
| ;; from (guix utils).  Should we put it in (guix build utils)? | ||||
| (define (package-name->name+version name) | ||||
|   "Given NAME, a package name like \"foo-0.9.1b\", return two values: | ||||
| \"foo\" and \"0.9.1b\".  When the version part is unavailable, NAME and | ||||
| #f are returned.  The first hyphen followed by a digit is considered to | ||||
| introduce the version part." | ||||
|   ;; See also `DrvName' in Nix. | ||||
| 
 | ||||
|   (define number? | ||||
|     (cut char-set-contains? char-set:digit <>)) | ||||
| 
 | ||||
|   (let loop ((chars   (string->list name)) | ||||
|              (prefix '())) | ||||
|     (match chars | ||||
|       (() | ||||
|        (values name #f)) | ||||
|       ((#\- (? number? n) rest ...) | ||||
|        (values (list->string (reverse prefix)) | ||||
|                (list->string (cons n rest)))) | ||||
|       ((head tail ...) | ||||
|        (loop tail (cons head prefix)))))) | ||||
| 
 | ||||
| (define %standard-phases | ||||
|   (modify-phases gnu:%standard-phases | ||||
|     (delete 'configure) | ||||
|     (delete 'check) | ||||
|     (delete 'install) | ||||
|     (replace 'build build) | ||||
|     (add-before 'build 'install install) | ||||
|     (add-after 'install 'make-autoloads make-autoloads) | ||||
|     (add-after 'make-autoloads 'patch-el-files patch-el-files) | ||||
|     (add-after 'make-autoloads 'move-doc move-doc))) | ||||
| 
 | ||||
| (define* (emacs-build #:key inputs (phases %standard-phases) | ||||
|                       #:allow-other-keys #:rest args) | ||||
|   "Build the given Emacs package, applying all of PHASES in order." | ||||
|   (apply gnu:gnu-build | ||||
|          #:inputs inputs #:phases phases | ||||
|          args)) | ||||
| 
 | ||||
| ;;; emacs-build-system.scm ends here | ||||
		Reference in a new issue