Subject: [bug#67266] [PATCH] build: zig-build-system: Add cross-compilation support

From: Ekaitz Zarraga <[email-masked]>
Date: Sat, 18 Nov 2023 23:33:50 +0100

* guix/build/zig-build-system.scm (zig-cross-build): New function
(lower): Add cross-compilation support
* guix/build-system/zig.scm (build): Add --target flag with target input
(check): Disable with cross compilation

Change-Id: I5f42ff897bfe00c92c6576900221a15ef210d669
---
 guix/build-system/zig.scm       | 118 ++++++++++++++++++++++++++------
 guix/build/zig-build-system.scm |   6 +-
 2 files changed, 102 insertions(+), 22 deletions(-)

diff --git a/guix/build-system/zig.scm b/guix/build-system/zig.scm
index 16b8a712cc..7f944f7d34 100644
--- a/guix/build-system/zig.scm
+++ b/guix/build-system/zig.scm
@@ -84,6 +84,79 @@ (define* (zig-build name inputs
                       #:system system
                       #:guile-for-build guile)))
 
+(define* (zig-cross-build name
+                          #:key
+                          source target
+                          build-inputs target-inputs host-inputs
+                          (phases '%standard-phases)
+                          (outputs '("out"))
+                          (search-paths '())
+                          (native-search-paths '())
+                          (tests? #t)
+                          (test-target #f)
+                          (zig-build-flags ''())
+                          (zig-test-flags ''())
+                          (zig-destdir "out")
+                          (zig-test-destdir "test-out")
+                          (zig-release-type #f)
+                          (system (%current-system))
+                          (guile #f)
+                          (imported-modules %zig-build-system-modules)
+                          (modules '((guix build zig-build-system)
+                                     (guix build utils))))
+  "Build SOURCE using Zig, and with INPUTS."
+  (define builder
+    (with-imported-modules imported-modules
+      #~(begin
+          (use-modules #$@(sexp->gexp modules))
+
+          (define %build-host-inputs
+            #+(input-tuples->gexp build-inputs))
+
+          (define %build-target-inputs
+            (append #$(input-tuples->gexp host-inputs)
+              #+(input-tuples->gexp target-inputs)))
+
+          (define %build-inputs
+            (append %build-host-inputs %build-target-inputs))
+
+          (define %outputs
+            #$(outputs->gexp outputs))
+
+          (zig-build #:name #$name
+                     #:source #+source
+                     #:system #$system
+                     #:phases #$phases
+                     #:outputs %outputs
+                     #:target #$target
+                     #:test-target #$test-target
+                     #:inputs %build-target-inputs
+                     #:native-inputs %build-host-inputs
+                     #:search-paths '#$(map search-path-specification->sexp
+                                            search-paths)
+                     #:native-search-paths '#$(map
+                                                search-path-specification->sexp
+                                                native-search-paths)
+                     #:zig-build-flags #$zig-build-flags
+                     #:zig-test-flags #$zig-test-flags
+                     #:zig-release-type #$zig-release-type
+                     #:zig-destdir #$zig-destdir
+                     #:zig-test-destdir #$zig-test-destdir
+                     #:tests? #$tests?
+                     #:search-paths '#$(sexp->gexp
+                                        (map search-path-specification->sexp
+                                             search-paths))))))
+
+  (mlet %store-monad ((guile (package->derivation (or guile (default-guile))
+                                                  system #:graft? #f)))
+        (gexp->derivation name builder
+                          #:system system
+                          #:target target
+                          #:graft? #f
+                          #:substitutable? substitutable?
+                          #:guile-for-build guile)))
+
+
 (define* (lower name
                 #:key source inputs native-inputs outputs system target
                 (zig (default-zig))
@@ -94,27 +167,30 @@ (define* (lower name
   (define private-keywords
     '(#:target #:zig #:inputs #:native-inputs #:outputs))
 
-  ;; TODO: support cross-compilation
-  ;; It's as simple as adding some build flags to `zig-build-flags`
-  ;; -Dtarget=aarch64-linux-musl, for example.
-  (and (not target)
-       (bag
-         (name name)
-         (system system)
-         (target target)
-         (host-inputs `(,@(if source
-                              `(("source" ,source))
-                              '())
-                        ,@inputs
-
-                        ;; Keep the standard inputs of 'gnu-build-system'
-                        ;; TODO: do we need this?
-                        ,@(standard-packages)))
-         (build-inputs `(("zig" ,zig)
-                         ,@native-inputs))
-         (outputs outputs)
-         (build zig-build)
-         (arguments (strip-keyword-arguments private-keywords arguments)))))
+  (bag
+    (name name)
+    (system system)
+    (target target)
+    (build-inputs `(,@(if source
+                        `(("source" ,source))
+                        '())
+                    ,@`(("zig" ,zig))
+                    ,@native-inputs
+                    ,@(if target '() inputs)
+                    ,@(if target
+                        ;; Use the standard cross inputs of
+                        ;; 'gnu-build-system'.
+                        (standard-cross-packages target 'host)
+                        '())
+                    ;; Keep the standard inputs of 'gnu-build-system'.
+                    ,@(standard-packages)))
+    (host-inputs (if target inputs '()))
+    (target-inputs (if target
+                     (standard-cross-packages target 'target)
+                     '()))
+    (outputs outputs)
+    (build (if target zig-cross-build zig-build))
+    (arguments (strip-keyword-arguments private-keywords arguments))))
 
 (define zig-build-system
   (build-system
diff --git a/guix/build/zig-build-system.scm b/guix/build/zig-build-system.scm
index d414ebfb17..0b0b0cdb33 100644
--- a/guix/build/zig-build-system.scm
+++ b/guix/build/zig-build-system.scm
@@ -47,6 +47,7 @@ (define* (build #:key
                 zig-build-flags
                 zig-release-type       ;; "safe", "fast" or "small" empty for a
                                        ;; debug build"
+                target
                 #:allow-other-keys)
   "Build a given Zig package."
 
@@ -56,6 +57,9 @@ (define* (build #:key
                      "--prefix-lib-dir"     "lib"
                      "--prefix-exe-dir"     "bin"
                      "--prefix-include-dir" "include"
+                     ,@(if target
+                         (list (string-append "-Dtarget=" target))
+                         '())
                      ,@(if zig-release-type
                          (list (string-append "-Drelease-" zig-release-type))
                          '())
@@ -67,7 +71,7 @@ (define* (check #:key tests?
                 zig-test-flags
                 #:allow-other-keys)
   "Run all the tests"
-  (when tests?
+  (when (and tests? (not target))
     (let ((old-destdir (getenv "DESTDIR")))
       (setenv "DESTDIR" "test-out") ;; Avoid colisions with the build output
       (let ((call `("zig" "build" "test"

base-commit: fc6bdaad57bf91609849623c5f485403c030cb49
-- 
2.41.0