guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

01/15: build-system: Rewrite using gexps.


From: guix-commits
Subject: 01/15: build-system: Rewrite using gexps.
Date: Tue, 23 Feb 2021 08:33:59 -0500 (EST)

civodul pushed a commit to branch wip-build-systems-gexp
in repository guix.

commit 27e1faa57152f577841ccbcf4db5aee027ce2f6d
Author: Ludovic Courtès <ludo@gnu.org>
AuthorDate: Sat Mar 28 19:26:39 2015 +0100

    build-system: Rewrite using gexps.
    
    * guix/packages.scm (expand-input): Remove 'store', 'system', and
      'cross-system' parameters; add #:native?.  Rewrite to return
      name/gexp-input tuples.
      (bag->derivation): Adjust accordingly.  Lower (bag-build bag).
      (bag->cross-derivation): Ditto.  Instead of #:native-drvs and
      #:target-drvs, pass #:build-inputs, #:host-inputs, and #:target-inputs.
      (%derivation-cache): Remove.
    * guix/gexp.scm (with-build-variables): New procedure.
    * gnu/packages/bootstrap.scm (raw-build): Turn into a monadic procedure.
    * gnu/packages/commencement.scm (glibc-final)[arguments]: Use
      'gexp-input' for the #:allowed-references argument.
    * guix/build-system/cmake.scm (cmake-build): Remove 'store' parameter.
      Switch to the use of gexps and 'gexp->derivation'.
      (lower): Remove #:source from 'private-keywords'.
    * guix/build-system/glib-or-gtk.scm (glib-or-gtk-build, lower):
      Likewise.
    * guix/build-system/font.scm (font-build): Likewise.
    * guix/build-system/gnu.scm (gnu-build): Likewise, and remove
      'canonicalize-reference'.
      (gnu-cross-build): Likewise, and expect #:build-inputs, #:host-inputs,
      and #:target-inputs instead of #:native-drvs and #:target-drvs.
      (lower): Likewise.
    * guix/build-system/perl.scm (perl-build, lower): Likewise.
    * guix/build-system/python.scm (python-build, lower): Likewise.
    * guix/build-system/ruby.scm (ruby-build, lower): Likewise.
    * guix/build-system/waf.scm (waf-build, lower): Likewise.
    * guix/build-system/trivial.scm (guile-for-build): Remove.
      (trivial-build): Remove 'store' parameter, change to gexps.
      (trivial-cross-build): Ditto, and change to #:build-inputs & co.
    * tests/builders.scm ("gnu-build"): Call 'store-lower' on 'gnu-build'.
      Pass #:source parameter.
    * tests/packages.scm ("search paths"): Use 'abort-to-prompt' instead of
      a normal return from the 'build' method.
---
 .dir-locals.el                    |   1 +
 gnu/packages/bootstrap.scm        | 115 +++++++--------
 gnu/packages/commencement.scm     |   3 +-
 guix/build-system/cmake.scm       | 205 ++++++++++++---------------
 guix/build-system/font.scm        |  59 ++++----
 guix/build-system/glib-or-gtk.scm | 103 ++++++--------
 guix/build-system/gnu.scm         | 284 +++++++++++++++-----------------------
 guix/build-system/perl.scm        |  74 +++++-----
 guix/build-system/python.scm      |  73 +++++-----
 guix/build-system/ruby.scm        |  66 ++++-----
 guix/build-system/trivial.scm     |  89 ++++--------
 guix/build-system/waf.scm         |  88 ++++++------
 guix/gexp.scm                     |  26 ++++
 guix/packages.scm                 |  77 ++++-------
 tests/builders.scm                |  20 ++-
 tests/packages.scm                |   6 +-
 16 files changed, 560 insertions(+), 729 deletions(-)

diff --git a/.dir-locals.el b/.dir-locals.el
index 8f07a08..378071e 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -119,6 +119,7 @@
    (eval . (put 'with-extensions 'scheme-indent-function 1))
    (eval . (put 'with-parameters 'scheme-indent-function 1))
    (eval . (put 'let-system 'scheme-indent-function 1))
+   (eval . (put 'with-build-variables 'scheme-indent-function 2))
 
    (eval . (put 'with-database 'scheme-indent-function 2))
    (eval . (put 'call-with-database 'scheme-indent-function 1))
diff --git a/gnu/packages/bootstrap.scm b/gnu/packages/bootstrap.scm
index fee2ae1..d6f8b35 100644
--- a/gnu/packages/bootstrap.scm
+++ b/gnu/packages/bootstrap.scm
@@ -31,11 +31,13 @@
   #:use-module (guix build-system gnu)
   #:use-module (guix build-system trivial)
   #:use-module ((guix store)
-                #:select (run-with-store add-to-store add-text-to-store))
+                #:select (%store-monad interned-file text-file store-lift))
   #:use-module ((guix derivations)
-                #:select (derivation derivation-input derivation->output-path))
-  #:use-module ((guix utils) #:select (gnu-triplet->nix-system))
+                #:select (raw-derivation derivation-input 
derivation->output-path))
+  #:use-module (guix utils)
+  #:use-module ((guix build utils) #:select (elf-file?))
   #:use-module ((guix gexp) #:select (lower-object))
+  #:use-module (guix monads)
   #:use-module (guix memoization)
   #:use-module (guix i18n)
   #:use-module (srfi srfi-1)
@@ -360,59 +362,58 @@ or false to signal an error."
               %bootstrap-base-urls))
     (sha256 (bootstrap-guile-hash system))))
 
