unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / Atom feed
* [bug#48044] [PATCH] build/go: Support cross compiling.
@ 2021-04-26 18:32 Efraim Flashner
  2021-04-26 19:39 ` Maxime Devos
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Efraim Flashner @ 2021-04-26 18:32 UTC (permalink / raw)
  To: 48044; +Cc: Efraim Flashner

* guix/build-system/go.scm (lower): Only add target to private-keywords
when not cross compiling. Adjust bag depending if doing a native or
cross compile.
(go-cross-build): New procedure.
* guix/build/go-build-system.scm (setup-go-environment): Accept target
keyword. Add logic to choose correct target architecture when cross
compiling.
---
 guix/build-system/go.scm       | 137 +++++++++++++++++++++++++++++----
 guix/build/go-build-system.scm |  29 ++++++-
 2 files changed, 148 insertions(+), 18 deletions(-)

diff --git a/guix/build-system/go.scm b/guix/build-system/go.scm
index 8f55796e86..c9c8f5ba15 100644
--- a/guix/build-system/go.scm
+++ b/guix/build-system/go.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2016 Petter <petter@mykolab.ch>
 ;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
 ;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
+;;; Copyright © 2021 Efraim Flashner <efraim@flashner.co.il>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -96,24 +97,40 @@ commit hash and its date rather than a proper release tag."
                 #:rest arguments)
   "Return a bag for NAME."
   (define private-keywords
-    '(#:source #:target #:go #:inputs #:native-inputs))
+    `(#:source #:go #:inputs #:native-inputs
+      ,@(if target '() '(#:target))))
 
-  (and (not target)                               ;XXX: no cross-compilation
-       (bag
-         (name name)
-         (system system)
-         (host-inputs `(,@(if source
-                              `(("source" ,source))
-                              '())
-                        ,@inputs
+  (bag
+    (name name)
+    (system system)
+    (target target)
+    (build-inputs `(,@(if source
+                        `(("source" ,source))
+                        '())
+                     ,@`(("go" ,go))
+                     ,@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 '()))
 
-                        ;; Keep the standard inputs of 'gnu-build-system'.
-                        ,@(standard-packages)))
-         (build-inputs `(("go" ,go)
-                         ,@native-inputs))
-         (outputs outputs)
-         (build go-build)
-         (arguments (strip-keyword-arguments private-keywords arguments)))))
+    ;; The cross-libc is really a target package, but for bootstrapping
+    ;; reasons, we can't put it in 'host-inputs'.  Namely, 'cross-gcc' is a
+    ;; native package, so it would end up using a "native" variant of
+    ;; 'cross-libc' (built with 'gnu-build'), whereas all the other packages
+    ;; would use a target variant (built with 'gnu-cross-build'.)
+    (target-inputs (if target
+                     (standard-cross-packages target 'target)
+                     '()))
+
+    (outputs outputs)
+    (build (if target go-cross-build go-build))
+    (arguments (strip-keyword-arguments private-keywords arguments))))
 
 (define* (go-build store name inputs
                    #:key
@@ -174,6 +191,94 @@ commit hash and its date rather than a proper release tag."
                                 #:outputs outputs
                                 #:guile-for-build guile-for-build))
 
+(define* (go-cross-build store name
+                         #:key
+                         target native-drvs target-drvs
+                         (phases '(@ (guix build go-build-system)
+                                     %standard-phases))
+                         (outputs '("out"))
+                         (search-paths '())
+                         (native-search-paths '())
+                         (install-source? #t)
+                         (import-path "")
+                         (unpack-path "")
+                         (build-flags ''())
+                         (tests? #f) ; nothing can be done
+                         (allow-go-reference? #f)
+                         (system (%current-system))
+                         (guile #f)
+                         (imported-modules %go-build-system-modules)
+                         (modules '((guix build go-build-system)
+                                    (guix build union)
+                                    (guix build utils))))
+  "Cross-build NAME using GO, where TARGET is a GNU triplet and with INPUTS."
+  (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))
+
+         (go-build #:name ,name
+                   #:source ,(match (assoc-ref native-drvs "source")
+                                    (((? derivation? source))
+                                     (derivation->output-path source))
+                                    ((source)
+                                     source)
+                                    (source
+                                      source))
+                   #:system ,system
+                   #:phases ,phases
+                   #:outputs %outputs
+                   #:target ,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)
+                   #:install-source? ,install-source?
+                   #:import-path ,import-path
+                   #:unpack-path ,unpack-path
+                   #:build-flags ,build-flags
+                   #:tests? ,tests?
+                   #:allow-go-reference? ,allow-go-reference?
+                   #: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
+                                  #:system system
+                                  #:inputs (append native-drvs target-drvs)
+                                  #:outputs outputs
+                                  #:modules imported-modules
+                                  #:guile-for-build guile-for-build))
+
 (define go-build-system
   (build-system
     (name 'go)
diff --git a/guix/build/go-build-system.scm b/guix/build/go-build-system.scm
index 227df820db..5436e19854 100644
--- a/guix/build/go-build-system.scm
+++ b/guix/build/go-build-system.scm
@@ -4,7 +4,7 @@
 ;;; Copyright © 2019 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;; Copyright © 2020 Jack Hill <jackhill@jackhill.us>
 ;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
-;;; Copyright © 2020 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2020, 2021 Efraim Flashner <efraim@flashner.co.il>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -131,7 +131,7 @@
 ;;
 ;; Code:
 
-(define* (setup-go-environment #:key inputs outputs #:allow-other-keys)
+(define* (setup-go-environment #:key inputs outputs target #:allow-other-keys)
   "Prepare a Go build environment for INPUTS and OUTPUTS.  Build a file system
 union of INPUTS.  Export GOPATH, which helps the compiler find the source code
 of the package being built and its dependencies, and GOBIN, which determines
@@ -149,6 +149,31 @@ dependencies, so it should be self-contained."
   ;; GOPATH behavior.
   (setenv "GO111MODULE" "off")
   (setenv "GOBIN" (string-append (assoc-ref outputs "out") "/bin"))
+
+  ;; Cross-build
+  (when target
+    ;; Separate the 3 parts of the target-triplet
+    (let* ((first-dash (string-index target #\-))
+           (second-dash (string-index target #\- (1+ first-dash)))
+           (machine (string-take target first-dash)))
+      (setenv "GOARCH" (match machine
+                         ("aarch64" "arm64")
+                         ("powerpc64le" "ppc64le")
+                         ("powerpc64" "ppc64")
+                         ("i686" "386")
+                         ("x86_64" "amd64")
+                         ("mips64el" "mips64le")
+                         (_ machine)))
+      ;; We really only support targeting Linux and mingw.
+      (setenv "GOOS" (if (string-contains target "mingw")
+                       "windows"
+                       "linux"))
+      (setenv "GOARM" "7")  ; Default is 6, target our armhf-linux architecture.
+      ;; (setenv "GOMIPS" "hardfloat")      ; The default.
+      ;; (setenv "GOMIPS64" "hardfloat")    ; The default.
+      ;; (setenv "GOPPC64" "power8")        ; The default.
+      ))
+
   (let ((tmpdir (tmpnam)))
     (match (go-inputs inputs)
       (((names . directories) ...)

base-commit: f365d48909156ad754a2ade45375f45b54b06bbc
-- 
2.31.1





^ permalink raw reply	[flat|nested] 7+ messages in thread

* [bug#48044] [PATCH] build/go: Support cross compiling.
  2021-04-26 18:32 [bug#48044] [PATCH] build/go: Support cross compiling Efraim Flashner
@ 2021-04-26 19:39 ` Maxime Devos
  2021-08-22 10:20 ` [bug#48044] [PATCH v3] " Efraim Flashner
  2021-08-22 18:52 ` [bug#48044] " Sarah Morgensen
  2 siblings, 0 replies; 7+ messages in thread
From: Maxime Devos @ 2021-04-26 19:39 UTC (permalink / raw)
  To: Efraim Flashner, 48044

[-- Attachment #1: Type: text/plain, Size: 983 bytes --]

> +      ;; We really only support targeting Linux and mingw.
> +      (setenv "GOOS" (if (string-contains target "mingw")
> +                       "windows"
> +                       "linux"))

If only Linux and mingw is supported, perhaps some kind of error
could be thrown if 'target' does not contain either "mingw" or "linux",
to avoid silently compiling for the wrong operating system?  There is
the Hurd as well for example.

I would recommend throwing the error (or returning #f?) from lower,
to notify the user cross-compilation is not possible as early as possible.

> +      (setenv "GOARM" "7")  ; Default is 6, target our armhf-linux architecture.

Would it be possible to only set that variable when targetting armhf-linux?
Setting this when targetting other architectures seems unlikely to cause issues,
but still seems subtly wrong to me, for some value of subtle.

Note: I do not know much about go and did not test this.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [bug#48044] [PATCH v3] build/go: Support cross compiling.
  2021-04-26 18:32 [bug#48044] [PATCH] build/go: Support cross compiling Efraim Flashner
  2021-04-26 19:39 ` Maxime Devos
@ 2021-08-22 10:20 ` Efraim Flashner
  2021-09-14  8:38   ` bug#48044: " Efraim Flashner
  2021-08-22 18:52 ` [bug#48044] " Sarah Morgensen
  2 siblings, 1 reply; 7+ messages in thread
From: Efraim Flashner @ 2021-08-22 10:20 UTC (permalink / raw)
  To: 48044, iskarian, leo; +Cc: Efraim Flashner

* guix/build-system/go.scm (lower): Only add target to private-keywords
when not cross compiling. Adjust bag depending if doing a native or
cross compile.
(%go-build-system-modules): Use source-module-closure, add (guix utils).
(go-cross-build): New procedure.
* guix/build/go-build-system.scm (setup-go-environment): Accept target
keyword. Add logic to choose correct target architecture when cross
compiling.
---

Third version of this patch. I think I'm ready to push it. I don't love
using source-module-closure to include (guix utils), but I need it for
gnu-triplet->nix-system in setup-go-environment instead of the custom
parsing I was doing before.

---

 guix/build-system/go.scm       | 146 ++++++++++++++++++++++++++++-----
 guix/build/go-build-system.scm |  37 ++++++++-
 2 files changed, 162 insertions(+), 21 deletions(-)

diff --git a/guix/build-system/go.scm b/guix/build-system/go.scm
index 8f55796e86..fe0c884b62 100644
--- a/guix/build-system/go.scm
+++ b/guix/build-system/go.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2016 Petter <petter@mykolab.ch>
 ;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
 ;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
+;;; Copyright © 2021 Efraim Flashner <efraim@flashner.co.il>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -20,6 +21,7 @@
 
 (define-module (guix build-system go)
   #:use-module (guix utils)
+  #:use-module (guix modules)
   #:use-module (guix derivations)
   #:use-module (guix search-paths)
   #:use-module (guix build-system)
@@ -80,9 +82,11 @@ commit hash and its date rather than a proper release tag."
 
 (define %go-build-system-modules
   ;; Build-side modules imported and used by default.
-  `((guix build go-build-system)
-    (guix build union)
-    ,@%gnu-build-system-modules))
+  (source-module-closure
+    `((guix build go-build-system)
+      (guix utils)
+      (guix build union)
+      ,@%gnu-build-system-modules)))
 
 (define (default-go)
   ;; Lazily resolve the binding to avoid a circular dependency.
@@ -96,24 +100,40 @@ commit hash and its date rather than a proper release tag."
                 #:rest arguments)
   "Return a bag for NAME."
   (define private-keywords
-    '(#:source #:target #:go #:inputs #:native-inputs))
+    `(#:source #:go #:inputs #:native-inputs
+      ,@(if target '() '(#:target))))
 
-  (and (not target)                               ;XXX: no cross-compilation
-       (bag
-         (name name)
-         (system system)
-         (host-inputs `(,@(if source
-                              `(("source" ,source))
-                              '())
-                        ,@inputs
+  (bag
+    (name name)
+    (system system)
+    (target target)
+    (build-inputs `(,@(if source
+                        `(("source" ,source))
+                        '())
+                     ,@`(("go" ,go))
+                     ,@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 '()))
 
-                        ;; Keep the standard inputs of 'gnu-build-system'.
-                        ,@(standard-packages)))
-         (build-inputs `(("go" ,go)
-                         ,@native-inputs))
-         (outputs outputs)
-         (build go-build)
-         (arguments (strip-keyword-arguments private-keywords arguments)))))
+    ;; The cross-libc is really a target package, but for bootstrapping
+    ;; reasons, we can't put it in 'host-inputs'.  Namely, 'cross-gcc' is a
+    ;; native package, so it would end up using a "native" variant of
+    ;; 'cross-libc' (built with 'gnu-build'), whereas all the other packages
+    ;; would use a target variant (built with 'gnu-cross-build'.)
+    (target-inputs (if target
+                     (standard-cross-packages target 'target)
+                     '()))
+
+    (outputs outputs)
+    (build (if target go-cross-build go-build))
+    (arguments (strip-keyword-arguments private-keywords arguments))))
 
 (define* (go-build store name inputs
                    #:key
@@ -174,6 +194,94 @@ commit hash and its date rather than a proper release tag."
                                 #:outputs outputs
                                 #:guile-for-build guile-for-build))
 
+(define* (go-cross-build store name
+                         #:key
+                         target native-drvs target-drvs
+                         (phases '(@ (guix build go-build-system)
+                                     %standard-phases))
+                         (outputs '("out"))
+                         (search-paths '())
+                         (native-search-paths '())
+                         (install-source? #t)
+                         (import-path "")
+                         (unpack-path "")
+                         (build-flags ''())
+                         (tests? #f) ; nothing can be done
+                         (allow-go-reference? #f)
+                         (system (%current-system))
+                         (guile #f)
+                         (imported-modules %go-build-system-modules)
+                         (modules '((guix build go-build-system)
+                                    (guix build union)
+                                    (guix build utils))))
+  "Cross-build NAME using GO, where TARGET is a GNU triplet and with INPUTS."
+  (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))
+
+         (go-build #:name ,name
+                   #:source ,(match (assoc-ref native-drvs "source")
+                                    (((? derivation? source))
+                                     (derivation->output-path source))
+                                    ((source)
+                                     source)
+                                    (source
+                                      source))
+                   #:system ,system
+                   #:phases ,phases
+                   #:outputs %outputs
+                   #:target ,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)
+                   #:install-source? ,install-source?
+                   #:import-path ,import-path
+                   #:unpack-path ,unpack-path
+                   #:build-flags ,build-flags
+                   #:tests? ,tests?
+                   #:allow-go-reference? ,allow-go-reference?
+                   #: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
+                                  #:system system
+                                  #:inputs (append native-drvs target-drvs)
+                                  #:outputs outputs
+                                  #:modules imported-modules
+                                  #:guile-for-build guile-for-build))
+
 (define go-build-system
   (build-system
     (name 'go)
diff --git a/guix/build/go-build-system.scm b/guix/build/go-build-system.scm
index 227df820db..701ccf0011 100644
--- a/guix/build/go-build-system.scm
+++ b/guix/build/go-build-system.scm
@@ -4,7 +4,7 @@
 ;;; Copyright © 2019 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;; Copyright © 2020 Jack Hill <jackhill@jackhill.us>
 ;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
-;;; Copyright © 2020 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2020, 2021 Efraim Flashner <efraim@flashner.co.il>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -25,6 +25,7 @@
   #:use-module ((guix build gnu-build-system) #:prefix gnu:)
   #:use-module (guix build union)
   #:use-module (guix build utils)
+  #:use-module ((guix utils) #:hide (package-name->name+version))
   #:use-module (ice-9 match)
   #:use-module (ice-9 ftw)
   #:use-module (srfi srfi-1)
@@ -131,7 +132,7 @@
 ;;
 ;; Code:
 
-(define* (setup-go-environment #:key inputs outputs #:allow-other-keys)
+(define* (setup-go-environment #:key inputs outputs target #:allow-other-keys)
   "Prepare a Go build environment for INPUTS and OUTPUTS.  Build a file system
 union of INPUTS.  Export GOPATH, which helps the compiler find the source code
 of the package being built and its dependencies, and GOBIN, which determines
@@ -149,6 +150,38 @@ dependencies, so it should be self-contained."
   ;; GOPATH behavior.
   (setenv "GO111MODULE" "off")
   (setenv "GOBIN" (string-append (assoc-ref outputs "out") "/bin"))
+
+  ;; Cross-build
+  (when target
+    ;; Parse the nix-system equivalent of the target and set the
+    ;; target for compilation accordingly.
+    (let* ((system (gnu-triplet->nix-system target))
+           (dash   (string-index system #\-))
+           (arch   (substring system 0 dash))
+           (os     (substring system (+ 1 dash))))
+      (setenv "GOARCH" (match arch
+                         ("aarch64" "arm64")
+                         ("armhf" "arm")
+                         ("powerpc64le" "ppc64le")
+                         ("powerpc64" "ppc64")
+                         ("i686" "386")
+                         ("x86_64" "amd64")
+                         ("mips64el" "mips64le")
+                         (_ arch)))
+      (setenv "GOOS" (match os
+                       ((or "mingw" "cygwin") "windows")
+                       (_ os)))
+      (match arch
+        ((or "arm" "armhf")
+         (setenv "GOARM" "7"))
+        ((or "mips" "mipsel")
+         (setenv "GOMIPS" "hardfloat"))
+        ((or "mips64" "mips64el")
+         (setenv "GOMIPS64" "hardfloat"))
+        ((or "powerpc64" "powerpc64le")
+         (setenv "GOPPC64" "power8"))
+        (_ #t))))
+
   (let ((tmpdir (tmpnam)))
     (match (go-inputs inputs)
       (((names . directories) ...)

base-commit: 9e3b68203cba2b1bd96e524d3ae9dfc3336a72f7
-- 
2.33.0





^ permalink raw reply	[flat|nested] 7+ messages in thread

* [bug#48044] [PATCH v3] build/go: Support cross compiling.
  2021-04-26 18:32 [bug#48044] [PATCH] build/go: Support cross compiling Efraim Flashner
  2021-04-26 19:39 ` Maxime Devos
  2021-08-22 10:20 ` [bug#48044] [PATCH v3] " Efraim Flashner
@ 2021-08-22 18:52 ` Sarah Morgensen
  2021-08-23  9:02   ` Efraim Flashner
  2021-08-23  9:26   ` Efraim Flashner
  2 siblings, 2 replies; 7+ messages in thread
From: Sarah Morgensen @ 2021-08-22 18:52 UTC (permalink / raw)
  To: Efraim Flashner; +Cc: 48044, leo

Hi Efraim,

Thanks for doing this work!  I'm excited to see it in action.

Efraim Flashner <efraim@flashner.co.il> writes:

> * guix/build-system/go.scm (lower): Only add target to private-keywords
> when not cross compiling. Adjust bag depending if doing a native or
> cross compile.
> (%go-build-system-modules): Use source-module-closure, add (guix utils).
> (go-cross-build): New procedure.
> * guix/build/go-build-system.scm (setup-go-environment): Accept target
> keyword. Add logic to choose correct target architecture when cross
> compiling.
> ---
>
> Third version of this patch. I think I'm ready to push it. I don't love
> using source-module-closure to include (guix utils), but I need it for
> gnu-triplet->nix-system in setup-go-environment instead of the custom
> parsing I was doing before.

Can you do the parsing host-side and pass e.g. TARGET-GOOS/TARGET-GOARCH
keyword arguments to the build-side?

> -(define* (setup-go-environment #:key inputs outputs #:allow-other-keys)
> +(define* (setup-go-environment #:key inputs outputs target #:allow-other-keys)
>    "Prepare a Go build environment for INPUTS and OUTPUTS.  Build a file system
>  union of INPUTS.  Export GOPATH, which helps the compiler find the source code
>  of the package being built and its dependencies, and GOBIN, which determines
> @@ -149,6 +150,38 @@ dependencies, so it should be self-contained."
>    ;; GOPATH behavior.
>    (setenv "GO111MODULE" "off")
>    (setenv "GOBIN" (string-append (assoc-ref outputs "out") "/bin"))
> +
> +  ;; Cross-build
> +  (when target
> +    ;; Parse the nix-system equivalent of the target and set the
> +    ;; target for compilation accordingly.
> +    (let* ((system (gnu-triplet->nix-system target))
> +           (dash   (string-index system #\-))
> +           (arch   (substring system 0 dash))
> +           (os     (substring system (+ 1 dash))))

And then, if this parsing is host-side, you can probably just do
something like

--8<---------------cut here---------------start------------->8---
(match (string-split (gnu-triplet->nix-system target) #\-)
  ((arch os)
   [...]
--8<---------------cut here---------------end--------------->8---

> +      (match arch
> +        ((or "arm" "armhf")
> +         (setenv "GOARM" "7"))
> +        ((or "mips" "mipsel")
> +         (setenv "GOMIPS" "hardfloat"))
> +        ((or "mips64" "mips64el")
> +         (setenv "GOMIPS64" "hardfloat"))
> +        ((or "powerpc64" "powerpc64le")
> +         (setenv "GOPPC64" "power8"))
> +        (_ #t))))

Are these choices obvious for those compiling for those architectures?
If not, this could probably do with some documentation on why these were
chosen.  (I note that these are all Go's defaults with the exception of
GOARM).

--
Sarah




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [bug#48044] [PATCH v3] build/go: Support cross compiling.
  2021-08-22 18:52 ` [bug#48044] " Sarah Morgensen
@ 2021-08-23  9:02   ` Efraim Flashner
  2021-08-23  9:26   ` Efraim Flashner
  1 sibling, 0 replies; 7+ messages in thread
From: Efraim Flashner @ 2021-08-23  9:02 UTC (permalink / raw)
  To: Sarah Morgensen; +Cc: 48044, leo

[-- Attachment #1: Type: text/plain, Size: 3859 bytes --]

On Sun, Aug 22, 2021 at 11:52:29AM -0700, Sarah Morgensen wrote:
> Hi Efraim,
> 
> Thanks for doing this work!  I'm excited to see it in action.
> 
> Efraim Flashner <efraim@flashner.co.il> writes:
> 
> > * guix/build-system/go.scm (lower): Only add target to private-keywords
> > when not cross compiling. Adjust bag depending if doing a native or
> > cross compile.
> > (%go-build-system-modules): Use source-module-closure, add (guix utils).
> > (go-cross-build): New procedure.
> > * guix/build/go-build-system.scm (setup-go-environment): Accept target
> > keyword. Add logic to choose correct target architecture when cross
> > compiling.
> > ---
> >
> > Third version of this patch. I think I'm ready to push it. I don't love
> > using source-module-closure to include (guix utils), but I need it for
> > gnu-triplet->nix-system in setup-go-environment instead of the custom
> > parsing I was doing before.
> 
> Can you do the parsing host-side and pass e.g. TARGET-GOOS/TARGET-GOARCH
> keyword arguments to the build-side?

I'll have to see if there's somewhere I can slot that in. We already
have target, but that's what we're parsing now.

I guess if I add them as a keywords then we can build for targets that
go supports but which Guix doesn't.

> > -(define* (setup-go-environment #:key inputs outputs #:allow-other-keys)
> > +(define* (setup-go-environment #:key inputs outputs target #:allow-other-keys)
> >    "Prepare a Go build environment for INPUTS and OUTPUTS.  Build a file system
> >  union of INPUTS.  Export GOPATH, which helps the compiler find the source code
> >  of the package being built and its dependencies, and GOBIN, which determines
> > @@ -149,6 +150,38 @@ dependencies, so it should be self-contained."
> >    ;; GOPATH behavior.
> >    (setenv "GO111MODULE" "off")
> >    (setenv "GOBIN" (string-append (assoc-ref outputs "out") "/bin"))
> > +
> > +  ;; Cross-build
> > +  (when target
> > +    ;; Parse the nix-system equivalent of the target and set the
> > +    ;; target for compilation accordingly.
> > +    (let* ((system (gnu-triplet->nix-system target))
> > +           (dash   (string-index system #\-))
> > +           (arch   (substring system 0 dash))
> > +           (os     (substring system (+ 1 dash))))
> 
> And then, if this parsing is host-side, you can probably just do
> something like
> 
> --8<---------------cut here---------------start------------->8---
> (match (string-split (gnu-triplet->nix-system target) #\-)
>   ((arch os)
>    [...]
> --8<---------------cut here---------------end--------------->8---

I like the way this looks much better. Even if we did just parse the
gnu-triplet we'd have our special case for arm-linux-gnueabihf (unless
we ignored it, as I did below). 

> > +      (match arch
> > +        ((or "arm" "armhf")
> > +         (setenv "GOARM" "7"))
> > +        ((or "mips" "mipsel")
> > +         (setenv "GOMIPS" "hardfloat"))
> > +        ((or "mips64" "mips64el")
> > +         (setenv "GOMIPS64" "hardfloat"))
> > +        ((or "powerpc64" "powerpc64le")
> > +         (setenv "GOPPC64" "power8"))
> > +        (_ #t))))
> 
> Are these choices obvious for those compiling for those architectures?
> If not, this could probably do with some documentation on why these were
> chosen.  (I note that these are all Go's defaults with the exception of
> GOARM).

For the mips I did just copy from the Go documentation, but for arm and
ppc64 I wanted to make sure we targeted the same systems that Guix
already supports.

> 
> --
> Sarah

Thanks for taking a look at it.

-- 
Efraim Flashner   <efraim@flashner.co.il>   רנשלפ םירפא
GPG key = A28B F40C 3E55 1372 662D  14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [bug#48044] [PATCH v3] build/go: Support cross compiling.
  2021-08-22 18:52 ` [bug#48044] " Sarah Morgensen
  2021-08-23  9:02   ` Efraim Flashner
@ 2021-08-23  9:26   ` Efraim Flashner
  1 sibling, 0 replies; 7+ messages in thread
From: Efraim Flashner @ 2021-08-23  9:26 UTC (permalink / raw)
  To: Sarah Morgensen; +Cc: 48044, leo


[-- Attachment #1.1: Type: text/plain, Size: 697 bytes --]

New version of the patch. I moved the logic to figure out GOOS/GOARCH to
the host side and added keywords to pass the information along to the
build side.

With a properly configured go package and perhaps some additional
qemu-binfmt targets packages like this should work:

(use-modules (guix packages)
             (gnu packages syncthing))
(package
  (inherit syncthing)
  (arguments
   `(,@(package-arguments syncthing)
     #:goos "plan9"
     #:goarch "amd64")))

-- 
Efraim Flashner   <efraim@flashner.co.il>   רנשלפ םירפא
GPG key = A28B F40C 3E55 1372 662D  14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted

[-- Attachment #1.2: v4-0001-build-go-Support-cross-compiling.patch --]
[-- Type: text/plain, Size: 12490 bytes --]

From c4f25c1759b5d8cff1f3198144b2495b502db99c Mon Sep 17 00:00:00 2001
Message-Id: <c4f25c1759b5d8cff1f3198144b2495b502db99c.1629710553.git.efraim@flashner.co.il>
From: Efraim Flashner <efraim@flashner.co.il>
Date: Mon, 26 Apr 2021 21:13:06 +0300
Subject: [PATCH v4] build/go: Support cross compiling.

* guix/build-system/go.scm (go-target): New procedure.
(go-build): Add goarch, goos keywords.
(lower): Only add target to private-keywords when not cross compiling.
Adjust bag depending if doing a native or cross compile.
(go-cross-build): New procedure.
* guix/build/go-build-system.scm (setup-go-environment): Accept goarch,
goos keywords. Set go environment variables based on target architecture.
---
 guix/build-system/go.scm       | 164 +++++++++++++++++++++++++++++----
 guix/build/go-build-system.scm |  19 +++-
 2 files changed, 165 insertions(+), 18 deletions(-)

diff --git a/guix/build-system/go.scm b/guix/build-system/go.scm
index 8f55796e86..55db449cdf 100644
--- a/guix/build-system/go.scm
+++ b/guix/build-system/go.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2016 Petter <petter@mykolab.ch>
 ;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
 ;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
+;;; Copyright © 2021 Efraim Flashner <efraim@flashner.co.il>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -27,6 +28,7 @@
   #:use-module (guix packages)
   #:use-module (ice-9 match)
   #:use-module (ice-9 regex)
+  #:use-module (srfi srfi-1)
   #:export (%go-build-system-modules
             go-build
             go-build-system
@@ -78,6 +80,24 @@ present) if a pseudo-version pattern is not recognized."
 commit hash and its date rather than a proper release tag."
   (regexp-exec %go-pseudo-version-rx version))
 
+(define (go-target target)
+    ;; Parse the nix-system equivalent of the target and set the
+    ;; target for compilation accordingly.
+    (match (string-split (gnu-triplet->nix-system target) #\-)
+      ((arch os)
+       (list (match arch
+               ("aarch64" "arm64")
+               ("armhf" "arm")
+               ("powerpc64le" "ppc64le")
+               ("powerpc64" "ppc64")
+               ("i686" "386")
+               ("x86_64" "amd64")
+               ("mips64el" "mips64le")
+               (_ arch))
+             (match os
+               ((or "mingw32" "cygwin") "windows")
+               (_ os))))))
+
 (define %go-build-system-modules
   ;; Build-side modules imported and used by default.
   `((guix build go-build-system)
@@ -96,24 +116,40 @@ commit hash and its date rather than a proper release tag."
                 #:rest arguments)
   "Return a bag for NAME."
   (define private-keywords
-    '(#:source #:target #:go #:inputs #:native-inputs))
+    `(#:source #:go #:inputs #:native-inputs
+      ,@(if target '() '(#:target))))
 
-  (and (not target)                               ;XXX: no cross-compilation
-       (bag
-         (name name)
-         (system system)
-         (host-inputs `(,@(if source
-                              `(("source" ,source))
-                              '())
-                        ,@inputs
+  (bag
+    (name name)
+    (system system)
+    (target target)
+    (build-inputs `(,@(if source
+                        `(("source" ,source))
+                        '())
+                     ,@`(("go" ,go))
+                     ,@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 '()))
 
-                        ;; Keep the standard inputs of 'gnu-build-system'.
-                        ,@(standard-packages)))
-         (build-inputs `(("go" ,go)
-                         ,@native-inputs))
-         (outputs outputs)
-         (build go-build)
-         (arguments (strip-keyword-arguments private-keywords arguments)))))
+    ;; The cross-libc is really a target package, but for bootstrapping
+    ;; reasons, we can't put it in 'host-inputs'.  Namely, 'cross-gcc' is a
+    ;; native package, so it would end up using a "native" variant of
+    ;; 'cross-libc' (built with 'gnu-build'), whereas all the other packages
+    ;; would use a target variant (built with 'gnu-cross-build'.)
+    (target-inputs (if target
+                     (standard-cross-packages target 'target)
+                     '()))
+
+    (outputs outputs)
+    (build (if target go-cross-build go-build))
+    (arguments (strip-keyword-arguments private-keywords arguments))))
 
 (define* (go-build store name inputs
                    #:key
@@ -128,6 +164,8 @@ commit hash and its date rather than a proper release tag."
                    (tests? #t)
                    (allow-go-reference? #f)
                    (system (%current-system))
+                   (goarch (first (go-target (%current-system))))
+                   (goos (last (go-target (%current-system))))
                    (guile #f)
                    (imported-modules %go-build-system-modules)
                    (modules '((guix build go-build-system)
@@ -147,6 +185,8 @@ commit hash and its date rather than a proper release tag."
                 #:system ,system
                 #:phases ,phases
                 #:outputs %outputs
+                #:goarch ,goarch
+                #:goos ,goos
                 #:search-paths ',(map search-path-specification->sexp
                                       search-paths)
                 #:install-source? ,install-source?
@@ -174,6 +214,98 @@ commit hash and its date rather than a proper release tag."
                                 #:outputs outputs
                                 #:guile-for-build guile-for-build))
 
+(define* (go-cross-build store name
+                         #:key
+                         target native-drvs target-drvs
+                         (phases '(@ (guix build go-build-system)
+                                     %standard-phases))
+                         (outputs '("out"))
+                         (search-paths '())
+                         (native-search-paths '())
+                         (install-source? #t)
+                         (import-path "")
+                         (unpack-path "")
+                         (build-flags ''())
+                         (tests? #f) ; nothing can be done
+                         (allow-go-reference? #f)
+                         (system (%current-system))
+                         (goarch (first (go-target target)))
+                         (goos (last (go-target target)))
+                         (guile #f)
+                         (imported-modules %go-build-system-modules)
+                         (modules '((guix build go-build-system)
+                                    (guix build union)
+                                    (guix build utils))))
+  "Cross-build NAME using GO, where TARGET is a GNU triplet and with INPUTS."
+  (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))
+
+         (go-build #:name ,name
+                   #:source ,(match (assoc-ref native-drvs "source")
+                                    (((? derivation? source))
+                                     (derivation->output-path source))
+                                    ((source)
+                                     source)
+                                    (source
+                                      source))
+                   #:system ,system
+                   #:phases ,phases
+                   #:outputs %outputs
+                   #:target ,target
+                   #:goarch ,goarch
+                   #:goos ,goos
+                   #: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)
+                   #:install-source? ,install-source?
+                   #:import-path ,import-path
+                   #:unpack-path ,unpack-path
+                   #:build-flags ,build-flags
+                   #:tests? ,tests?
+                   #:allow-go-reference? ,allow-go-reference?
+                   #: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
+                                  #:system system
+                                  #:inputs (append native-drvs target-drvs)
+                                  #:outputs outputs
+                                  #:modules imported-modules
+                                  #:guile-for-build guile-for-build))
+
 (define go-build-system
   (build-system
     (name 'go)
diff --git a/guix/build/go-build-system.scm b/guix/build/go-build-system.scm
index 227df820db..918ce074ad 100644
--- a/guix/build/go-build-system.scm
+++ b/guix/build/go-build-system.scm
@@ -4,7 +4,7 @@
 ;;; Copyright © 2019 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;; Copyright © 2020 Jack Hill <jackhill@jackhill.us>
 ;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
-;;; Copyright © 2020 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2020, 2021 Efraim Flashner <efraim@flashner.co.il>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -131,7 +131,7 @@
 ;;
 ;; Code:
 
-(define* (setup-go-environment #:key inputs outputs #:allow-other-keys)
+(define* (setup-go-environment #:key inputs outputs goos goarch #:allow-other-keys)
   "Prepare a Go build environment for INPUTS and OUTPUTS.  Build a file system
 union of INPUTS.  Export GOPATH, which helps the compiler find the source code
 of the package being built and its dependencies, and GOBIN, which determines
@@ -149,6 +149,21 @@ dependencies, so it should be self-contained."
   ;; GOPATH behavior.
   (setenv "GO111MODULE" "off")
   (setenv "GOBIN" (string-append (assoc-ref outputs "out") "/bin"))
+
+  ;; Make sure we're building for the correct architecture and OS.
+  (setenv "GOARCH" goarch)
+  (setenv "GOOS" goos)
+  (match goarch
+    ("arm"
+     (setenv "GOARM" "7"))
+    ((or "mips" "mipsel")
+     (setenv "GOMIPS" "hardfloat"))
+    ((or "mips64" "mips64le")
+     (setenv "GOMIPS64" "hardfloat"))
+    ((or "ppc64" "ppc64le")
+     (setenv "GOPPC64" "power8"))
+    (_ #t))
+
   (let ((tmpdir (tmpnam)))
     (match (go-inputs inputs)
       (((names . directories) ...)

base-commit: bb5f395a08deacb799ef1e085863ba01a5f05e70
-- 
2.33.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#48044: [PATCH v3] build/go: Support cross compiling.
  2021-08-22 10:20 ` [bug#48044] [PATCH v3] " Efraim Flashner
@ 2021-09-14  8:38   ` Efraim Flashner
  0 siblings, 0 replies; 7+ messages in thread
From: Efraim Flashner @ 2021-09-14  8:38 UTC (permalink / raw)
  To: 48044-done

[-- Attachment #1: Type: text/plain, Size: 236 bytes --]

v4 pushed in the end.

-- 
Efraim Flashner   <efraim@flashner.co.il>   רנשלפ םירפא
GPG key = A28B F40C 3E55 1372 662D  14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-09-14  8:45 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-26 18:32 [bug#48044] [PATCH] build/go: Support cross compiling Efraim Flashner
2021-04-26 19:39 ` Maxime Devos
2021-08-22 10:20 ` [bug#48044] [PATCH v3] " Efraim Flashner
2021-09-14  8:38   ` bug#48044: " Efraim Flashner
2021-08-22 18:52 ` [bug#48044] " Sarah Morgensen
2021-08-23  9:02   ` Efraim Flashner
2021-08-23  9:26   ` Efraim Flashner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).