summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2020-03-06 11:25:43 +0100
committerLudovic Courtès <ludo@gnu.org>2020-03-12 18:32:15 +0100
commitcf2ac04f13d9266c7c8a2ebd2e85ef593231ac9d (patch)
tree409921980504c7138e4dac8769823fb50becc516
parentbe78906592c761aa2a67e979074561e459efdcac (diff)
gexp: Add 'with-parameters'.
* guix/gexp.scm (<parameterized>): New record type. (with-parameters): New macro. (compile-parameterized): New gexp compiler. * tests/gexp.scm ("with-parameters for %current-system") ("with-parameters for %current-target-system") ("with-parameters + file-append"): New tests. * doc/guix.texi (G-Expressions): Document it.
-rw-r--r--.dir-locals.el1
-rw-r--r--doc/guix.texi19
-rw-r--r--guix/gexp.scm59
-rw-r--r--tests/gexp.scm38
4 files changed, 117 insertions, 0 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
index 5ce3fbc9a51..1976f7e60d7 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -83,6 +83,7 @@
83 (eval . (put 'wrap-program 'scheme-indent-function 1)) 83 (eval . (put 'wrap-program 'scheme-indent-function 1))
84 (eval . (put 'with-imported-modules 'scheme-indent-function 1)) 84 (eval . (put 'with-imported-modules 'scheme-indent-function 1))
85 (eval . (put 'with-extensions 'scheme-indent-function 1)) 85 (eval . (put 'with-extensions 'scheme-indent-function 1))
86 (eval . (put 'with-parameters 'scheme-indent-function 1))
86 87
87 (eval . (put 'with-database 'scheme-indent-function 2)) 88 (eval . (put 'with-database 'scheme-indent-function 2))
88 (eval . (put 'call-with-transaction 'scheme-indent-function 2)) 89 (eval . (put 'call-with-transaction 'scheme-indent-function 2))
diff --git a/doc/guix.texi b/doc/guix.texi
index dd32b65fe07..4f8f7cfb2aa 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -8022,6 +8022,25 @@ the second case, the resulting script contains a @code{(string-append
8022@dots{})} expression to construct the file name @emph{at run time}. 8022@dots{})} expression to construct the file name @emph{at run time}.
8023@end deffn 8023@end deffn
8024 8024
8025@deffn {Scheme Syntax} with-parameters ((@var{parameter} @var{value}) @dots{}) @var{exp}
8026This macro is similar to the @code{parameterize} form for
8027dynamically-bound @dfn{parameters} (@pxref{Parameters,,, guile, GNU
8028Guile Reference Manual}). The key difference is that it takes effect
8029when the file-like object returned by @var{exp} is lowered to a
8030derivation or store item.
8031
8032A typical use of @code{with-parameters} is to force the system in effect
8033for a given object:
8034
8035@lisp
8036(with-parameters ((%current-system "i686-linux"))
8037 coreutils)
8038@end lisp
8039
8040The example above returns an object that corresponds to the i686 build
8041of Coreutils, regardless of the current value of @code{%current-system}.
8042@end deffn
8043
8025 8044
8026Of course, in addition to gexps embedded in ``host'' code, there are 8045Of course, in addition to gexps embedded in ``host'' code, there are
8027also modules containing build tools. To make it clear that they are 8046also modules containing build tools. To make it clear that they are
diff --git a/guix/gexp.scm b/guix/gexp.scm
index a657921741c..133e0f56794 100644
--- a/guix/gexp.scm
+++ b/guix/gexp.scm
@@ -82,6 +82,9 @@
82 raw-derivation-file 82 raw-derivation-file
83 raw-derivation-file? 83 raw-derivation-file?
84 84
85 with-parameters
86 parameterized?
87
85 load-path-expression 88 load-path-expression
86 gexp-modules 89 gexp-modules
87 90
@@ -523,6 +526,62 @@ SUFFIX."
523 (base (expand base lowered output))) 526 (base (expand base lowered output)))
524 (string-append base (string-concatenate suffix))))))) 527 (string-append base (string-concatenate suffix)))))))
525 528
529;; Representation of SRFI-39 parameter settings in the dynamic scope of an
530;; object lowering.
531(define-record-type <parameterized>
532 (parameterized bindings thunk)
533 parameterized?
534 (bindings parameterized-bindings) ;list of parameter/value pairs
535 (thunk parameterized-thunk)) ;thunk
536
537(define-syntax-rule (with-parameters ((param value) ...) body ...)
538 "Bind each PARAM to the corresponding VALUE for the extent during which BODY
539is lowered. Consider this example:
540
541 (with-parameters ((%current-system \"x86_64-linux\"))
542 coreutils)
543
544It returns a <parameterized> object that ensures %CURRENT-SYSTEM is set to
545x86_64-linux when COREUTILS is lowered."
546 (parameterized (list (list param (lambda () value)) ...)
547 (lambda ()
548 body ...)))
549
550(define-gexp-compiler compile-parameterized <parameterized>
551 compiler =>
552 (lambda (parameterized system target)
553 (match (parameterized-bindings parameterized)
554 (((parameters values) ...)
555 (let ((fluids (map parameter-fluid parameters))
556 (thunk (parameterized-thunk parameterized)))
557 ;; Install the PARAMETERS for the dynamic extent of THUNK.
558 (with-fluids* fluids
559 (map (lambda (thunk) (thunk)) values)
560 (lambda ()
561 ;; Special-case '%current-system' and '%current-target-system' to
562 ;; make sure we get the desired effect.
563 (let ((system (if (memq %current-system parameters)
564 (%current-system)
565 system))
566 (target (if (memq %current-target-system parameters)
567 (%current-target-system)
568 target)))
569 (lower-object (thunk) system #:target target))))))))
570
571 expander => (lambda (parameterized lowered output)
572 (match (parameterized-bindings parameterized)
573 (((parameters values) ...)
574 (let ((fluids (map parameter-fluid parameters))
575 (thunk (parameterized-thunk parameterized)))
576 ;; Install the PARAMETERS for the dynamic extent of THUNK.
577 (with-fluids* fluids
578 (map (lambda (thunk) (thunk)) values)
579 (lambda ()
580 ;; Delegate to the expander of the wrapped object.
581 (let* ((base (thunk))
582 (expand (lookup-expander base)))
583 (expand base lowered output)))))))))
584
526 585
527;;; 586;;;
528;;; Inputs & outputs. 587;;; Inputs & outputs.
diff --git a/tests/gexp.scm b/tests/gexp.scm
index 9e38816c3dc..6a42d3eb57b 100644
--- a/tests/gexp.scm
+++ b/tests/gexp.scm
@@ -284,6 +284,44 @@
284 (((thing "out")) 284 (((thing "out"))
285 (eq? thing file)))))) 285 (eq? thing file))))))
286 286
287(test-assertm "with-parameters for %current-system"
288 (mlet* %store-monad ((system -> (match (%current-system)
289 ("aarch64-linux" "x86_64-linux")
290 (_ "aarch64-linux")))
291 (drv (package->derivation coreutils system))
292 (obj -> (with-parameters ((%current-system system))
293 coreutils))
294 (result (lower-object obj)))
295 (return (string=? (derivation-file-name drv)
296 (derivation-file-name result)))))
297
298(test-assertm "with-parameters for %current-target-system"
299 (mlet* %store-monad ((target -> "riscv64-linux-gnu")
300 (drv (package->cross-derivation coreutils target))
301 (obj -> (with-parameters
302 ((%current-target-system target))
303 coreutils))
304 (result (lower-object obj)))
305 (return (string=? (derivation-file-name drv)
306 (derivation-file-name result)))))
307
308(test-assert "with-parameters + file-append"
309 (let* ((system (match (%current-system)
310 ("aarch64-linux" "x86_64-linux")
311 (_ "aarch64-linux")))
312 (drv (package-derivation %store coreutils system))
313 (param (make-parameter 7))
314 (exp #~(here we go #$(with-parameters ((%current-system system)
315 (param 42))
316 (if (= (param) 42)
317 (file-append coreutils "/bin/touch")
318 %bootstrap-guile)))))
319 (match (gexp->sexp* exp)
320 (('here 'we 'go (? string? result))
321 (string=? result
322 (string-append (derivation->output-path drv)
323 "/bin/touch"))))))
324
287(test-assert "ungexp + ungexp-native" 325(test-assert "ungexp + ungexp-native"
288 (let* ((exp (gexp (list (ungexp-native %bootstrap-guile) 326 (let* ((exp (gexp (list (ungexp-native %bootstrap-guile)
289 (ungexp coreutils) 327 (ungexp coreutils)