diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2020-03-06 11:25:43 +0100 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2020-03-12 18:32:15 +0100 |
| commit | cf2ac04f13d9266c7c8a2ebd2e85ef593231ac9d (patch) | |
| tree | 409921980504c7138e4dac8769823fb50becc516 | |
| parent | be78906592c761aa2a67e979074561e459efdcac (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.el | 1 | ||||
| -rw-r--r-- | doc/guix.texi | 19 | ||||
| -rw-r--r-- | guix/gexp.scm | 59 | ||||
| -rw-r--r-- | tests/gexp.scm | 38 |
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} | ||
| 8026 | This macro is similar to the @code{parameterize} form for | ||
| 8027 | dynamically-bound @dfn{parameters} (@pxref{Parameters,,, guile, GNU | ||
| 8028 | Guile Reference Manual}). The key difference is that it takes effect | ||
| 8029 | when the file-like object returned by @var{exp} is lowered to a | ||
| 8030 | derivation or store item. | ||
| 8031 | |||
| 8032 | A typical use of @code{with-parameters} is to force the system in effect | ||
| 8033 | for a given object: | ||
| 8034 | |||
| 8035 | @lisp | ||
| 8036 | (with-parameters ((%current-system "i686-linux")) | ||
| 8037 | coreutils) | ||
| 8038 | @end lisp | ||
| 8039 | |||
| 8040 | The example above returns an object that corresponds to the i686 build | ||
| 8041 | of Coreutils, regardless of the current value of @code{%current-system}. | ||
| 8042 | @end deffn | ||
| 8043 | |||
| 8025 | 8044 | ||
| 8026 | Of course, in addition to gexps embedded in ``host'' code, there are | 8045 | Of course, in addition to gexps embedded in ``host'' code, there are |
| 8027 | also modules containing build tools. To make it clear that they are | 8046 | also 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 | ||
| 539 | is lowered. Consider this example: | ||
| 540 | |||
| 541 | (with-parameters ((%current-system \"x86_64-linux\")) | ||
| 542 | coreutils) | ||
| 543 | |||
| 544 | It returns a <parameterized> object that ensures %CURRENT-SYSTEM is set to | ||
| 545 | x86_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) |