-(define (download-bootstrap-guile store system)
+(define (download-bootstrap-guile system)
   "Return a derivation that downloads the bootstrap Guile tarball for SYSTEM."
   (let* ((path (bootstrap-guile-url-path system))
          (base (basename path))
          (urls (map (cut string-append <> path) %bootstrap-base-urls)))
-    (run-with-store store
-      (url-fetch urls 'sha256 (bootstrap-guile-hash system)
-                 #:system system))))
+    (url-fetch urls 'sha256 (bootstrap-guile-hash system)
+               #:system system)))
 
-(define* (raw-build store name inputs
+(define* (raw-build name inputs
                     #:key outputs system search-paths
                     #:allow-other-keys)
   (define (->store file)
-    (run-with-store store
-      (lower-object (bootstrap-executable file system)
-                    system)))
-
-  (let* ((tar   (->store "tar"))
-         (xz    (->store "xz"))
-         (mkdir (->store "mkdir"))
-         (bash  (->store "bash"))
-         (guile (download-bootstrap-guile store system))
-         ;; The following code, run by the bootstrap guile after it is
-         ;; unpacked, creates a wrapper for itself to set its load path.
-         ;; This replaces the previous non-portable method based on
-         ;; reading the /proc/self/exe symlink.
-         (make-guile-wrapper
-          '(begin
-             (use-modules (ice-9 match))
-             (match (command-line)
-               ((_ out bash)
-                (let ((bin-dir    (string-append out "/bin"))
-                      (guile      (string-append out "/bin/guile"))
-                      (guile-real (string-append out "/bin/.guile-real"))
-                      ;; We must avoid using a bare dollar sign in this code,
-                      ;; because it would be interpreted by the shell.
-                      (dollar     (string (integer->char 36))))
-                  (chmod bin-dir #o755)
-                  (rename-file guile guile-real)
-                  (call-with-output-file guile
-                    (lambda (p)
-                      (format p "\
+    (lower-object (bootstrap-executable file system)
+                  system))
+
+  (define (make-guile-wrapper bash guile-real)
+    ;; The following code, run by the bootstrap guile after it is unpacked,
+    ;; creates a wrapper for itself to set its load path.  This replaces the
+    ;; previous non-portable method based on reading the /proc/self/exe
+    ;; symlink.
+    '(begin
+       (use-modules (ice-9 match))
+       (match (command-line)
+         ((_ out bash)
+          (let ((bin-dir    (string-append out "/bin"))
+                (guile      (string-append out "/bin/guile"))
+                (guile-real (string-append out "/bin/.guile-real"))
+                ;; We must avoid using a bare dollar sign in this code,
+                ;; because it would be interpreted by the shell.
+                (dollar     (string (integer->char 36))))
+            (chmod bin-dir #o755)
+            (rename-file guile guile-real)
+            (call-with-output-file guile
+              (lambda (p)
+                (format p "\
 #!~a
 export GUILE_SYSTEM_PATH=~a/share/guile/2.0
 export GUILE_SYSTEM_COMPILED_PATH=~a/lib/guile/2.0/ccache
 exec -a \"~a0\" ~a \"~a@\"\n"
-                              bash out out dollar guile-real dollar)))
-                  (chmod guile   #o555)
-                  (chmod bin-dir #o555))))))
-         (builder
-          (add-text-to-store store
-                             "build-bootstrap-guile.sh"
-                             (format #f "
+                        bash out out dollar guile-real dollar)))
+            (chmod guile   #o555)
+            (chmod bin-dir #o555))))))
+
+  (mlet* %store-monad ((tar   (->store "tar"))
+                       (xz    (->store "xz"))
+                       (mkdir (->store "mkdir"))
+                       (bash  (->store "bash"))
+                       (guile (download-bootstrap-guile system))
+                       (wrapper -> (make-guile-wrapper bash guile))
+                       (builder
+                        (text-file "build-bootstrap-guile.sh"
+                                   (format #f "
 echo \"unpacking bootstrap Guile to '$out'...\"
 ~a $out
 cd $out
@@ -425,19 +426,19 @@ $out/bin/guile -c ~s $out ~a
 
 # Sanity check.
 $out/bin/guile --version~%"
-                                     (derivation->output-path mkdir)
-                                     (derivation->output-path xz)
-                                     (derivation->output-path tar)
-                                     (format #f "~s" make-guile-wrapper)
-                                     (derivation->output-path bash)))))
-    (derivation store name
-                (derivation->output-path bash) `(,builder)
-                #:system system
-                #:inputs (map derivation-input
-                              (list bash mkdir tar xz guile))
-                #:sources (list builder)
-                #:env-vars `(("GUILE_TARBALL"
-                              . ,(derivation->output-path guile))))))
+                                           (derivation->output-path mkdir)
+                                           (derivation->output-path xz)
+                                           (derivation->output-path tar)
+                                           (object->string wrapper)
+                                           (derivation->output-path bash)))))
+    (raw-derivation name
+                    (derivation->output-path bash) `(,builder)
+                    #:system system
+                    #:inputs (map derivation-input
+                                  (list bash mkdir tar xz guile))
+                    #:sources (list builder)
+                    #:env-vars `(("GUILE_TARBALL"
+                                  . ,(derivation->output-path guile))))))
 
 (define* (make-raw-bag name
                        #:key source inputs native-inputs outputs
diff --git a/gnu/packages/commencement.scm b/gnu/packages/commencement.scm
index 890d579..3990fec 100644
--- a/gnu/packages/commencement.scm
+++ b/gnu/packages/commencement.scm
@@ -51,6 +51,7 @@
   #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages rsync)
   #:use-module (gnu packages xml)
+  #:use-module (guix gexp)
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix build-system gnu)
@@ -3366,7 +3367,7 @@ exec ~a/bin/~a-~a -B~a/lib -Wl,-dynamic-linker -Wl,~a/~a 
\"$@\"~%"
    ;; if 'allowed-references' were per-output.
    (arguments
     `(#:allowed-references
-      ((,gcc-boot0 "lib")
+      (,(gexp-input gcc-boot0 "lib")
        ,(kernel-headers-boot0)
        ,static-bash-for-glibc
        ,@(if (hurd-system?)
diff --git a/guix/build-system/cmake.scm b/guix/build-system/cmake.scm
index f590b6e..1b64575 100644
--- a/guix/build-system/cmake.scm
+++ b/guix/build-system/cmake.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2013 Cyril Roelandt <tipecaml@gmail.com>
 ;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2020 Efraim Flashner <efraim@flashner.co.il>
@@ -21,7 +21,9 @@
 
 (define-module (guix build-system cmake)
   #:use-module (guix store)
+  #:use-module (guix gexp)
   #:use-module (guix utils)
+  #:use-module (guix monads)
   #:use-module (guix derivations)
   #:use-module (guix search-paths)
   #:use-module (guix build-system)
@@ -61,7 +63,7 @@
                 #:rest arguments)
   "Return a bag for NAME."
   (define private-keywords
-    `(#:source #:cmake #:inputs #:native-inputs #:outputs
+    `(#:cmake #:inputs #:native-inputs
       ,@(if target '() '(#:target))))
 
   (bag
@@ -95,8 +97,8 @@
     (build (if target cmake-cross-build cmake-build))
     (arguments (strip-keyword-arguments private-keywords arguments))))
 
-(define* (cmake-build store name inputs
-                      #:key (guile #f)
+(define* (cmake-build name inputs
+                      #:key guile source
                       (outputs '("out")) (configure-flags ''())
                       (search-paths '())
                       (make-flags ''())
@@ -120,52 +122,40 @@
                                  (guix build utils))))
   "Build SOURCE using CMAKE, and with INPUTS. This assumes that SOURCE
 provides a 'CMakeLists.txt' file as its build system."
-  (define builder
-    `(begin
-       (use-modules ,@modules)
-       (cmake-build #:source ,(match (assoc-ref inputs "source")
-                                (((? derivation? source))
-                                 (derivation->output-path source))
-                                ((source)
-                                 source)
-                                (source
-                                 source))
-                    #:system ,system
-                    #:outputs %outputs
-                    #:inputs %build-inputs
-                    #:search-paths ',(map search-path-specification->sexp
-                                          search-paths)
-                    #:phases ,phases
-                    #:configure-flags ,configure-flags
-                    #:make-flags ,make-flags
-                    #:out-of-source? ,out-of-source?
-                    #:build-type ,build-type
-                    #:tests? ,tests?
-                    #:test-target ,test-target
-                    #:parallel-build? ,parallel-build?
-                    #:parallel-tests? ,parallel-tests?
-                    #:validate-runpath? ,validate-runpath?
-                    #:patch-shebangs? ,patch-shebangs?
-                    #:strip-binaries? ,strip-binaries?
-                    #:strip-flags ,strip-flags
-                    #:strip-directories ,strip-directories)))
+  (define build
+    #~(begin
+        (use-modules ,@modules)
 
-  (define guile-for-build
-    (match guile
-      ((? package?)
-       (package-derivation store guile system #:graft? #f))
-      (#f                                         ; the default
-       (let* ((distro (resolve-interface '(gnu packages commencement)))
-              (guile  (module-ref distro 'guile-final)))
-         (package-derivation store guile system #:graft? #f)))))
+        #$(with-build-variables inputs outputs
+            #~(cmake-build #:source #+source
+                           #:system #$system
+                           #:outputs %outputs
+                           #:inputs %build-inputs
+                           #:search-paths '#$(map 
search-path-specification->sexp
+                                                  search-paths)
+                           #:phases #$phases
+                           #:configure-flags #$configure-flags
+                           #:make-flags #$make-flags
+                           #:out-of-source? #$out-of-source?
+                           #:build-type #$build-type
+                           #:tests? #$tests?
+                           #:test-target #$test-target
+                           #:parallel-build? #$parallel-build?
+                           #:parallel-tests? #$parallel-tests?
+                           #:validate-runpath? #$validate-runpath?
+                           #:patch-shebangs? #$patch-shebangs?
+                           #:strip-binaries? #$strip-binaries?
+                           #:strip-flags #$strip-flags
+                           #:strip-directories #$strip-directories))))
 
-  (build-expression->derivation store name builder
-                                #:system system
-                                #:inputs inputs
-                                #:modules imported-modules
-                                #:outputs outputs
-                                #:substitutable? substitutable?
-                                #:guile-for-build guile-for-build))
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name build
+                      #:system system
+                      #:target #f
+                      #:modules imported-modules
+                      #:substitutable? substitutable?
+                      #:guile-for-build guile)))
 
 
 ;;;
@@ -174,8 +164,9 @@ provides a 'CMakeLists.txt' file as its build system."
 
 (define* (cmake-cross-build store name
                             #:key
-                            target native-drvs target-drvs
-                            (guile #f)
+                            target
+                            build-inputs target-inputs host-inputs
+                            source guile
                             (outputs '("out"))
                             (configure-flags ''())
                             (search-paths '())
@@ -205,78 +196,60 @@ provides a 'CMakeLists.txt' file as its build system."
 with INPUTS.  This assumes that SOURCE provides a 'CMakeLists.txt' file as its
 build system."
   (define builder
-    `(begin
-       (use-modules ,@modules)
-       (let ()
-         (define %build-host-inputs
-           ',(map (match-lambda
-                    ((name (? derivation? drv) sub ...)
-                     `(,name . ,(apply derivation->output-path drv sub)))
-                    ((name path)
-                     `(,name . ,path)))
-                  native-drvs))
+    #~(begin
+        (use-modules ,@modules)
+
+        (define %build-host-inputs
+          (map (lambda (tuple)
+                 (apply cons tuple))
+               '#+(append build-inputs target-inputs)))
 
-         (define %build-target-inputs
-           ',(map (match-lambda
-                    ((name (? derivation? drv) sub ...)
-                     `(,name . ,(apply derivation->output-path drv sub)))
-                    ((name (? package? pkg) sub ...)
-                     (let ((drv (package-cross-derivation store pkg
-                                                          target system)))
-                       `(,name . ,(apply derivation->output-path drv sub))))
-                    ((name path)
-                     `(,name . ,path)))
-                  target-drvs))
+        (define %build-target-inputs
+          (map (lambda (tuple)
+                 (apply cons tuple))
+               '#$host-inputs))
 
-         (cmake-build #:source ,(match (assoc-ref native-drvs "source")
-                                  (((? derivation? source))
-                                   (derivation->output-path source))
-                                  ((source)
-                                   source)
-                                  (source
-                                   source))
-                      #:system ,system
-                      #:build ,build
-                      #:target ,target
-                      #:outputs %outputs
-                      #:inputs %build-target-inputs
-                      #:native-inputs %build-host-inputs
-                      #:search-paths ',(map search-path-specification->sexp
+        (define %outputs
+          (list #$@(map (lambda (name)
+                          #~(cons #$name
+                                  (ungexp output name)))
+                        outputs)))
+
+        (cmake-build #:source #+source
+                     #:system #$system
+                     #:build #$build
+                     #:target #$target
+                     #:outputs %outputs
+                     #:inputs %build-target-inputs
+                     #:native-inputs %build-host-inputs
+                     #:search-paths '#$(map search-path-specification->sexp
                                             search-paths)
-                      #:native-search-paths ',(map
+                     #:native-search-paths '#$(map
                                                search-path-specification->sexp
                                                native-search-paths)
-                      #:phases ,phases
-                      #:configure-flags ,configure-flags
-                      #:make-flags ,make-flags
-                      #:out-of-source? ,out-of-source?
-                      #:build-type ,build-type
-                      #:tests? ,tests?
-                      #:test-target ,test-target
-                      #:parallel-build? ,parallel-build?
-                      #:parallel-tests? ,parallel-tests?
-                      #:validate-runpath? ,validate-runpath?
-                      #:patch-shebangs? ,patch-shebangs?
-                      #:strip-binaries? ,strip-binaries?
-                      #:strip-flags ,strip-flags
-                      #:strip-directories ,strip-directories))))
-
-  (define guile-for-build
-    (match guile
-      ((? package?)
-       (package-derivation store guile system #:graft? #f))
-      (#f                               ; the default
-       (let* ((distro (resolve-interface '(gnu packages commencement)))
-              (guile  (module-ref distro 'guile-final)))
-         (package-derivation store guile system #:graft? #f)))))
+                     #:phases #$phases
+                     #:configure-flags #$configure-flags
+                     #:make-flags #$make-flags
+                     #:out-of-source? #$out-of-source?
+                     #:build-type #$build-type
+                     #:tests? #$tests?
+                     #:test-target #$test-target
+                     #:parallel-build? #$parallel-build?
+                     #:parallel-tests? #$parallel-tests?
+                     #:validate-runpath? #$validate-runpath?
+                     #:patch-shebangs? #$patch-shebangs?
+                     #:strip-binaries? #$strip-binaries?
+                     #:strip-flags #$strip-flags
+                     #:strip-directories #$strip-directories)))
 
-  (build-expression->derivation store name builder
-                                #:system system
-                                #:inputs (append native-drvs target-drvs)
-                                #:outputs outputs
-                                #:modules imported-modules
-                                #:substitutable? substitutable?
-                                #:guile-for-build guile-for-build))
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name builder
+                      #:system system
+                      #:target target
+                      #:modules imported-modules
+                      #:substitutable? substitutable?
+                      #:guile-for-build guile)))
 
 (define cmake-build-system
   (build-system
diff --git a/guix/build-system/font.scm b/guix/build-system/font.scm
index d40a4985..e7160ff 100644
--- a/guix/build-system/font.scm
+++ b/guix/build-system/font.scm
@@ -17,6 +17,9 @@
 ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
 
 (define-module (guix build-system font)
+  #:use-module (guix gexp)
+  #:use-module (guix store)
+  #:use-module (guix monads)
   #:use-module (guix utils)
   #:use-module (guix packages)
   #:use-module (guix derivations)
@@ -69,7 +72,7 @@
     (build font-build)
     (arguments (strip-keyword-arguments private-keywords arguments))))
 
-(define* (font-build store name inputs
+(define* (font-build name inputs
                      #:key source
                      (tests? #t)
                      (test-target "test")
@@ -85,41 +88,29 @@
                                 (guix build utils))))
   "Build SOURCE with INPUTS."
   (define builder
-    `(begin
-       (use-modules ,@modules)
-       (font-build #:name ,name
-                   #:source ,(match (assoc-ref inputs "source")
-                               (((? derivation? source))
-                                (derivation->output-path source))
-                               ((source)
-                                source)
-                               (source
-                                source))
-                   #:configure-flags ,configure-flags
-                   #:system ,system
-                   #:test-target ,test-target
-                   #:tests? ,tests?
-                   #:phases ,phases
-                   #:outputs %outputs
-                   #:search-paths ',(map search-path-specification->sexp
-                                         search-paths)
-                   #:inputs %build-inputs)))
+    (with-imported-modules imported-modules
+      #~(begin
+          (use-modules #$@modules)
 
-  (define guile-for-build
-    (match guile
-      ((? package?)
-       (package-derivation store guile system #:graft? #f))
-      (#f                                         ; the default
-       (let* ((distro (resolve-interface '(gnu packages commencement)))
-              (guile  (module-ref distro 'guile-final)))
-         (package-derivation store guile system #:graft? #f)))))
+          #$(with-build-variables inputs outputs
+              #~(font-build #:name #$name
+                            #:source #+source
+                            #:configure-flags #$configure-flags
+                            #:system #$system
+                            #:test-target #$test-target
+                            #:tests? #$tests?
+                            #:phases #$phases
+                            #:outputs %outputs
+                            #:search-paths '#$(map 
search-path-specification->sexp
+                                                   search-paths)
+                            #:inputs %build-inputs)))))
 
-  (build-expression->derivation store name builder
-                                #:inputs inputs
-                                #:system system
-                                #:modules imported-modules
-                                #:outputs outputs
-                                #:guile-for-build guile-for-build))
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name builder
+                      #:system system
+                      #:target #f
+                      #:guile-for-build guile)))
 
 (define font-build-system
   (build-system
diff --git a/guix/build-system/glib-or-gtk.scm 
b/guix/build-system/glib-or-gtk.scm
index fb1f8fb..57922df 100644
--- a/guix/build-system/glib-or-gtk.scm
+++ b/guix/build-system/glib-or-gtk.scm
@@ -21,6 +21,8 @@
 (define-module (guix build-system glib-or-gtk)
   #:use-module (guix store)
   #:use-module (guix utils)
+  #:use-module (guix gexp)
+  #:use-module (guix monads)
   #:use-module (guix derivations)
   #:use-module (guix search-paths)
   #:use-module (guix build-system)
@@ -85,7 +87,7 @@
                 #:rest arguments)
   "Return a bag for NAME."
   (define private-keywords
-    '(#:source #:target #:glib #:inputs #:native-inputs
+    '(#:target #:glib #:inputs #:native-inputs
       #:outputs #:implicit-inputs?))
 
   (and (not target)                               ;XXX: no cross-compilation
@@ -105,8 +107,8 @@
          (build glib-or-gtk-build)
          (arguments (strip-keyword-arguments private-keywords arguments)))))
 
-(define* (glib-or-gtk-build store name inputs
-                            #:key (guile #f)
+(define* (glib-or-gtk-build name inputs
+                            #:key guile source
                             (outputs '("out"))
                             (search-paths '())
                             (configure-flags ''())
@@ -132,70 +134,43 @@
                             allowed-references
                             disallowed-references)
   "Build SOURCE with INPUTS.  See GNU-BUILD for more details."
-  (define canonicalize-reference
-    (match-lambda
-     ((? package? p)
-      (derivation->output-path (package-derivation store p system)))
-     (((? package? p) output)
-      (derivation->output-path (package-derivation store p system)
-                               output))
-     ((? string? output)
-      output)))
+  (define build
+    #~(begin
+        (use-modules #$modules)
 
-  (define builder
-    `(begin
-       (use-modules ,@modules)
-       (glib-or-gtk-build #:source ,(match (assoc-ref inputs "source")
-                                      (((? derivation? source))
-                                       (derivation->output-path source))
-                                      ((source)
-                                       source)
-                                      (source
-                                       source))
-                          #:system ,system
-                          #:outputs %outputs
-                          #:inputs %build-inputs
-                          #:search-paths ',(map search-path-specification->sexp
-                                                search-paths)
-                          #:phases ,phases
-                          #:glib-or-gtk-wrap-excluded-outputs
-                           ,glib-or-gtk-wrap-excluded-outputs
-                          #:configure-flags ,configure-flags
-                          #:make-flags ,make-flags
-                          #:out-of-source? ,out-of-source?
-                          #:tests? ,tests?
-                          #:test-target ,test-target
-                          #:parallel-build? ,parallel-build?
-                          #:parallel-tests? ,parallel-tests?
-                          #:validate-runpath? ,validate-runpath?
-                          #:patch-shebangs? ,patch-shebangs?
-                          #:strip-binaries? ,strip-binaries?
-                          #:strip-flags ,strip-flags
-                          #:strip-directories ,strip-directories)))
+        #$(with-build-variables inputs outputs
+            #~(glib-or-gtk-build #:source #+source
+                                 #:system #$system
+                                 #:outputs %outputs
+                                 #:inputs %build-inputs
+                                 #:search-paths '#$(map 
search-path-specification->sexp
+                                                        search-paths)
+                                 #:phases #$phases
+                                 #:glib-or-gtk-wrap-excluded-outputs
+                                 #$glib-or-gtk-wrap-excluded-outputs
+                                 #:configure-flags #$configure-flags
+                                 #:make-flags #$make-flags
+                                 #:out-of-source? #$out-of-source?
+                                 #:tests? #$tests?
+                                 #:test-target #$test-target
+                                 #:parallel-build? #$parallel-build?
+                                 #:parallel-tests? #$parallel-tests?
+                                 #:validate-runpath? #$validate-runpath?
+                                 #:patch-shebangs? #$patch-shebangs?
+                                 #:strip-binaries? #$strip-binaries?
+                                 #:strip-flags #$strip-flags
+                                 #:strip-directories #$strip-directories))))
 
-  (define guile-for-build
-    (match guile
-      ((? package?)
-       (package-derivation store guile system #:graft? #f))
-      (#f                                         ; the default
-       (let* ((distro (resolve-interface '(gnu packages commencement)))
-              (guile  (module-ref distro 'guile-final)))
-         (package-derivation store guile system #:graft? #f)))))
 
-  (build-expression->derivation store name builder
-                                #:system system
-                                #:inputs inputs
-                                #:modules imported-modules
-                                #:outputs outputs
-                                #:allowed-references
-                                (and allowed-references
-                                     (map canonicalize-reference
-                                          allowed-references))
-                                #:disallowed-references
-                                (and disallowed-references
-                                     (map canonicalize-reference
-                                          disallowed-references))
-                                #:guile-for-build guile-for-build))
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name build
+                      #:system system
+                      #:target #f
+                      #:modules imported-modules
+                      #:allowed-references allowed-references
+                      #:disallowed-references disallowed-references
+                      #:guile-for-build guile)))
 
 (define glib-or-gtk-build-system
   (build-system
diff --git a/guix/build-system/gnu.scm b/guix/build-system/gnu.scm
index fc045f1..dc500a5 100644
--- a/guix/build-system/gnu.scm
+++ b/guix/build-system/gnu.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2020, 2021 Ludovic 
Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic 
Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -20,6 +20,8 @@
   #:use-module (guix store)
   #:use-module (guix utils)
   #:use-module (guix memoization)
+  #:use-module (guix gexp)
+  #:use-module (guix monads)
   #:use-module (guix derivations)
   #:use-module (guix search-paths)
   #:use-module (guix build-system)
@@ -281,7 +283,7 @@ standard packages used as implicit inputs of the GNU build 
system."
                 #:rest arguments)
   "Return a bag for NAME from the given arguments."
   (define private-keywords
-    `(#:source #:inputs #:native-inputs #:outputs
+    `(#:inputs #:native-inputs #:outputs
       #:implicit-inputs? #:implicit-cross-inputs?
       ,@(if target '() '(#:target))))
 
@@ -328,8 +330,9 @@ standard packages used as implicit inputs of the GNU build 
system."
   ;; Typical names of Autotools "bootstrap" scripts.
   '("bootstrap" "bootstrap.sh" "autogen.sh"))
 
-(define* (gnu-build store name input-drvs
-                    #:key (guile #f)
+(define* (gnu-build name inputs
+                    #:key
+                    guile source
                     (outputs '("out"))
                     (search-paths '())
                     (bootstrap-scripts (list 'quote %bootstrap-scripts))
@@ -374,80 +377,48 @@ SUBSTITUTABLE? determines whether users may be able to 
use substitutes of the
 returned derivations, or whether they should always build it locally.
 
 ALLOWED-REFERENCES can be either #f, or a list of packages that the outputs
-are allowed to refer to.  Likewise for DISALLOWED-REFERENCES, which lists
-packages that must not be referenced."
-  (define canonicalize-reference
-    (match-lambda
-     ((? package? p)
-      (derivation->output-path (package-derivation store p system
-                                                   #:graft? #f)))
-     (((? package? p) output)
-      (derivation->output-path (package-derivation store p system
-                                                   #:graft? #f)
-                               output))
-     ((? string? output)
-      output)))
-
+are allowed to refer to."
   (define builder
-    `(begin
-       (use-modules ,@modules)
-       (gnu-build #:source ,(match (assoc-ref input-drvs "source")
-                              (((? derivation? source))
-                               (derivation->output-path source))
-                              ((source)
-                               source)
-                              (source
-                               source))
-                  #:system ,system
-                  #:build ,build
-                  #:outputs %outputs
-                  #:inputs %build-inputs
-                  #:search-paths ',(map search-path-specification->sexp
-                                        search-paths)
-                  #:phases ,phases
-                  #:locale ,locale
-                  #:bootstrap-scripts ,bootstrap-scripts
-                  #:configure-flags ,configure-flags
-                  #:make-flags ,make-flags
-                  #:out-of-source? ,out-of-source?
-                  #:tests? ,tests?
-                  #:test-target ,test-target
-                  #:parallel-build? ,parallel-build?
-                  #:parallel-tests? ,parallel-tests?
-                  #:patch-shebangs? ,patch-shebangs?
-                  #:strip-binaries? ,strip-binaries?
-                  #:validate-runpath? ,validate-runpath?
-                  #:make-dynamic-linker-cache? ,make-dynamic-linker-cache?
-                  #:license-file-regexp ,license-file-regexp
-                  #:strip-flags ,strip-flags
-                  #:strip-directories ,strip-directories)))
-
-  (define guile-for-build
-    (match guile
-      ((? package?)
-       (package-derivation store guile system #:graft? #f))
-      (#f                                         ; the default
-       (let* ((distro (resolve-interface '(gnu packages commencement)))
-              (guile  (module-ref distro 'guile-final)))
-         (package-derivation store guile system
-                             #:graft? #f)))))
-
-  (build-expression->derivation store name builder
-                                #:system system
-                                #:inputs input-drvs
-                                #:outputs outputs
-                                #:modules imported-modules
-                                #:substitutable? substitutable?
-
-                                #:allowed-references
-                                (and allowed-references
-                                     (map canonicalize-reference
-                                          allowed-references))
-                                #:disallowed-references
-                                (and disallowed-references
-                                     (map canonicalize-reference
-                                          disallowed-references))
-                                #:guile-for-build guile-for-build))
+    #~(begin
+        (use-modules #$@modules)
+
+        #$(with-build-variables inputs outputs
+            #~(gnu-build #:source #+source
+                         #:system #$system
+                         #:build #$build
+                         #:outputs %outputs
+                         #:inputs %build-inputs
+                         #:search-paths '#$(map search-path-specification->sexp
+                                                search-paths)
+                         #:phases #$phases
+                         #:locale #$locale
+                         #:bootstrap-scripts #$bootstrap-scripts
+                         #:configure-flags #$configure-flags
+                         #:make-flags #$make-flags
+                         #:out-of-source? #$out-of-source?
+                         #:tests? #$tests?
+                         #:test-target #$test-target
+                         #:parallel-build? #$parallel-build?
+                         #:parallel-tests? #$parallel-tests?
+                         #:patch-shebangs? #$patch-shebangs?
+                         #:license-file-regexp #$license-file-regexp
+                         #:strip-binaries? #$strip-binaries?
+                         #:validate-runpath? #$validate-runpath?
+                         #:make-dynamic-linker-cache? 
#$make-dynamic-linker-cache?
+                         #:license-file-regexp #$license-file-regexp
+                         #:strip-flags #$strip-flags
+                         #:strip-directories #$strip-directories))))
+
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name builder
+                      #:system system
+                      #:target #f
+                      #:modules imported-modules
+                      #:substitutable? substitutable?
+                      #:allowed-references allowed-references
+                      #:disallowed-references disallowed-references
+                      #:guile-for-build guile)))
 
 
 ;;;
@@ -483,11 +454,11 @@ is one of `host' or `target'."
                    `(("cross-libc:static" ,libc "static"))
                    '()))))))))
 
-(define* (gnu-cross-build store name
+(define* (gnu-cross-build name
                           #:key
-                          target native-drvs target-drvs
-                          (guile #f)
-                          source
+                          target
+                          build-inputs target-inputs host-inputs
+                          guile source
                           (outputs '("out"))
                           (search-paths '())
                           (native-search-paths '())
@@ -525,104 +496,67 @@ is one of `host' or `target'."
   "Cross-build NAME for TARGET, where TARGET is a GNU triplet.  INPUTS are
 cross-built inputs, and NATIVE-INPUTS are inputs that run on the build
 platform."
-  (define canonicalize-reference
-    (match-lambda
-     ((? package? p)
-      (derivation->output-path (package-cross-derivation store p
-                                                         target system)))
-     (((? package? p) output)
-      (derivation->output-path (package-cross-derivation store p
-                                                         target system)
-                               output))
-     ((? string? output)
-      output)))
-
   (define builder
-    `(begin
-       (use-modules ,@modules)
-
-       (let ()
-         (define %build-host-inputs
-           ',(map (match-lambda
-                   ((name (? derivation? drv) sub ...)
-                    `(,name . ,(apply derivation->output-path drv sub)))
-                   ((name path)
-                    `(,name . ,path)))
-                  native-drvs))
-
-         (define %build-target-inputs
-           ',(map (match-lambda
-                   ((name (? derivation? drv) sub ...)
-                    `(,name . ,(apply derivation->output-path drv sub)))
-                   ((name (? package? pkg) sub ...)
-                    (let ((drv (package-cross-derivation store pkg
-                                                         target system)))
-                      `(,name . ,(apply derivation->output-path drv sub))))
-                   ((name path)
-                    `(,name . ,path)))
-                  target-drvs))
-
-         (gnu-build #:source ,(match (assoc-ref native-drvs "source")
-                                (((? derivation? source))
-                                 (derivation->output-path source))
-                                ((source)
-                                 source)
-                                (source
-                                 source))
-                    #:system ,system
-                    #:build ,build
-                    #:target ,target
-                    #:outputs %outputs
-                    #:inputs %build-target-inputs
-                    #:native-inputs %build-host-inputs
-                    #:search-paths ',(map search-path-specification->sexp
+    #~(begin
+        (use-modules #$@modules)
+
+        (define %build-host-inputs
+          (map (lambda (tuple)
+                 (apply cons tuple))
+               '#+build-inputs))
+
+        (define %build-target-inputs
+          (map (lambda (tuple)
+                 (apply cons tuple))
+               (append '#$host-inputs '#+target-inputs)))
+
+        (define %outputs
+          (list #$@(map (lambda (name)
+                          #~(cons #$name
+                                  (ungexp output name)))
+                        outputs)))
+
+        (gnu-build #:source #+source
+                   #:system #$system
+                   #:build #$build
+                   #:target #$target
+                   #:outputs %outputs
+                   #:inputs %build-target-inputs
+                   #:native-inputs %build-host-inputs
+                   #:search-paths '#$(map search-path-specification->sexp
                                           search-paths)
-                    #:native-search-paths ',(map
+                   #:native-search-paths '#$(map
                                              search-path-specification->sexp
                                              native-search-paths)
-                    #:phases ,phases
-                    #:locale ,locale
-                    #:bootstrap-scripts ,bootstrap-scripts
-                    #:configure-flags ,configure-flags
-                    #:make-flags ,make-flags
-                    #:out-of-source? ,out-of-source?
-                    #:tests? ,tests?
-                    #:test-target ,test-target
-                    #:parallel-build? ,parallel-build?
-                    #:parallel-tests? ,parallel-tests?
-                    #:patch-shebangs? ,patch-shebangs?
-                    #:strip-binaries? ,strip-binaries?
-                    #:validate-runpath? ,validate-runpath?
-                    #:make-dynamic-linker-cache? ,make-dynamic-linker-cache?
-                    #:license-file-regexp ,license-file-regexp
-                    #:strip-flags ,strip-flags
-                    #:strip-directories ,strip-directories))))
-
-  (define guile-for-build
-    (match guile
-      ((? package?)
-       (package-derivation store guile system #:graft? #f))
-      (#f                                         ; the default
-       (let* ((distro (resolve-interface '(gnu packages commencement)))
-              (guile  (module-ref distro 'guile-final)))
-         (package-derivation store guile system #:graft? #f)))))
-
-  (build-expression->derivation store name builder
-                                #:system system
-                                #:inputs (append native-drvs target-drvs)
-                                #:outputs outputs
-                                #:modules imported-modules
-                                #:substitutable? substitutable?
-
-                                #:allowed-references
-                                (and allowed-references
-                                     (map canonicalize-reference
-                                          allowed-references))
-                                #:disallowed-references
-                                (and disallowed-references
-                                     (map canonicalize-reference
-                                          disallowed-references))
-                                #:guile-for-build guile-for-build))
+                   #:phases #$phases
+                   #:locale #$locale
+                   #:bootstrap-scripts #$bootstrap-scripts
+                   #:configure-flags #$configure-flags
+                   #:make-flags #$make-flags
+                   #:out-of-source? #$out-of-source?
+                   #:tests? #$tests?
+                   #:test-target #$test-target
+                   #:parallel-build? #$parallel-build?
+                   #:parallel-tests? #$parallel-tests?
+                   #:patch-shebangs? #$patch-shebangs?
+                   #:license-file-regexp #$license-file-regexp
+                   #:strip-binaries? #$strip-binaries?
+                   #:validate-runpath? #$validate-runpath?
+                   #:make-dynamic-linker-cache? #$make-dynamic-linker-cache?
+                   #:license-file-regexp #$license-file-regexp
+                   #:strip-flags #$strip-flags
+                   #:strip-directories #$strip-directories)))
+
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name builder
+                      #:system system
+                      #:target target
+                      #:modules imported-modules
+                      #:substitutable? substitutable?
+                      #:allowed-references allowed-references
+                      #:disallowed-references disallowed-references
+                      #:guile-for-build guile)))
 
 (define gnu-build-system
   (build-system
diff --git a/guix/build-system/perl.scm b/guix/build-system/perl.scm
index 06af1dd..8b62927 100644
--- a/guix/build-system/perl.scm
+++ b/guix/build-system/perl.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2021 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -19,6 +19,8 @@
 (define-module (guix build-system perl)
   #:use-module (guix store)
   #:use-module (guix utils)
+  #:use-module (guix gexp)
+  #:use-module (guix monads)
   #:use-module (guix derivations)
   #:use-module (guix search-paths)
   #:use-module (guix build-system)
@@ -57,7 +59,7 @@
                 #:rest arguments)
   "Return a bag for NAME."
   (define private-keywords
-    '(#:source #:target #:perl #:inputs #:native-inputs))
+    '(#:target #:perl #:inputs #:native-inputs))
 
   (and (not target)                               ;XXX: no cross-compilation
        (bag
@@ -76,8 +78,8 @@
          (build perl-build)
          (arguments (strip-keyword-arguments private-keywords arguments)))))
 
-(define* (perl-build store name inputs
-                     #:key
+(define* (perl-build name inputs
+                     #:key source
                      (search-paths '())
                      (tests? #t)
                      (parallel-build? #t)
@@ -95,46 +97,34 @@
                                 (guix build utils))))
   "Build SOURCE using PERL, and with INPUTS.  This assumes that SOURCE
 provides a `Makefile.PL' file as its build system."
-  (define builder
-    `(begin
-       (use-modules ,@modules)
-       (perl-build #:name ,name
-                   #:source ,(match (assoc-ref inputs "source")
-                               (((? derivation? source))
-                                (derivation->output-path source))
-                               ((source)
-                                source)
-                               (source
-                                source))
-                   #:search-paths ',(map search-path-specification->sexp
-                                         search-paths)
-                   #:make-maker? ,make-maker?
-                   #:make-maker-flags ,make-maker-flags
-                   #:module-build-flags ,module-build-flags
-                   #:phases ,phases
-                   #:system ,system
-                   #:test-target "test"
-                   #:tests? ,tests?
-                   #:parallel-build? ,parallel-build?
-                   #:parallel-tests? ,parallel-tests?
-                   #:outputs %outputs
-                   #:inputs %build-inputs)))
+  (define build
+    #~(begin
+        (use-modules #$@modules)
 
-  (define guile-for-build
-    (match guile
-      ((? package?)
-       (package-derivation store guile system #:graft? #f))
-      (#f                                         ; the default
-       (let* ((distro (resolve-interface '(gnu packages commencement)))
-              (guile  (module-ref distro 'guile-final)))
-         (package-derivation store guile system #:graft? #f)))))
+        #$(with-build-variables inputs outputs
+            #~(perl-build #:name #$name
+                          #:source #+source
+                          #:search-paths '#$(map 
search-path-specification->sexp
+                                                 search-paths)
+                          #:make-maker? #$make-maker?
+                          #:make-maker-flags #$make-maker-flags
+                          #:module-build-flags #$module-build-flags
+                          #:phases #$phases
+                          #:system #$system
+                          #:test-target "test"
+                          #:tests? #$tests?
+                          #:parallel-build? #$parallel-build?
+                          #:parallel-tests? #$parallel-tests?
+                          #:outputs %outputs
+                          #:inputs %build-inputs))))
 
-  (build-expression->derivation store name builder
-                                #:system system
-                                #:inputs inputs
-                                #:modules imported-modules
-                                #:outputs outputs
-                                #:guile-for-build guile-for-build))
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name build
+                      #:system system
+                      #:target #f
+                      #:modules imported-modules
+                      #:guile-for-build guile)))
 
 (define perl-build-system
   (build-system
diff --git a/guix/build-system/python.scm b/guix/build-system/python.scm
index 2bb6fa8..085b0c6 100644
--- a/guix/build-system/python.scm
+++ b/guix/build-system/python.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2021 Ludovic Courtès 
<ludo@gnu.org>
 ;;; Copyright © 2013 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
 ;;; Copyright © 2021 Lars-Dominik Braun <lars@6xq.net>
@@ -25,6 +25,8 @@
   #:use-module (guix store)
   #:use-module (guix utils)
   #:use-module (guix memoization)
+  #:use-module (guix gexp)
+  #:use-module (guix monads)
   #:use-module (guix packages)
   #:use-module (guix derivations)
   #:use-module (guix search-paths)
@@ -149,7 +151,7 @@ pre-defined variants."
                 #:rest arguments)
   "Return a bag for NAME."
   (define private-keywords
-    '(#:source #:target #:python #:inputs #:native-inputs))
+    '(#:target #:python #:inputs #:native-inputs))
 
   (and (not target)                               ;XXX: no cross-compilation
        (bag
@@ -169,8 +171,8 @@ pre-defined variants."
          (build python-build)
          (arguments (strip-keyword-arguments private-keywords arguments)))))
 
-(define* (python-build store name inputs
-                       #:key
+(define* (python-build name inputs
+                       #:key source
                        (tests? #t)
                        (test-target "test")
                        (use-setuptools? #t)
@@ -186,43 +188,32 @@ pre-defined variants."
                                   (guix build utils))))
   "Build SOURCE using PYTHON, and with INPUTS.  This assumes that SOURCE
 provides a 'setup.py' file as its build system."
-  (define builder
-    `(begin
-       (use-modules ,@modules)
-       (python-build #:name ,name
-                     #:source ,(match (assoc-ref inputs "source")
-                                 (((? derivation? source))
-                                  (derivation->output-path source))
-                                 ((source)
-                                  source)
-                                 (source
-                                  source))
-                     #:configure-flags ,configure-flags
-                     #:system ,system
-                     #:test-target ,test-target
-                     #:tests? ,tests?
-                     #:use-setuptools? ,use-setuptools?
-                     #:phases ,phases
-                     #:outputs %outputs
-                     #:search-paths ',(map search-path-specification->sexp
-                                           search-paths)
-                     #:inputs %build-inputs)))
-
-  (define guile-for-build
-    (match guile
-      ((? package?)
-       (package-derivation store guile system #:graft? #f))
-      (#f                                         ; the default
-       (let* ((distro (resolve-interface '(gnu packages commencement)))
-              (guile  (module-ref distro 'guile-final)))
-         (package-derivation store guile system #:graft? #f)))))
-
-  (build-expression->derivation store name builder
-                                #:inputs inputs
-                                #:system system
-                                #:modules imported-modules
-                                #:outputs outputs
-                                #:guile-for-build guile-for-build))
+  (define build
+    #~(begin
+        (use-modules #$@modules)
+
+        #$(with-build-variables inputs outputs
+            #~(python-build #:name #$name
+                            #:source #+source
+                            #:configure-flags #$configure-flags
+                            #:use-setuptools? ,use-setuptools?
+                            #:system #$system
+                            #:test-target #$test-target
+                            #:tests? #$tests?
+                            #:phases #$phases
+                            #:outputs %outputs
+                            #:search-paths '#$(map 
search-path-specification->sexp
+                                                   search-paths)
+                            #:inputs %build-inputs))))
+
+
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name build
+                      #:system system
+                      #:target #f
+                      #:modules imported-modules
+                      #:guile-for-build guile)))
 
 (define python-build-system
   (build-system
diff --git a/guix/build-system/ruby.scm b/guix/build-system/ruby.scm
index 8142e85..8b02e0f 100644
--- a/guix/build-system/ruby.scm
+++ b/guix/build-system/ruby.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014 David Thompson <davet@gnu.org>
-;;; Copyright © 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014, 2015, 2021 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -20,6 +20,8 @@
 (define-module (guix build-system ruby)
   #:use-module (guix store)
   #:use-module (guix utils)
+  #:use-module (guix gexp)
+  #:use-module (guix monads)
   #:use-module (guix packages)
   #:use-module (guix derivations)
   #:use-module (guix search-paths)
@@ -54,7 +56,7 @@ NAME and VERSION."
                 #:rest arguments)
   "Return a bag for NAME."
   (define private-keywords
-    '(#:source #:target #:ruby #:inputs #:native-inputs))
+    '(#:target #:ruby #:inputs #:native-inputs))
 
   (and (not target)                    ;XXX: no cross-compilation
        (bag
@@ -73,8 +75,8 @@ NAME and VERSION."
          (build ruby-build)
          (arguments (strip-keyword-arguments private-keywords arguments)))))
 
-(define* (ruby-build store name inputs
-                     #:key
+(define* (ruby-build name inputs
+                     #:key source
                      (gem-flags ''())
                      (test-target "test")
                      (tests? #t)
@@ -88,42 +90,30 @@ NAME and VERSION."
                      (modules '((guix build ruby-build-system)
                                 (guix build utils))))
   "Build SOURCE using RUBY and INPUTS."
-  (define builder
-    `(begin
-       (use-modules ,@modules)
-       (ruby-build #:name ,name
-                   #:source ,(match (assoc-ref inputs "source")
-                               (((? derivation? source))
-                                (derivation->output-path source))
-                               ((source)
-                                source)
-                               (source
-                                source))
-                   #:system ,system
-                   #:gem-flags ,gem-flags
-                   #:test-target ,test-target
-                   #:tests? ,tests?
-                   #:phases ,phases
-                   #:outputs %outputs
-                   #:search-paths ',(map search-path-specification->sexp
-                                         search-paths)
-                   #:inputs %build-inputs)))
+  (define build
+    #~(begin
+        (use-modules #$@modules)
 
-  (define guile-for-build
-    (match guile
-      ((? package?)
-       (package-derivation store guile system #:graft? #f))
-      (#f
-       (let* ((distro (resolve-interface '(gnu packages commencement)))
-              (guile  (module-ref distro 'guile-final)))
-         (package-derivation store guile system #:graft? #f)))))
+        #$(with-build-variables inputs outputs
+            #~(ruby-build #:name #$name
+                          #:source #+source
+                          #:system #$system
+                          #:gem-flags #$gem-flags
+                          #:test-target #$test-target
+                          #:tests? #$tests?
+                          #:phases #$phases
+                          #:outputs %outputs
+                          #:search-paths '#$(map 
search-path-specification->sexp
+                                                 search-paths)
+                          #:inputs %build-inputs))))
 
-  (build-expression->derivation store name builder
-                                #:inputs inputs
-                                #:system system
-                                #:modules imported-modules
-                                #:outputs outputs
-                                #:guile-for-build guile-for-build))
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name build
+                      #:system system
+                      #:target #f
+                      #:modules imported-modules
+                      #:guile-for-build guile)))
 
 (define ruby-build-system
   (build-system
diff --git a/guix/build-system/trivial.scm b/guix/build-system/trivial.scm
index b50ef7c..0f89524 100644
--- a/guix/build-system/trivial.scm
+++ b/guix/build-system/trivial.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2018, 2021 Ludovic Courtès 
<ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -19,24 +19,16 @@
 (define-module (guix build-system trivial)
   #:use-module (guix store)
   #:use-module (guix utils)
-  #:use-module (guix derivations)
+  #:use-module (guix gexp)
+  #:use-module (guix monads)
   #:use-module (guix packages)
   #:use-module (guix build-system)
   #:use-module (ice-9 match)
   #:export (trivial-build-system))
 
-(define (guile-for-build store guile system)
-  (match guile
-    ((? package?)
-     (package-derivation store guile system #:graft? #f))
-    (#f                                         ; the default
-     (let* ((distro (resolve-interface '(gnu packages commencement)))
-            (guile  (module-ref distro 'guile-final)))
-       (package-derivation store guile system #:graft? #f)))))
-
 (define* (lower name
                 #:key source inputs native-inputs outputs system target
-                guile builder modules allowed-references)
+                guile builder (modules '()) allowed-references)
   "Return a bag for NAME."
   (bag
     (name name)
@@ -54,65 +46,42 @@
                  #:modules ,modules
                  #:allowed-references ,allowed-references))))
 
-(define* (trivial-build store name inputs
+(define* (trivial-build name inputs
                         #:key
-                        outputs guile system builder (modules '())
+                        outputs guile
+                        system builder (modules '())
                         search-paths allowed-references)
   "Run build expression BUILDER, an expression, for SYSTEM.  SOURCE is
 ignored."
-  (define canonicalize-reference
-    (match-lambda
-     ((? package? p)
-      (derivation->output-path (package-derivation store p system
-                                                   #:graft? #f)))
-     (((? package? p) output)
-      (derivation->output-path (package-derivation store p system
-                                                   #:graft? #f)
-                               output))
-     ((? string? output)
-      output)))
-
-  (build-expression->derivation store name builder
-                                #:inputs inputs
-                                #:system system
-                                #:outputs outputs
-                                #:modules modules
-                                #:allowed-references
-                                (and allowed-references
-                                     (map canonicalize-reference
-                                          allowed-references))
-                                #:guile-for-build
-                                (guile-for-build store guile system)))
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name (with-build-variables inputs outputs builder)
+                      #:system system
+                      #:target #f
+                      #:modules modules
+                      #:allowed-references allowed-references
+                      #:guile-for-build guile)))
 
-(define* (trivial-cross-build store name
+(define* (trivial-cross-build name
                               #:key
-                              target native-drvs target-drvs
+                              target
+                              source build-inputs target-inputs host-inputs
                               outputs guile system builder (modules '())
                               search-paths native-search-paths
                               allowed-references)
   "Run build expression BUILDER, an expression, for SYSTEM.  SOURCE is
 ignored."
-  (define canonicalize-reference
-    (match-lambda
-     ((? package? p)
-      (derivation->output-path (package-cross-derivation store p system)))
-     (((? package? p) output)
-      (derivation->output-path (package-cross-derivation store p system)
-                               output))
-     ((? string? output)
-      output)))
-
-  (build-expression->derivation store name builder
-                                #:inputs (append native-drvs target-drvs)
-                                #:system system
-                                #:outputs outputs
-                                #:modules modules
-                                #:allowed-references
-                                (and allowed-references
-                                     (map canonicalize-reference
-                                          allowed-references))
-                                #:guile-for-build
-                                (guile-for-build store guile system)))
+  (mlet %store-monad  ((guile (package->derivation (or guile (default-guile))
+                                                   system #:graft? #f)))
+    (gexp->derivation name (with-build-variables
+                               (append build-inputs target-inputs)
+                               outputs
+                             builder)
+                      #:system system
+                      #:target target
+                      #:modules modules
+                      #:allowed-references allowed-references
+                      #:guile-for-build guile)))
 
 (define trivial-build-system
   (build-system
diff --git a/guix/build-system/waf.scm b/guix/build-system/waf.scm
index 044d2a0..db604e6 100644
--- a/guix/build-system/waf.scm
+++ b/guix/build-system/waf.scm
@@ -19,6 +19,8 @@
 (define-module (guix build-system waf)
   #:use-module (guix store)
   #:use-module (guix utils)
+  #:use-module (guix gexp)
+  #:use-module (guix monads)
   #:use-module (guix packages)
   #:use-module (guix derivations)
   #:use-module (guix search-paths)
@@ -52,7 +54,7 @@
                 #:rest arguments)
   "Return a bag for NAME."
   (define private-keywords
-    '(#:source #:target #:python #:inputs #:native-inputs))
+    '(#:target #:python #:inputs #:native-inputs))
 
   (and (not target)                               ;XXX: no cross-compilation
        (bag
@@ -71,58 +73,46 @@
          (build waf-build) ; only change compared to 'lower' in python.scm
          (arguments (strip-keyword-arguments private-keywords arguments)))))
 
-(define* (waf-build store name inputs
-                       #:key
-                       (tests? #t)
-                       (test-target "check")
-                       (configure-flags ''())
-                       (phases '(@ (guix build waf-build-system)
-                                   %standard-phases))
-                       (outputs '("out"))
-                       (search-paths '())
-                       (system (%current-system))
-                       (guile #f)
-                       (imported-modules %waf-build-system-modules)
-                       (modules '((guix build waf-build-system)
-                                  (guix build utils))))
+(define* (waf-build name inputs
+                    #:key source
+                    (tests? #t)
+                    (test-target "check")
+                    (configure-flags ''())
+                    (phases '(@ (guix build waf-build-system)
+                                %standard-phases))
+                    (outputs '("out"))
+                    (search-paths '())
+                    (system (%current-system))
+                    (guile #f)
+                    (imported-modules %waf-build-system-modules)
+                    (modules '((guix build waf-build-system)
+                               (guix build utils))))
   "Build SOURCE with INPUTS.  This assumes that SOURCE provides a 'waf' file
 as its build system."
-  (define builder
-    `(begin
-       (use-modules ,@modules)
-       (waf-build #:name ,name
-                  #:source ,(match (assoc-ref inputs "source")
-                              (((? derivation? source))
-                               (derivation->output-path source))
-                              ((source)
-                               source)
-                              (source
-                               source))
-                  #:configure-flags ,configure-flags
-                  #:system ,system
-                  #:test-target ,test-target
-                  #:tests? ,tests?
-                  #:phases ,phases
-                  #:outputs %outputs
-                  #:search-paths ',(map search-path-specification->sexp
-                                        search-paths)
-                  #:inputs %build-inputs)))
+  (define build
+    #~(begin
+        (use-modules #$@modules)
 
-  (define guile-for-build
-    (match guile
-      ((? package?)
-       (package-derivation store guile system #:graft? #f))
-      (#f                                         ; the default
-       (let* ((distro (resolve-interface '(gnu packages commencement)))
-              (guile  (module-ref distro 'guile-final)))
-         (package-derivation store guile system #:graft? #f)))))
+        #$(with-build-variables inputs outputs
+            #~(waf-build #:name #$name
+                         #:source #+source
+                         #:configure-flags #$configure-flags
+                         #:system #$system
+                         #:test-target #$test-target
+                         #:tests? #$tests?
+                         #:phases #$phases
+                         #:outputs %outputs
+                         #:search-paths '#$(map search-path-specification->sexp
+                                                search-paths)
+                         #:inputs %build-inputs))))
 
-  (build-expression->derivation store name builder
-                                #:inputs inputs
-                                #:system system
-                                #:modules imported-modules
-                                #:outputs outputs
-                                #:guile-for-build guile-for-build))
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+    (gexp->derivation name build
+                      #:system system
+                      #:target #f
+                      #:modules imported-modules
+                      #:guile-for-build guile)))
 
 (define waf-build-system
   (build-system
diff --git a/guix/gexp.scm b/guix/gexp.scm
index 2735d25..620a86e 100644
--- a/guix/gexp.scm
+++ b/guix/gexp.scm
@@ -104,6 +104,7 @@
             lowered-gexp-load-path
             lowered-gexp-load-compiled-path
 
+            with-build-variables
             gexp->derivation
             gexp->file
             gexp->script
@@ -111,6 +112,7 @@
             mixed-text-file
             file-union
             directory-union
+
             imported-files
             imported-modules
             compiled-modules
@@ -1757,6 +1759,30 @@ are searched for in PATH.  Return #f when MODULES and 
EXTENSIONS are empty."
                                          extensions))
                               %load-compiled-path)))))))))
 
+(define (with-build-variables inputs outputs body)
+  "Return a gexp that surrounds BODY with a definition of the legacy
+'%build-inputs', '%outputs', and '%output' variables based on INPUTS, a list
+of name/gexp-input tuples, and OUTPUTS, a list of strings."
+
+  ;; These two variables are defined for backward compatibility.  They are
+  ;; used by package expressions.  These must be top-level defines so that
+  ;; 'use-modules' form in BODY that are required for macro expansion work as
+  ;; expected.
+  (gexp (begin
+          (define %build-inputs
+            (map (lambda (tuple)
+                   (apply cons tuple))
+                 '(ungexp inputs)))
+          (define %outputs
+            (list (ungexp-splicing
+                   (map (lambda (name)
+                          (gexp (cons (ungexp name)
+                                      (ungexp output name))))
+                        outputs))))
+          (define  %output
+            (assoc-ref %outputs "out"))
+          (ungexp body))))
+
 (define* (gexp->script name exp
                        #:key (guile (default-guile))
                        (module-path %load-path)
diff --git a/guix/packages.scm b/guix/packages.scm
index 67ef6ea..7c8ecc6 100644
--- a/guix/packages.scm
+++ b/guix/packages.scm
@@ -1167,10 +1167,6 @@ matching package and returns a replacement for that 
package."
 ;;; Package derivations.
 ;;;
 
-(define %derivation-cache
-  ;; Package to derivation-path mapping.
-  (make-weak-key-hash-table 100))
-
 (define (cache! cache package system thunk)
   "Memoize in CACHE the return values of THUNK as the derivation of PACKAGE on
 SYSTEM."
@@ -1202,48 +1198,29 @@ Return the cached result when available."
     ((_ package system body ...)
      (cached (=> %derivation-cache) package system body ...))))
 
-(define* (expand-input store package input system #:optional cross-system)
-  "Expand INPUT, an input tuple, such that it contains only references to
-derivation paths or store paths.  PACKAGE is only used to provide contextual
-information in exceptions."
-  (define (intern file)
-    ;; Add FILE to the store.  Set the `recursive?' bit to #t, so that
-    ;; file permissions are preserved.
-    (add-to-store store (basename file) #t "sha256" file))
-
-  (define derivation
-    (if cross-system
-        (cut package-cross-derivation store <> cross-system system
-             #:graft? #f)
-        (cut package-derivation store <> system #:graft? #f)))
+(define* (expand-input package input #:key native?)
+  "Expand INPUT, an input tuple, to a name/<gexp-input> tuple.  PACKAGE is
+only used to provide contextual information in exceptions."
+  (define (valid? x)
+    (or (package? x) (origin? x) (derivation? x)))
 
   (match input
-    (((? string? name) (? package? package))
-     (list name (derivation package)))
-    (((? string? name) (? package? package)
-      (? string? sub-drv))
-     (list name (derivation package)
-           sub-drv))
-    (((? string? name)
-      (and (? string?) (? derivation-path?) drv))
-     (list name drv))
+    (((? string? name) (? valid? thing))
+     (list name (gexp-input thing #:native? native?)))
+    (((? string? name) (? valid? thing) (? string? output))
+     (list name (gexp-input thing output #:native? native?)))
     (((? string? name)
       (and (? string?) (? file-exists? file)))
      ;; Add FILE to the store.  When FILE is in the sub-directory of a
      ;; store path, it needs to be added anyway, so it can be used as a
      ;; source.
-     (list name (intern file)))
+     (list name (gexp-input (local-file file #:recursive? #t)
+                            #:native? native?)))
     (((? string? name) (? struct? source))
      ;; 'package-source-derivation' calls 'lower-object', which can throw
      ;; '&gexp-input-error'.  However '&gexp-input-error' lacks source
-     ;; location info, so we catch and rethrow here (XXX: not optimal
-     ;; performance-wise).
-     (guard (c ((gexp-input-error? c)
-                (raise (condition
-                        (&package-input-error
-                         (package package)
-                         (input   (gexp-error-invalid-input c)))))))
-       (list name (package-source-derivation store source system))))
+     ;; location info, so we used to catch and rethrow here (FIXME!).
+     (list name (gexp-input source)))
     (x
      (raise (condition (&package-input-error
                         (package package)
@@ -1427,12 +1404,14 @@ TARGET."
 (define (input=? input1 input2)
   "Return true if INPUT1 and INPUT2 are equivalent."
   (match input1
-    ((label1 drv1 . outputs1)
+    ((label1 obj1 . outputs1)
      (match input2
-       ((label2 drv2 . outputs2)
+       ((label2 obj2 . outputs2)
         (and (string=? label1 label2)
              (equal? outputs1 outputs2)
-             (derivation=? drv1 drv2)))))))
+             (or (and (derivation? obj1) (derivation? obj2)
+                      (derivation=? obj1 obj2))
+                 (equal? obj1 obj2))))))))
 
 (define* (bag->derivation store bag
                           #:optional context)
@@ -1443,7 +1422,7 @@ error reporting."
       (bag->cross-derivation store bag)
       (let* ((system     (bag-system bag))
              (inputs     (bag-transitive-inputs bag))
-             (input-drvs (map (cut expand-input store context <> system)
+             (input-drvs (map (cut expand-input context <> #:native? #t)
                               inputs))
              (paths      (delete-duplicates
                           (append-map (match-lambda
@@ -1455,7 +1434,8 @@ error reporting."
         ;; It's possible that INPUTS contains packages that are not 'eq?' but
         ;; that lead to the same derivation.  Delete those duplicates to avoid
         ;; issues down the road, such as duplicate entries in '%build-inputs'.
-        (apply (bag-build bag)
+        ;; TODO: Change to monadic style.
+        (apply (store-lower (bag-build bag))
                store (bag-name bag)
                (delete-duplicates input-drvs input=?)
                #:search-paths paths
@@ -1470,13 +1450,13 @@ This is an internal procedure."
   (let* ((system      (bag-system bag))
          (target      (bag-target bag))
          (host        (bag-transitive-host-inputs bag))
-         (host-drvs   (map (cut expand-input store context <> system target)
+         (host-drvs   (map (cut expand-input context <> #:native? #f)
                            host))
          (target*     (bag-transitive-target-inputs bag))
-         (target-drvs (map (cut expand-input store context <> system)
+         (target-drvs (map (cut expand-input context <> #:native? #t)
                            target*))
          (build       (bag-transitive-build-inputs bag))
-         (build-drvs  (map (cut expand-input store context <> system)
+         (build-drvs  (map (cut expand-input context <> #:native? #t)
                            build))
          (all         (append build target* host))
          (paths       (delete-duplicates
@@ -1493,11 +1473,12 @@ This is an internal procedure."
                                     (_ '()))
                                    all))))
 
-    (apply (bag-build bag)
+    ;; TODO: Change to monadic style.
+    (apply (store-lower (bag-build bag))
            store (bag-name bag)
-           #:native-drvs (delete-duplicates build-drvs input=?)
-           #:target-drvs (delete-duplicates (append host-drvs target-drvs)
-                                            input=?)
+           #:build-inputs (delete-duplicates build-drvs input=?)
+           #:host-inputs (delete-duplicates host-drvs input=?)
+           #:target-inputs (delete-duplicates target-drvs input=?)
            #:search-paths paths
            #:native-search-paths npaths
            #:outputs (bag-outputs bag)
diff --git a/tests/builders.scm b/tests/builders.scm
index 2143c07..62ff991 100644
--- a/tests/builders.scm
+++ b/tests/builders.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2019 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2018, 2019 Ludovic Courtès 
<ludo@gnu.org>
 ;;; Copyright © 2021 Lars-Dominik Braun <lars@6xq.net>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -190,5 +190,23 @@ setup(
              python-dummy-fail-requirements
              python-dummy-fail-import
              python-dummy-fail-console-script)))
+(when (or (not (network-reachable?)) (shebang-too-long?))
+  (test-skip 1))
+
+(test-assert "gnu-build"
+  (let* ((url      "http://ftp.gnu.org/gnu/hello/hello-2.8.tar.gz";)
+         (hash     (nix-base32-string->bytevector
+                    "0wqd8sjmxfskrflaxywc7gqw7sfawrfvdxd9skxawzfgyy0pzdz6"))
+         (tarball  (url-fetch* %store url 'sha256 hash
+                               #:guile %bootstrap-guile))
+         (build    ((store-lower gnu-build) %store "hello-2.8"
+                    (%bootstrap-inputs)
+                    #:source tarball
+                    #:guile %bootstrap-guile
+                    #:search-paths %bootstrap-search-paths))
+         (out      (derivation->output-path build)))
+    (and (build-derivations %store (list (pk 'hello-drv build)))
+         (valid-path? %store out)
+         (file-exists? (string-append out "/bin/hello")))))
 
 (test-end "builders")
diff --git a/tests/packages.scm b/tests/packages.scm
index ff756c6..27072a3 100644
--- a/tests/packages.scm
+++ b/tests/packages.scm
@@ -868,9 +868,9 @@
                         (system system) (target target)
                         (build-inputs inputs)
                         (build
-                         (lambda* (store name inputs
-                                         #:key outputs system search-paths)
-                           search-paths)))))))
+                         (lambda* (name inputs
+                                        #:key outputs system search-paths)
+                           (abort-to-prompt p search-paths))))))))
          (x (list (search-path-specification
                    (variable "GUILE_LOAD_PATH")
                    (files '("share/guile/site/2.0")))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]