diff options
Diffstat (limited to 'guix/build/asdf-build-system.scm')
-rw-r--r-- | guix/build/asdf-build-system.scm | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/guix/build/asdf-build-system.scm b/guix/build/asdf-build-system.scm new file mode 100644 index 0000000000..085d073dea --- /dev/null +++ b/guix/build/asdf-build-system.scm @@ -0,0 +1,282 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2016 Andy Patterson <ajpatter@uwaterloo.ca> +;;; +;;; 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 asdf-build-system) + #:use-module ((guix build gnu-build-system) #:prefix gnu:) + #:use-module (guix build utils) + #:use-module (guix build lisp-utils) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (ice-9 rdelim) + #:use-module (ice-9 receive) + #:use-module (ice-9 regex) + #:use-module (ice-9 match) + #:use-module (ice-9 format) + #:use-module (ice-9 ftw) + #:export (%standard-phases + %standard-phases/source + asdf-build + asdf-build/source)) + +;; Commentary: +;; +;; System for building ASDF packages; creating executable programs and images +;; from them. +;; +;; Code: + +(define %object-prefix "/lib") + +(define (source-install-prefix lisp) + (string-append %install-prefix "/" lisp "-source")) + +(define %system-install-prefix + (string-append %install-prefix "/systems")) + +(define (output-path->package-name path) + (package-name->name+version (strip-store-file-name path))) + +(define (outputs->name outputs) + (output-path->package-name + (assoc-ref outputs "out"))) + +(define (lisp-source-directory output lisp name) + (string-append output (source-install-prefix lisp) "/" name)) + +(define (source-directory output name) + (string-append output %install-prefix "/source/" name)) + +(define (library-directory output lisp) + (string-append output %object-prefix + "/" lisp)) + +(define (output-translation source-path + object-output + lisp) + "Return a translation for the system's source path +to it's binary output." + `((,source-path + :**/ :*.*.*) + (,(library-directory object-output lisp) + :**/ :*.*.*))) + +(define (source-asd-file output lisp name asd-file) + (string-append (lisp-source-directory output lisp name) "/" asd-file)) + +(define (copy-files-to-output outputs output name) + "Copy all files from OUTPUT to \"out\". Create an extra link to any +system-defining files in the source to a convenient location. This is done +before any compiling so that the compiled source locations will be valid." + (let* ((out (assoc-ref outputs output)) + (source (getcwd)) + (target (source-directory out name)) + (system-path (string-append out %system-install-prefix))) + (copy-recursively source target) + (mkdir-p system-path) + (for-each + (lambda (file) + (symlink file + (string-append system-path "/" (basename file)))) + (find-files target "\\.asd$")) + #t)) + +(define* (install #:key outputs #:allow-other-keys) + "Copy and symlink all the source files." + (copy-files-to-output outputs "out" (outputs->name outputs))) + +(define* (copy-source #:key outputs lisp #:allow-other-keys) + "Copy the source to \"out\"." + (let* ((out (assoc-ref outputs "out")) + (name (remove-lisp-from-name (output-path->package-name out) lisp)) + (install-path (string-append out %install-prefix))) + (copy-files-to-output outputs "out" name) + ;; Hide the files from asdf + (with-directory-excursion install-path + (rename-file "source" (string-append lisp "-source")) + (delete-file-recursively "systems"))) + #t) + +(define* (build #:key outputs inputs lisp asd-file + #:allow-other-keys) + "Compile the system." + (let* ((out (assoc-ref outputs "out")) + (name (remove-lisp-from-name (output-path->package-name out) lisp)) + (source-path (lisp-source-directory out lisp name)) + (translations (wrap-output-translations + `(,(output-translation source-path + out + lisp)))) + (asd-file (and=> asd-file (cut source-asd-file out lisp name <>)))) + + (setenv "ASDF_OUTPUT_TRANSLATIONS" + (replace-escaped-macros (format #f "~S" translations))) + + ;; We don't need this if we have the asd file, and it can mess with the + ;; load ordering we're trying to enforce + (unless asd-file + (prepend-to-source-registry (string-append source-path "//"))) + + (setenv "HOME" out) ; ecl's asdf sometimes wants to create $HOME/.cache + + (parameterize ((%lisp (string-append + (assoc-ref inputs lisp) "/bin/" lisp))) + (compile-system name lisp asd-file)) + + ;; As above, ecl will sometimes create this even though it doesn't use it + + (let ((cache-directory (string-append out "/.cache"))) + (when (directory-exists? cache-directory) + (delete-file-recursively cache-directory)))) + #t) + +(define* (check #:key lisp tests? outputs inputs asd-file + #:allow-other-keys) + "Test the system." + (let* ((name (remove-lisp-from-name (outputs->name outputs) lisp)) + (out (assoc-ref outputs "out")) + (asd-file (and=> asd-file (cut source-asd-file out lisp name <>)))) + (if tests? + (parameterize ((%lisp (string-append + (assoc-ref inputs lisp) "/bin/" lisp))) + (test-system name lisp asd-file)) + (format #t "test suite not run~%"))) + #t) + +(define* (patch-asd-files #:key outputs + inputs + lisp + special-dependencies + test-only-systems + #:allow-other-keys) + "Patch any asd files created by the compilation process so that they can +find their dependencies. Exclude any TEST-ONLY-SYSTEMS which were only +included to run tests. Add any SPECIAL-DEPENDENCIES which the LISP +implementation itself provides." + (let* ((out (assoc-ref outputs "out")) + (name (remove-lisp-from-name (output-path->package-name out) lisp)) + (registry (lset-difference + (lambda (input system) + (match input + ((name . path) (string=? name system)))) + (lisp-dependencies lisp inputs) + test-only-systems)) + (lisp-systems (map first registry))) + + (for-each + (lambda (asd-file) + (patch-asd-file asd-file registry lisp + (append lisp-systems special-dependencies))) + (find-files out "\\.asd$"))) + #t) + +(define* (symlink-asd-files #:key outputs lisp #:allow-other-keys) + "Create an extra reference to the system in a convenient location." + (let* ((out (assoc-ref outputs "out"))) + (for-each + (lambda (asd-file) + (substitute* asd-file + ((";;; Built for.*") "") ; remove potential non-determinism + (("^\\(DEFSYSTEM(.*)$" all end) (string-append "(asdf:defsystem" end))) + (receive (new-asd-file asd-file-directory) + (bundle-asd-file out asd-file lisp) + (mkdir-p asd-file-directory) + (symlink asd-file new-asd-file) + ;; Update the source registry for future phases which might want to + ;; use the newly compiled system. + (prepend-to-source-registry + (string-append asd-file-directory "/")))) + + (find-files (string-append out %object-prefix) "\\.asd$")) +) + #t) + +(define* (cleanup-files #:key outputs lisp + #:allow-other-keys) + "Remove any compiled files which are not a part of the final bundle." + (let ((out (assoc-ref outputs "out"))) + (match lisp + ("sbcl" + (for-each + (lambda (file) + (unless (string-suffix? "--system.fasl" file) + (delete-file file))) + (find-files out "\\.fasl$"))) + ("ecl" + (for-each delete-file + (append (find-files out "\\.fas$") + (find-files out "\\.o$") + (find-files out "\\.a$"))))) + + (with-directory-excursion (library-directory out lisp) + (for-each + (lambda (file) + (rename-file file + (string-append "./" (basename file)))) + (find-files ".")) + (for-each delete-file-recursively + (scandir "." + (lambda (file) + (and + (directory-exists? file) + (string<> "." file) + (string<> ".." file))))))) + #t) + +(define* (strip #:key lisp #:allow-other-keys #:rest args) + ;; stripping sbcl binaries removes their entry program and extra systems + (or (string=? lisp "sbcl") + (apply (assoc-ref gnu:%standard-phases 'strip) args))) + +(define %standard-phases/source + (modify-phases gnu:%standard-phases + (delete 'configure) + (delete 'check) + (delete 'build) + (replace 'install install))) + +(define %standard-phases + (modify-phases gnu:%standard-phases + (delete 'configure) + (delete 'install) + (replace 'build build) + (add-before 'build 'copy-source copy-source) + (replace 'check check) + (replace 'strip strip) + (add-after 'check 'link-dependencies patch-asd-files) + (add-after 'link-dependencies 'cleanup cleanup-files) + (add-after 'cleanup 'create-symlinks symlink-asd-files))) + +(define* (asdf-build #:key inputs + (phases %standard-phases) + #:allow-other-keys + #:rest args) + (apply gnu:gnu-build + #:inputs inputs + #:phases phases + args)) + +(define* (asdf-build/source #:key inputs + (phases %standard-phases/source) + #:allow-other-keys + #:rest args) + (apply gnu:gnu-build + #:inputs inputs + #:phases phases + args)) + +;;; asdf-build-system.scm ends here |