build-system/asdf: Use asdf to determine dependencies.

This removes the need for conventions to determine which inputs are run-time
dependencies, and also the need to specify "special" dependencies.

* guix/build/lisp-utils.scm (patch-asd-file, lisp-dependencies)
(wrap-perform-method): Remove them.
(inputs->asd-file-map, system-dependencies, generate-system-definition)
(generate-dependency-links, make-asd-file): New procedures.
(lisp-eval-program): Add an error if no lisp matches.
(compile-system): Don't use asdf's in-built asd-file generator.
master
Andy Patterson 2017-04-03 09:01:23 -04:00 committed by Ricardo Wurmus
parent 290bf612bb
commit 35189728cd
No known key found for this signature in database
GPG Key ID: 197A5888235FACAC
4 changed files with 141 additions and 99 deletions

View File

@ -822,8 +822,6 @@ compatible with ANSI-compliant Common Lisp implementations.")
(substitute* "clx.asd" (substitute* "clx.asd"
(("\\(:file \"trapezoid\"\\)") "")))))) (("\\(:file \"trapezoid\"\\)") ""))))))
(build-system asdf-build-system/sbcl) (build-system asdf-build-system/sbcl)
(arguments
'(#:special-dependencies '("sb-bsd-sockets")))
(home-page "http://www.cliki.net/portable-clx") (home-page "http://www.cliki.net/portable-clx")
(synopsis "X11 client library for Common Lisp") (synopsis "X11 client library for Common Lisp")
(description "CLX is an X11 client library for Common Lisp. The code was (description "CLX is an X11 client library for Common Lisp. The code was
@ -855,8 +853,7 @@ from other CLXes around the net.")
("sbcl-clx" ,sbcl-clx))) ("sbcl-clx" ,sbcl-clx)))
(outputs '("out" "lib")) (outputs '("out" "lib"))
(arguments (arguments
'(#:special-dependencies '("sb-posix") '(#:phases
#:phases
(modify-phases %standard-phases (modify-phases %standard-phases
(add-after 'create-symlinks 'build-program (add-after 'create-symlinks 'build-program
(lambda* (#:key lisp outputs inputs #:allow-other-keys) (lambda* (#:key lisp outputs inputs #:allow-other-keys)

View File

@ -194,8 +194,7 @@ set up using CL source package conventions."
(define base-arguments (define base-arguments
(if target-is-source? (if target-is-source?
(strip-keyword-arguments (strip-keyword-arguments
'(#:tests? #:special-dependencies #:asd-file '(#:tests? #:asd-file #:lisp)
#:test-only-systems #:lisp)
(package-arguments pkg)) (package-arguments pkg))
(package-arguments pkg))) (package-arguments pkg)))
@ -262,9 +261,7 @@ set up using CL source package conventions."
(lambda* (store name inputs (lambda* (store name inputs
#:key source outputs #:key source outputs
(tests? #t) (tests? #t)
(special-dependencies ''())
(asd-file #f) (asd-file #f)
(test-only-systems ''())
(lisp lisp-implementation) (lisp lisp-implementation)
(phases '(@ (guix build asdf-build-system) (phases '(@ (guix build asdf-build-system)
%standard-phases)) %standard-phases))
@ -284,9 +281,7 @@ set up using CL source package conventions."
((source) source) ((source) source)
(source source)) (source source))
#:lisp ,lisp #:lisp ,lisp
#:special-dependencies ,special-dependencies
#:asd-file ,asd-file #:asd-file ,asd-file
#:test-only-systems ,test-only-systems
#:system ,system #:system ,system
#:tests? ,tests? #:tests? ,tests?
#:phases ,phases #:phases ,phases

View File

@ -21,6 +21,7 @@
#:use-module (guix build utils) #:use-module (guix build utils)
#:use-module (guix build lisp-utils) #:use-module (guix build lisp-utils)
#:use-module (srfi srfi-1) #:use-module (srfi srfi-1)
#:use-module (srfi srfi-11)
#:use-module (srfi srfi-26) #:use-module (srfi srfi-26)
#:use-module (ice-9 rdelim) #:use-module (ice-9 rdelim)
#:use-module (ice-9 receive) #:use-module (ice-9 receive)
@ -161,31 +162,25 @@ valid."
(format #t "test suite not run~%"))) (format #t "test suite not run~%")))
#t) #t)
(define* (patch-asd-files #:key outputs (define* (create-asd-file #:key outputs
inputs inputs
lisp lisp
special-dependencies asd-file
test-only-systems
#:allow-other-keys) #:allow-other-keys)
"Patch any asd files created by the compilation process so that they can "Create a system definition file for the built system."
find their dependencies. Exclude any TEST-ONLY-SYSTEMS which were only (let*-values (((out) (library-output outputs))
included to run tests. Add any SPECIAL-DEPENDENCIES which the LISP ((full-name version) (package-name->name+version
implementation itself provides." (strip-store-file-name out)))
(let* ((out (library-output outputs)) ((name) (remove-lisp-from-name full-name lisp))
(name (remove-lisp-from-name (output-path->package-name out) lisp)) ((new-asd-file) (string-append (library-directory out lisp)
(registry (lset-difference "/" name ".asd")))
(lambda (input system)
(match input
((name . path) (string=? name system))))
(lisp-dependencies lisp inputs)
test-only-systems))
(lisp-systems (map first registry)))
(for-each (make-asd-file new-asd-file
(lambda (asd-file) #:lisp lisp
(patch-asd-file asd-file registry lisp #:system name
(append lisp-systems special-dependencies))) #:version version
(find-files out "\\.asd$"))) #:inputs inputs
#:system-asd-file asd-file))
#t) #t)
(define* (symlink-asd-files #:key outputs lisp #:allow-other-keys) (define* (symlink-asd-files #:key outputs lisp #:allow-other-keys)
@ -193,9 +188,6 @@ implementation itself provides."
(let* ((out (library-output outputs))) (let* ((out (library-output outputs)))
(for-each (for-each
(lambda (asd-file) (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) (receive (new-asd-file asd-file-directory)
(bundle-asd-file out asd-file lisp) (bundle-asd-file out asd-file lisp)
(mkdir-p asd-file-directory) (mkdir-p asd-file-directory)
@ -205,12 +197,11 @@ implementation itself provides."
(prepend-to-source-registry (prepend-to-source-registry
(string-append asd-file-directory "/")))) (string-append asd-file-directory "/"))))
(find-files (string-append out %object-prefix) "\\.asd$")) (find-files (string-append out %object-prefix) "\\.asd$")))
)
#t) #t)
(define* (cleanup-files #:key outputs lisp (define* (cleanup-files #:key outputs lisp
#:allow-other-keys) #:allow-other-keys)
"Remove any compiled files which are not a part of the final bundle." "Remove any compiled files which are not a part of the final bundle."
(let ((out (library-output outputs))) (let ((out (library-output outputs)))
(match lisp (match lisp
@ -261,8 +252,8 @@ implementation itself provides."
(add-before 'build 'copy-source copy-source) (add-before 'build 'copy-source copy-source)
(replace 'check check) (replace 'check check)
(replace 'strip strip) (replace 'strip strip)
(add-after 'check 'link-dependencies patch-asd-files) (add-after 'check 'create-asd-file create-asd-file)
(add-after 'link-dependencies 'cleanup cleanup-files) (add-after 'create-asd-file 'cleanup cleanup-files)
(add-after 'cleanup 'create-symlinks symlink-asd-files))) (add-after 'cleanup 'create-symlinks symlink-asd-files)))
(define* (asdf-build #:key inputs (define* (asdf-build #:key inputs

View File

@ -18,6 +18,7 @@
(define-module (guix build lisp-utils) (define-module (guix build lisp-utils)
#:use-module (ice-9 format) #:use-module (ice-9 format)
#:use-module (ice-9 hash-table)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:use-module (ice-9 regex) #:use-module (ice-9 regex)
#:use-module (srfi srfi-1) #:use-module (srfi srfi-1)
@ -32,15 +33,14 @@
generate-executable-wrapper-system generate-executable-wrapper-system
generate-executable-entry-point generate-executable-entry-point
generate-executable-for-system generate-executable-for-system
patch-asd-file
bundle-install-prefix bundle-install-prefix
lisp-dependencies
bundle-asd-file bundle-asd-file
remove-lisp-from-name remove-lisp-from-name
wrap-output-translations wrap-output-translations
prepend-to-source-registry prepend-to-source-registry
build-program build-program
build-image)) build-image
make-asd-file))
;;; Commentary: ;;; Commentary:
;;; ;;;
@ -64,6 +64,23 @@
(define (remove-lisp-from-name name lisp) (define (remove-lisp-from-name name lisp)
(string-drop name (1+ (string-length lisp)))) (string-drop name (1+ (string-length lisp))))
(define (inputs->asd-file-map inputs lisp)
"Produce a hash table of the form (system . asd-file), where system is the
name of an ASD system, and asd-file is the full path to its definition."
(alist->hash-table
(filter-map
(match-lambda
((_ . path)
(let ((prefix (string-append path (bundle-install-prefix lisp))))
(and (directory-exists? prefix)
(match (find-files prefix "\\.asd$")
((asd-file)
(cons
(string-drop-right (basename asd-file) 4) ; drop ".asd"
asd-file))
(_ #f))))))
inputs)))
(define (wrap-output-translations translations) (define (wrap-output-translations translations)
`(:output-translations `(:output-translations
,@translations ,@translations
@ -80,7 +97,8 @@
with PROGRAM." with PROGRAM."
(match lisp (match lisp
("sbcl" `(,(%lisp) "--non-interactive" "--eval" ,program)) ("sbcl" `(,(%lisp) "--non-interactive" "--eval" ,program))
("ecl" `(,(%lisp) "-eval" ,program "-eval" "(quit)")))) ("ecl" `(,(%lisp) "-eval" ,program "-eval" "(quit)"))
(_ (error "The LISP provided is not supported at this time."))))
(define (asdf-load-all systems) (define (asdf-load-all systems)
(map (lambda (system) (map (lambda (system)
@ -108,15 +126,61 @@ first if SYSTEM is defined there."
(find-symbol (find-symbol
(symbol-name :compile-bundle-op) (symbol-name :compile-bundle-op)
(symbol-name :asdf)) (symbol-name :asdf))
,system)
(funcall (find-symbol
(symbol-name :operate)
(symbol-name :asdf))
(find-symbol
(symbol-name :deliver-asd-op)
(symbol-name :asdf))
,system)))) ,system))))
(define (system-dependencies lisp system asd-file)
"Return the dependencies of SYSTEM, as reported by
asdf:system-depends-on. First load the system's ASD-FILE, if necessary."
(define deps-file ".deps.sexp")
(define program
`(progn
(require :asdf)
,@(if asd-file
`((let ((*package* (find-package :asdf)))
(load ,asd-file)))
'())
(with-open-file
(stream ,deps-file :direction :output)
(format stream
"~s~%"
(funcall
(find-symbol
(symbol-name :system-depends-on)
(symbol-name :asdf))
(funcall
(find-symbol
(symbol-name :find-system)
(symbol-name :asdf))
,system))))))
(dynamic-wind
(lambda _
(lisp-eval-program lisp program))
(lambda _
(call-with-input-file deps-file read))
(lambda _
(when (file-exists? deps-file)
(delete-file deps-file)))))
(define (compiled-system system lisp)
(match lisp
("sbcl" (string-append system "--system"))
(_ system)))
(define* (generate-system-definition lisp system
#:key version dependencies)
`(asdf:defsystem
,system
:class asdf/bundle:prebuilt-system
:version ,version
:depends-on ,dependencies
:components ((:compiled-file ,(compiled-system system lisp)))
,@(if (string=? "ecl" lisp)
`(:lib ,(string-append system ".a"))
'())))
(define (test-system system lisp asd-file) (define (test-system system lisp asd-file)
"Use a lisp implementation to test SYSTEM using asdf. Load ASD-FILE first "Use a lisp implementation to test SYSTEM using asdf. Load ASD-FILE first
if SYSTEM is defined there." if SYSTEM is defined there."
@ -185,58 +249,53 @@ ENTRY-PROGRAM for SYSTEM within the current directory."
(declare (ignorable arguments)) (declare (ignorable arguments))
,@entry-program)))))))) ,@entry-program))))))))
(define (wrap-perform-method lisp registry dependencies file-name) (define (generate-dependency-links lisp registry system)
"Creates a wrapper method which allows the system to locate its dependent "Creates a program which populates asdf's source registry from REGISTRY, an
systems from REGISTRY, an alist of the same form as %outputs, which contains alist of dependency names to corresponding asd files. This allows the system
lisp systems which the systems is dependent on. All DEPENDENCIES which the to locate its dependent systems."
system depends on will the be loaded before this system." `(progn
(let* ((system (string-drop-right (basename file-name) 4)) (asdf/source-registry:ensure-source-registry)
(system-symbol (string->lisp-keyword system))) ,@(map (match-lambda
((name . asd-file)
`(setf
(gethash ,name
asdf/source-registry:*source-registry*)
,(string->symbol "#p")
,asd-file)))
registry)))
`(defmethod asdf:perform :before (define* (make-asd-file asd-file
(op (c (eql (asdf:find-system ,system-symbol)))) #:key lisp system version inputs
(asdf/source-registry:ensure-source-registry) (system-asd-file #f))
,@(map (match-lambda "Create an ASD-FILE for SYSTEM@VERSION, appending a program to allow the
((name . path) system to find its dependencies, as described by GENERATE-DEPENDENCY-LINKS."
(let ((asd-file (string-append path (define dependencies
(bundle-install-prefix lisp) (parameterize ((%lisp (string-append (assoc-ref inputs lisp) "/bin/" lisp)))
"/" name ".asd"))) (system-dependencies lisp system system-asd-file)))
`(setf
(gethash ,name
asdf/source-registry:*source-registry*)
,(string->symbol "#p")
,(bundle-asd-file path asd-file lisp)))))
registry)
,@(map (lambda (system)
`(asdf:load-system ,(string->lisp-keyword system)))
dependencies))))
(define (patch-asd-file asd-file registry lisp dependencies) (define lisp-input-map
"Patches ASD-FILE with a perform method as described in WRAP-PERFORM-METHOD." (inputs->asd-file-map inputs lisp))
(chmod asd-file #o644)
(let ((port (open-file asd-file "a")))
(dynamic-wind
(lambda _ #t)
(lambda _
(display
(replace-escaped-macros
(format #f "~%~y~%"
(wrap-perform-method lisp registry
dependencies asd-file)))
port))
(lambda _ (close-port port))))
(chmod asd-file #o444))
(define (lisp-dependencies lisp inputs) (define registry
"Determine which inputs are lisp system dependencies, by using the convention (filter-map hash-get-handle
that a lisp system dependency will resemble \"system-LISP\"." (make-list (if (eq? 'NIL dependencies)
(filter-map (match-lambda 0
((name . value) (length dependencies))
(and (string-prefix? lisp name) lisp-input-map)
(string<> lisp name) (if (eq? 'NIL dependencies)
`(,(remove-lisp-from-name name lisp) '()
. ,value)))) dependencies)))
inputs))
(call-with-output-file asd-file
(lambda (port)
(display
(replace-escaped-macros
(format #f "~y~%~y~%"
(generate-system-definition lisp system
#:version version
#:dependencies dependencies)
(generate-dependency-links lisp registry system)))
port))))
(define (bundle-asd-file output-path original-asd-file lisp) (define (bundle-asd-file output-path original-asd-file lisp)
"Find the symlinked bundle file for ORIGINAL-ASD-FILE by looking in "Find the symlinked bundle file for ORIGINAL-ASD-FILE by looking in