summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2017-11-14 10:16:22 +0100
committerLudovic Courtès <ludo@gnu.org>2020-05-16 00:34:41 +0200
commit644cb40cd83eff8a5bcdbd2d63887daa18228f41 (patch)
treee470f35ad20a8ad6805d2a8e7b03897bc10f6098
parentd03001a31a6d460b712825640dba11e3f1a53a14 (diff)
gexp: Add 'let-system'.
* guix/gexp.scm (<system-binding>): New record type. (let-system): New macro. (system-binding-compiler): New procedure. (default-expander): Add 'self-quoting?' case. (self-quoting?): New procedure. (lower-inputs): Add 'filterm'. Pass the result of 'mapm/accumulate-builds' through FILTERM. (gexp->sexp)[self-quoting?]: Remove. * tests/gexp.scm ("let-system", "let-system, target") ("let-system, ungexp-native, target") ("let-system, nested"): New tests. * doc/guix.texi (G-Expressions): Document it.
-rw-r--r--.dir-locals.el1
-rw-r--r--doc/guix.texi26
-rw-r--r--guix/gexp.scm110
-rw-r--r--tests/gexp.scm54
4 files changed, 165 insertions, 26 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
index ce305602f23..fcde914e602 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -85,6 +85,7 @@
85 (eval . (put 'with-imported-modules 'scheme-indent-function 1)) 85 (eval . (put 'with-imported-modules 'scheme-indent-function 1))
86 (eval . (put 'with-extensions 'scheme-indent-function 1)) 86 (eval . (put 'with-extensions 'scheme-indent-function 1))
87 (eval . (put 'with-parameters 'scheme-indent-function 1)) 87 (eval . (put 'with-parameters 'scheme-indent-function 1))
88 (eval . (put 'let-system 'scheme-indent-function 1))
88 89
89 (eval . (put 'with-database 'scheme-indent-function 2)) 90 (eval . (put 'with-database 'scheme-indent-function 2))
90 (eval . (put 'call-with-transaction 'scheme-indent-function 2)) 91 (eval . (put 'call-with-transaction 'scheme-indent-function 2))
diff --git a/doc/guix.texi b/doc/guix.texi
index a36b9691fbc..d043852ac3c 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -8123,6 +8123,32 @@ the second case, the resulting script contains a @code{(string-append
8123@dots{})} expression to construct the file name @emph{at run time}. 8123@dots{})} expression to construct the file name @emph{at run time}.
8124@end deffn 8124@end deffn
8125 8125
8126@deffn {Scheme Syntax} let-system @var{system} @var{body}@dots{}
8127@deffnx {Scheme Syntax} let-system (@var{system} @var{target}) @var{body}@dots{}
8128Bind @var{system} to the currently targeted system---e.g.,
8129@code{"x86_64-linux"}---within @var{body}.
8130
8131In the second case, additionally bind @var{target} to the current
8132cross-compilation target---a GNU triplet such as
8133@code{"arm-linux-gnueabihf"}---or @code{#f} if we are not
8134cross-compiling.
8135
8136@code{let-system} is useful in the occasional case where the object
8137spliced into the gexp depends on the target system, as in this example:
8138
8139@example
8140#~(system*
8141 #+(let-system system
8142 (cond ((string-prefix? "armhf-" system)
8143 (file-append qemu "/bin/qemu-system-arm"))
8144 ((string-prefix? "x86_64-" system)
8145 (file-append qemu "/bin/qemu-system-x86_64"))
8146 (else
8147 (error "dunno!"))))
8148 "-net" "user" #$image)
8149@end example
8150@end deffn
8151
8126@deffn {Scheme Syntax} with-parameters ((@var{parameter} @var{value}) @dots{}) @var{exp} 8152@deffn {Scheme Syntax} with-parameters ((@var{parameter} @var{value}) @dots{}) @var{exp}
8127This macro is similar to the @code{parameterize} form for 8153This macro is similar to the @code{parameterize} form for
8128dynamically-bound @dfn{parameters} (@pxref{Parameters,,, guile, GNU 8154dynamically-bound @dfn{parameters} (@pxref{Parameters,,, guile, GNU
diff --git a/guix/gexp.scm b/guix/gexp.scm
index 5c614f3e127..78b8af6fbcb 100644
--- a/guix/gexp.scm
+++ b/guix/gexp.scm
@@ -37,6 +37,7 @@
37 gexp? 37 gexp?
38 with-imported-modules 38 with-imported-modules
39 with-extensions 39 with-extensions
40 let-system
40 41
41 gexp-input 42 gexp-input
42 gexp-input? 43 gexp-input?
@@ -195,7 +196,9 @@ returns its output file name of OBJ's OUTPUT."
195 ((? derivation? drv) 196 ((? derivation? drv)
196 (derivation->output-path drv output)) 197 (derivation->output-path drv output))
197 ((? string? file) 198 ((? string? file)
198 file))) 199 file)
200 ((? self-quoting? obj)
201 obj)))
199 202
200(define (register-compiler! compiler) 203(define (register-compiler! compiler)
201 "Register COMPILER as a gexp compiler." 204 "Register COMPILER as a gexp compiler."
@@ -329,6 +332,52 @@ The expander specifies how an object is converted to its sexp representation."
329 332
330 333
331;;; 334;;;
335;;; System dependencies.
336;;;
337
338;; Binding form for the current system and cross-compilation target.
339(define-record-type <system-binding>
340 (system-binding proc)
341 system-binding?
342 (proc system-binding-proc))
343
344(define-syntax let-system
345 (syntax-rules ()
346 "Introduce a system binding in a gexp. The simplest form is:
347
348 (let-system system
349 (cond ((string=? system \"x86_64-linux\") ...)
350 (else ...)))
351
352which binds SYSTEM to the currently targeted system. The second form is
353similar, but it also shows the cross-compilation target:
354
355 (let-system (system target)
356 ...)
357
358Here TARGET is bound to the cross-compilation triplet or #f."
359 ((_ (system target) exp0 exp ...)
360 (system-binding (lambda (system target)
361 exp0 exp ...)))
362 ((_ system exp0 exp ...)
363 (system-binding (lambda (system target)
364 exp0 exp ...)))))
365
366(define-gexp-compiler system-binding-compiler <system-binding>
367 compiler => (lambda (binding system target)
368 (match binding
369 (($ <system-binding> proc)
370 (with-monad %store-monad
371 ;; PROC is expected to return a lowerable object.
372 ;; 'lower-object' takes care of residualizing it to a
373 ;; derivation or similar.
374 (return (proc system target))))))
375
376 ;; Delegate to the expander of the object returned by PROC.
377 expander => #f)
378
379
380;;;
332;;; File declarations. 381;;; File declarations.
333;;; 382;;;
334 383
@@ -706,6 +755,15 @@ GEXP) is false, meaning that GEXP is a plain Scheme object, return the empty
706list." 755list."
707 (gexp-attribute gexp gexp-self-extensions)) 756 (gexp-attribute gexp gexp-self-extensions))
708 757
758(define (self-quoting? x)
759 (letrec-syntax ((one-of (syntax-rules ()
760 ((_) #f)
761 ((_ pred rest ...)
762 (or (pred x)
763 (one-of rest ...))))))
764 (one-of symbol? string? keyword? pair? null? array?
765 number? boolean? char?)))
766
709(define* (lower-inputs inputs 767(define* (lower-inputs inputs
710 #:key system target) 768 #:key system target)
711 "Turn any object from INPUTS into a derivation input for SYSTEM or a store 769 "Turn any object from INPUTS into a derivation input for SYSTEM or a store
@@ -714,23 +772,32 @@ When TARGET is true, use it as the cross-compilation target triplet."
714 (define (store-item? obj) 772 (define (store-item? obj)
715 (and (string? obj) (store-path? obj))) 773 (and (string? obj) (store-path? obj)))
716 774
775 (define filterm
776 (lift1 (cut filter ->bool <>) %store-monad))
777
717 (with-monad %store-monad 778 (with-monad %store-monad
718 (mapm/accumulate-builds 779 (>>= (mapm/accumulate-builds
719 (match-lambda 780 (match-lambda
720 (((? struct? thing) sub-drv ...) 781 (((? struct? thing) sub-drv ...)
721 (mlet %store-monad ((obj (lower-object 782 (mlet %store-monad ((obj (lower-object
722 thing system #:target target))) 783 thing system #:target target)))
723 (return (match obj 784 (return (match obj
724 ((? derivation? drv) 785 ((? derivation? drv)
725 (let ((outputs (if (null? sub-drv) 786 (let ((outputs (if (null? sub-drv)
726 '("out") 787 '("out")
727 sub-drv))) 788 sub-drv)))
728 (derivation-input drv outputs))) 789 (derivation-input drv outputs)))
729 ((? store-item? item) 790 ((? store-item? item)
730 item))))) 791 item)
731 (((? store-item? item)) 792 ((? self-quoting?)
732 (return item))) 793 ;; Some inputs such as <system-binding> can lower to
733 inputs))) 794 ;; a self-quoting object that FILTERM will filter
795 ;; out.
796 #f)))))
797 (((? store-item? item))
798 (return item)))
799 inputs)
800 filterm)))
734 801
735(define* (lower-reference-graphs graphs #:key system target) 802(define* (lower-reference-graphs graphs #:key system target)
736 "Given GRAPHS, a list of (FILE-NAME INPUT ...) lists for use as a 803 "Given GRAPHS, a list of (FILE-NAME INPUT ...) lists for use as a
@@ -1146,15 +1213,6 @@ references; otherwise, return only non-native references."
1146 (target (%current-target-system))) 1213 (target (%current-target-system)))
1147 "Return (monadically) the sexp corresponding to EXP for the given OUTPUT, 1214 "Return (monadically) the sexp corresponding to EXP for the given OUTPUT,
1148and in the current monad setting (system type, etc.)" 1215and in the current monad setting (system type, etc.)"
1149 (define (self-quoting? x)
1150 (letrec-syntax ((one-of (syntax-rules ()
1151 ((_) #f)
1152 ((_ pred rest ...)
1153 (or (pred x)
1154 (one-of rest ...))))))
1155 (one-of symbol? string? keyword? pair? null? array?
1156 number? boolean? char?)))
1157
1158 (define* (reference->sexp ref #:optional native?) 1216 (define* (reference->sexp ref #:optional native?)
1159 (with-monad %store-monad 1217 (with-monad %store-monad
1160 (match ref 1218 (match ref
diff --git a/tests/gexp.scm b/tests/gexp.scm
index 6a42d3eb57b..e073a7b8167 100644
--- a/tests/gexp.scm
+++ b/tests/gexp.scm
@@ -321,6 +321,60 @@
321 (string=? result 321 (string=? result
322 (string-append (derivation->output-path drv) 322 (string-append (derivation->output-path drv)
323 "/bin/touch")))))) 323 "/bin/touch"))))))
324(test-equal "let-system"
325 (list `(begin ,(%current-system) #t) '(system-binding) '()
326 'low '() '())
327 (let* ((exp #~(begin
328 #$(let-system system system)
329 #t))
330 (low (run-with-store %store (lower-gexp exp))))
331 (list (lowered-gexp-sexp low)
332 (match (gexp-inputs exp)
333 (((($ (@@ (guix gexp) <system-binding>)) "out"))
334 '(system-binding))
335 (x x))
336 (gexp-native-inputs exp)
337 'low
338 (lowered-gexp-inputs low)
339 (lowered-gexp-sources low))))
340
341(test-equal "let-system, target"
342 (list `(list ,(%current-system) #f)
343 `(list ,(%current-system) "aarch64-linux-gnu"))
344 (let ((exp #~(list #$@(let-system (system target)
345 (list system target)))))
346 (list (gexp->sexp* exp)
347 (gexp->sexp* exp "aarch64-linux-gnu"))))
348
349(test-equal "let-system, ungexp-native, target"
350 `(here it is: ,(%current-system) #f)
351 (let ((exp #~(here it is: #+@(let-system (system target)
352 (list system target)))))
353 (gexp->sexp* exp "aarch64-linux-gnu")))
354
355(test-equal "let-system, nested"
356 (list `(system* ,(string-append "qemu-system-" (%current-system))
357 "-m" "256")
358 '()
359 '(system-binding))
360 (let ((exp #~(system*
361 #+(let-system (system target)
362 (file-append (@@ (gnu packages virtualization)
363 qemu)
364 "/bin/qemu-system-"
365 system))
366 "-m" "256")))
367 (list (match (gexp->sexp* exp)
368 (('system* command rest ...)
369 `(system* ,(and (string-prefix? (%store-prefix) command)
370 (basename command))
371 ,@rest))
372 (x x))
373 (gexp-inputs exp)
374 (match (gexp-native-inputs exp)
375 (((($ (@@ (guix gexp) <system-binding>)) "out"))
376 '(system-binding))
377 (x x)))))
324 378
325(test-assert "ungexp + ungexp-native" 379(test-assert "ungexp + ungexp-native"
326 (let* ((exp (gexp (list (ungexp-native %bootstrap-guile) 380 (let* ((exp (gexp (list (ungexp-native %bootstrap-guile)