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.master
parent
be78906592
commit
cf2ac04f13
|
@ -83,6 +83,7 @@
|
||||||
(eval . (put 'wrap-program 'scheme-indent-function 1))
|
(eval . (put 'wrap-program 'scheme-indent-function 1))
|
||||||
(eval . (put 'with-imported-modules 'scheme-indent-function 1))
|
(eval . (put 'with-imported-modules 'scheme-indent-function 1))
|
||||||
(eval . (put 'with-extensions 'scheme-indent-function 1))
|
(eval . (put 'with-extensions 'scheme-indent-function 1))
|
||||||
|
(eval . (put 'with-parameters 'scheme-indent-function 1))
|
||||||
|
|
||||||
(eval . (put 'with-database 'scheme-indent-function 2))
|
(eval . (put 'with-database 'scheme-indent-function 2))
|
||||||
(eval . (put 'call-with-transaction 'scheme-indent-function 2))
|
(eval . (put 'call-with-transaction 'scheme-indent-function 2))
|
||||||
|
|
|
@ -8022,6 +8022,25 @@ the second case, the resulting script contains a @code{(string-append
|
||||||
@dots{})} expression to construct the file name @emph{at run time}.
|
@dots{})} expression to construct the file name @emph{at run time}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Syntax} with-parameters ((@var{parameter} @var{value}) @dots{}) @var{exp}
|
||||||
|
This macro is similar to the @code{parameterize} form for
|
||||||
|
dynamically-bound @dfn{parameters} (@pxref{Parameters,,, guile, GNU
|
||||||
|
Guile Reference Manual}). The key difference is that it takes effect
|
||||||
|
when the file-like object returned by @var{exp} is lowered to a
|
||||||
|
derivation or store item.
|
||||||
|
|
||||||
|
A typical use of @code{with-parameters} is to force the system in effect
|
||||||
|
for a given object:
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
(with-parameters ((%current-system "i686-linux"))
|
||||||
|
coreutils)
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
The example above returns an object that corresponds to the i686 build
|
||||||
|
of Coreutils, regardless of the current value of @code{%current-system}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
|
||||||
Of course, in addition to gexps embedded in ``host'' code, there are
|
Of course, in addition to gexps embedded in ``host'' code, there are
|
||||||
also modules containing build tools. To make it clear that they are
|
also modules containing build tools. To make it clear that they are
|
||||||
|
|
|
@ -82,6 +82,9 @@
|
||||||
raw-derivation-file
|
raw-derivation-file
|
||||||
raw-derivation-file?
|
raw-derivation-file?
|
||||||
|
|
||||||
|
with-parameters
|
||||||
|
parameterized?
|
||||||
|
|
||||||
load-path-expression
|
load-path-expression
|
||||||
gexp-modules
|
gexp-modules
|
||||||
|
|
||||||
|
@ -523,6 +526,62 @@ SUFFIX."
|
||||||
(base (expand base lowered output)))
|
(base (expand base lowered output)))
|
||||||
(string-append base (string-concatenate suffix)))))))
|
(string-append base (string-concatenate suffix)))))))
|
||||||
|
|
||||||
|
;; Representation of SRFI-39 parameter settings in the dynamic scope of an
|
||||||
|
;; object lowering.
|
||||||
|
(define-record-type <parameterized>
|
||||||
|
(parameterized bindings thunk)
|
||||||
|
parameterized?
|
||||||
|
(bindings parameterized-bindings) ;list of parameter/value pairs
|
||||||
|
(thunk parameterized-thunk)) ;thunk
|
||||||
|
|
||||||
|
(define-syntax-rule (with-parameters ((param value) ...) body ...)
|
||||||
|
"Bind each PARAM to the corresponding VALUE for the extent during which BODY
|
||||||
|
is lowered. Consider this example:
|
||||||
|
|
||||||
|
(with-parameters ((%current-system \"x86_64-linux\"))
|
||||||
|
coreutils)
|
||||||
|
|
||||||
|
It returns a <parameterized> object that ensures %CURRENT-SYSTEM is set to
|
||||||
|
x86_64-linux when COREUTILS is lowered."
|
||||||
|
(parameterized (list (list param (lambda () value)) ...)
|
||||||
|
(lambda ()
|
||||||
|
body ...)))
|
||||||
|
|
||||||
|
(define-gexp-compiler compile-parameterized <parameterized>
|
||||||
|
compiler =>
|
||||||
|
(lambda (parameterized system target)
|
||||||
|
(match (parameterized-bindings parameterized)
|
||||||
|
(((parameters values) ...)
|
||||||
|
(let ((fluids (map parameter-fluid parameters))
|
||||||
|
(thunk (parameterized-thunk parameterized)))
|
||||||
|
;; Install the PARAMETERS for the dynamic extent of THUNK.
|
||||||
|
(with-fluids* fluids
|
||||||
|
(map (lambda (thunk) (thunk)) values)
|
||||||
|
(lambda ()
|
||||||
|
;; Special-case '%current-system' and '%current-target-system' to
|
||||||
|
;; make sure we get the desired effect.
|
||||||
|
(let ((system (if (memq %current-system parameters)
|
||||||
|
(%current-system)
|
||||||
|
system))
|
||||||
|
(target (if (memq %current-target-system parameters)
|
||||||
|
(%current-target-system)
|
||||||
|
target)))
|
||||||
|
(lower-object (thunk) system #:target target))))))))
|
||||||
|
|
||||||
|
expander => (lambda (parameterized lowered output)
|
||||||
|
(match (parameterized-bindings parameterized)
|
||||||
|
(((parameters values) ...)
|
||||||
|
(let ((fluids (map parameter-fluid parameters))
|
||||||
|
(thunk (parameterized-thunk parameterized)))
|
||||||
|
;; Install the PARAMETERS for the dynamic extent of THUNK.
|
||||||
|
(with-fluids* fluids
|
||||||
|
(map (lambda (thunk) (thunk)) values)
|
||||||
|
(lambda ()
|
||||||
|
;; Delegate to the expander of the wrapped object.
|
||||||
|
(let* ((base (thunk))
|
||||||
|
(expand (lookup-expander base)))
|
||||||
|
(expand base lowered output)))))))))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; Inputs & outputs.
|
;;; Inputs & outputs.
|
||||||
|
|
|
@ -284,6 +284,44 @@
|
||||||
(((thing "out"))
|
(((thing "out"))
|
||||||
(eq? thing file))))))
|
(eq? thing file))))))
|
||||||
|
|
||||||
|
(test-assertm "with-parameters for %current-system"
|
||||||
|
(mlet* %store-monad ((system -> (match (%current-system)
|
||||||
|
("aarch64-linux" "x86_64-linux")
|
||||||
|
(_ "aarch64-linux")))
|
||||||
|
(drv (package->derivation coreutils system))
|
||||||
|
(obj -> (with-parameters ((%current-system system))
|
||||||
|
coreutils))
|
||||||
|
(result (lower-object obj)))
|
||||||
|
(return (string=? (derivation-file-name drv)
|
||||||
|
(derivation-file-name result)))))
|
||||||
|
|
||||||
|
(test-assertm "with-parameters for %current-target-system"
|
||||||
|
(mlet* %store-monad ((target -> "riscv64-linux-gnu")
|
||||||
|
(drv (package->cross-derivation coreutils target))
|
||||||
|
(obj -> (with-parameters
|
||||||
|
((%current-target-system target))
|
||||||
|
coreutils))
|
||||||
|
(result (lower-object obj)))
|
||||||
|
(return (string=? (derivation-file-name drv)
|
||||||
|
(derivation-file-name result)))))
|
||||||
|
|
||||||
|
(test-assert "with-parameters + file-append"
|
||||||
|
(let* ((system (match (%current-system)
|
||||||
|
("aarch64-linux" "x86_64-linux")
|
||||||
|
(_ "aarch64-linux")))
|
||||||
|
(drv (package-derivation %store coreutils system))
|
||||||
|
(param (make-parameter 7))
|
||||||
|
(exp #~(here we go #$(with-parameters ((%current-system system)
|
||||||
|
(param 42))
|
||||||
|
(if (= (param) 42)
|
||||||
|
(file-append coreutils "/bin/touch")
|
||||||
|
%bootstrap-guile)))))
|
||||||
|
(match (gexp->sexp* exp)
|
||||||
|
(('here 'we 'go (? string? result))
|
||||||
|
(string=? result
|
||||||
|
(string-append (derivation->output-path drv)
|
||||||
|
"/bin/touch"))))))
|
||||||
|
|
||||||
(test-assert "ungexp + ungexp-native"
|
(test-assert "ungexp + ungexp-native"
|
||||||
(let* ((exp (gexp (list (ungexp-native %bootstrap-guile)
|
(let* ((exp (gexp (list (ungexp-native %bootstrap-guile)
|
||||||
(ungexp coreutils)
|
(ungexp coreutils)
|
||||||
|
|
Reference in New Issue