hako pushed a commit to branch wip-zig-bootstrap
in repository guix.

commit a41f66503b1cdd5b455e55fd1a684455caa0ae97
Author: Hilton Chain <[email protected]>
AuthorDate: Wed Nov 20 07:41:06 2024 +0800

    build-system: zig: Support Zig package manager.
    
    * guix/build-system/zig.scm (zig-build,zig-cross-build)
    [#:install-source?,#:skip-build?]: New arguments.
    [#:tests?]: Honor #:skip-build?.
    * guix/build/zig-build-system.scm (zig-source-install-path)
    (zig-input-install-path,unpack-dependencies): New procedures.
    (%standard-phases): Add 'unpack-dependencies.
    (build,install): Honor #:skip-build?.
    * doc/guix.texi (Build Systems)[zig-build-system]: Update documentation.
    * gnu/packages/zig.scm (zig-0.9)[native-search-paths]: Add
    GUIX_ZIG_PACKAGE_PATH.
    Use search paths defined in (guix search-paths).
    (add-build.zig.zon,rename-zig-dependencies): New procedures.
    * gnu/packages/ncdu.scm (ncdu)[arguments]: Don't install source.
    * gnu/packages/zig-xyz.scm (river,tigerbeetle,zig-zls)[arguments]: Likewise.
    
    Change-Id: I76ba483b67fdd26b33fa707a8d3cccc9f6a37e76
---
 doc/guix.texi                   | 35 ++++++++++-----
 gnu/packages/ncdu.scm           |  3 +-
 gnu/packages/zig-xyz.scm        |  7 ++-
 gnu/packages/zig.scm            | 60 +++++++++++++++++++++-----
 guix/build-system/zig.scm       | 20 ++++++---
 guix/build/zig-build-system.scm | 95 +++++++++++++++++++++++++++++++----------
 6 files changed, 168 insertions(+), 52 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index f7b7569887..e58ef1827c 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -10181,17 +10181,30 @@ build system (@command{zig build} command).
 Selecting this build system adds @code{zig} to the package inputs, in
 addition to the packages of @code{gnu-build-system}.
 
-There is no @code{configure} phase because Zig packages typically do not
-need to be configured.  The @code{#:zig-build-flags} parameter is a list of
-flags that are passed to the @code{zig} command during the build.  The
-@code{#:zig-test-flags} parameter is a list of flags that are passed to the
-@code{zig test} command during the @code{check} phase.  The default compiler
-package can be overridden with the @code{#:zig} argument.
-
-The optional @code{zig-release-type} parameter declares the type of release.
-Possible values are: @code{safe}, @code{fast}, or @code{small}. The default
-value is @code{#f}, which causes the release flag to be omitted from the
-@code{zig} command.  That results in a @code{debug} build.
+This build system by default installs package source to output.  This
+behavior can be disabled by setting @code{#:install-source?} parameter
+to @code{#f}.
+
+For packages that don't install anything and don't come with a test
+suite (likely library packages to be used by other Zig packages), you
+can set @code{#:skip-build?} parameter to @code{#t}, which skips
+@code{build} and @code{check} phases.
+
+The @code{configure} phase sets up environment for @command{zig build}.
+You need to add custom phases after it if you want to invoke
+@command{zig}.
+
+The @code{#:zig-build-flags} parameter is a list of flags that are
+passed to @command{zig build} in @code{build} phase.  The
+@code{#:zig-test-flags} parameter is a list of flags that are passed to
+@command{zig build test} in @code{check} phase.  The default compiler
+package can be overridden with the @code{#:zig} parameter.
+
+The optional @code{#:zig-release-type} parameter declares the type of
+release.  Possible values are: @code{safe}, @code{fast}, or
+@code{small}.  The default value is @code{#f}, which causes the release
+flag to be omitted from the @code{zig} command and results in a
+@code{debug} build.
 @end defvar
 
 @defvar scons-build-system
diff --git a/gnu/packages/ncdu.scm b/gnu/packages/ncdu.scm
index ab88f41dad..c49fefc077 100644
--- a/gnu/packages/ncdu.scm
+++ b/gnu/packages/ncdu.scm
@@ -72,7 +72,8 @@ ncurses installed.")
                 "01g5mpvsm78lkd0yin82gyancrl23npy69qcp3d60vmm72yiwirz"))))
     (build-system zig-build-system)
     (arguments
-     (list #:zig zig-0.12))
+     (list #:zig zig-0.12
+           #:install-source? #f))
     (inputs (list ncurses `(,zstd "lib")))
     (native-inputs (list pkg-config))
     (properties `((tunable? . #t)))))
diff --git a/gnu/packages/zig-xyz.scm b/gnu/packages/zig-xyz.scm
index 0cd08b6ac6..9c86dde556 100644
--- a/gnu/packages/zig-xyz.scm
+++ b/gnu/packages/zig-xyz.scm
@@ -53,6 +53,7 @@
     (build-system zig-build-system)
     (arguments
      (list
+      #:install-source? #f
       #:phases
       #~(modify-phases %standard-phases
           (add-after 'install 'install-wayland-session
@@ -98,6 +99,7 @@ directly from a tty using KMS/DRM.")
     (arguments
      (list
       #:zig zig-0.9
+      #:install-source? #f
       #:zig-release-type "safe"))
     (synopsis "Distributed financial accounting database")
     (description "TigerBeetle is a financial accounting database designed for
@@ -122,8 +124,9 @@ mission-critical safety and performance for financial 
services.")
     (build-system zig-build-system)
     (inputs (list zig-0.10 python))
     (arguments
-     ;; The tests fail with memory leaks.
-     (list #:tests? #f))
+     (list #:install-source? #f
+           ;; The tests fail with memory leaks.
+           #:tests? #f))
     (synopsis "Zig language server")
     (description
      "Zig Language Server is a language server implementing the @acronym{LSP,
diff --git a/gnu/packages/zig.scm b/gnu/packages/zig.scm
index 218e00552a..3008983bab 100644
--- a/gnu/packages/zig.scm
+++ b/gnu/packages/zig.scm
@@ -23,6 +23,7 @@
   #:use-module (guix gexp)
   #:use-module (guix packages)
   #:use-module (guix platform)
+  #:use-module (guix search-paths)
   #:use-module (guix utils)
   #:use-module (guix download)
   #:use-module (guix git-download)
@@ -32,7 +33,48 @@
   #:use-module (gnu packages compression)
   #:use-module (gnu packages llvm)
   #:use-module (gnu packages llvm-meta)
-  #:use-module (gnu packages web))
+  #:use-module (gnu packages web)
+  #:export (add-build.zig.zon
+            rename-zig-dependencies))
+
+(define* (add-build.zig.zon name version dependencies #:optional (paths '("")))
+  "Snippet to generate build.zig.zon of DEPENDENCIES for package NAME@VERSION."
+  `(let ((port (open-file "build.zig.zon" "w" #:encoding "utf8")))
+     (format port "\
+.{
+    .name = \"~a\",
+    .version = \"~a\",
+    .paths = .{
+~{\
+        \"~a\",
+~}\
+    },
+    .dependencies = .{
+~{\
+        .@\"~a\" = .{
+            .url = \"\",
+        },
+~}\
+    },
+}~%" ,name ,version (quote ,paths) (quote ,dependencies))
+     (close-port port)))
+
+(define (rename-zig-dependencies mapping)
+  "Snippet to rename Zig dependencies in build.zig and build.zig.zon."
+  `(begin
+     (use-modules (ice-9 match)
+                  (guix build utils))
+     (for-each
+      (match-lambda
+        ((old-name . new-name)
+         (begin
+           (substitute* "build.zig"
+             (((string-append "([Dd]ependency.\")" old-name) _ prefix)
+              (string-append prefix new-name)))
+           (substitute* "build.zig.zon"
+             (((format #f "\\.(@\")?~a\"?" old-name))
+              (format #f ".@\"~a\"" new-name))))))
+      (quote ,mapping))))
 
 (define (zig-source version commit hash)
   (origin
@@ -168,16 +210,12 @@
      (list llvm-13
            zig-0.9-glibc-abi-tool))
     (native-search-paths
-     (list
-      (search-path-specification
-       (variable "C_INCLUDE_PATH")
-       (files '("include")))
-      (search-path-specification
-       (variable "CPLUS_INCLUDE_PATH")
-       (files '("include/c++" "include")))
-      (search-path-specification
-       (variable "LIBRARY_PATH")
-       (files '("lib" "lib64")))))
+     (list $C_INCLUDE_PATH
+           $CPLUS_INCLUDE_PATH
+           $LIBRARY_PATH
+           (search-path-specification
+            (variable "GUIX_ZIG_PACKAGE_PATH")
+            (files '("src/zig")))))
     (synopsis "General purpose programming language and toolchain")
     (description "Zig is a general-purpose programming language and
 toolchain.  Among other features it provides
diff --git a/guix/build-system/zig.scm b/guix/build-system/zig.scm
index 82df75729c..0b96490387 100644
--- a/guix/build-system/zig.scm
+++ b/guix/build-system/zig.scm
@@ -48,6 +48,8 @@
                     source
                     (tests? #t)
                     (test-target #f)
+                    (install-source? #t)
+                    (skip-build? #f)
                     (zig-build-flags ''())
                     (zig-test-flags ''())
                     (zig-release-type #f)
@@ -68,13 +70,15 @@
                      #:source #+source
                      #:system #$system
                      #:test-target #$test-target
+                     #:install-source? #$install-source?
+                     #:skip-build? #$skip-build?
                      #:zig-build-flags #$zig-build-flags
                      ;; For reproducibility.
                      #:zig-build-target #$(platform-target
                                            (lookup-platform-by-system system))
                      #:zig-test-flags #$zig-test-flags
                      #:zig-release-type #$zig-release-type
-                     #:tests? #$tests?
+                     #:tests? #$(and tests? (not skip-build?))
                      #:phases #$phases
                      #:outputs #$(outputs->gexp outputs)
                      #:search-paths '#$(sexp->gexp
@@ -98,6 +102,8 @@
                           (native-search-paths '())
                           (tests? #t)
                           (test-target #f)
+                          (install-source? #t)
+                          (skip-build? #f)
                           (zig-build-flags ''())
                           (zig-test-flags ''())
                           (zig-destdir "out")
@@ -141,13 +147,15 @@
                      #:native-search-paths '#$(map
                                                 search-path-specification->sexp
                                                 native-search-paths)
+                     #:install-source? #$install-source?
+                     #:skip-build? #$skip-build?
                      #:zig-build-flags #$zig-build-flags
                      #:zig-build-target #$target
                      #:zig-test-flags #$zig-test-flags
                      #:zig-release-type #$zig-release-type
                      #:zig-destdir #$zig-destdir
                      #:zig-test-destdir #$zig-test-destdir
-                     #:tests? #$tests?
+                     #:tests? #$(and tests? (not skip-build?))
                      #:search-paths '#$(sexp->gexp
                                         (map search-path-specification->sexp
                                              search-paths))))))
@@ -164,13 +172,13 @@
 
 (define* (lower name
                 #:key source inputs native-inputs outputs system target
-                (zig (default-zig))
+                (zig (default-zig)) (zig-inputs '())
                 #:allow-other-keys
                 #:rest arguments)
   "Return a bag for NAME."
 
   (define private-keywords
-    '(#:target #:zig #:inputs #:native-inputs #:outputs))
+    '(#:target #:zig #:zig-inputs #:inputs #:native-inputs #:outputs))
 
   (bag
     (name name)
@@ -181,6 +189,7 @@
                         '())
                     ,@`(("zig" ,zig))
                     ,@native-inputs
+                    ,@(if target '() zig-inputs)
                     ,@(if target '() inputs)
                     ,@(if target
                         ;; Use the standard cross inputs of
@@ -189,7 +198,8 @@
                         '())
                     ;; Keep the standard inputs of 'gnu-build-system'.
                     ,@(standard-packages)))
-    (host-inputs (if target inputs '()))
+    (host-inputs `(,@(if target zig-inputs '())
+                   ,@(if target inputs '())))
     (target-inputs (if target
                      (standard-cross-packages target 'target)
                      '()))
diff --git a/guix/build/zig-build-system.scm b/guix/build/zig-build-system.scm
index d721baf57c..5ead11b28a 100644
--- a/guix/build/zig-build-system.scm
+++ b/guix/build/zig-build-system.scm
@@ -23,38 +23,82 @@
   #:use-module (ice-9 popen)
   #:use-module (ice-9 rdelim)
   #:use-module (ice-9 ftw)
-  #:use-module (ice-9 format)
   #:use-module (ice-9 match)
-  #:use-module (rnrs io ports)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-26)
   #:export (%standard-phases
-            zig-build))
+            zig-build
+            zig-source-install-path))
 
 ;; Interesting guide here:
 ;; https://github.com/riverwm/river/blob/master/PACKAGING.md
 
+(define (zig-source-install-path output)
+  (string-append output "/src/zig/" (strip-store-file-name output)))
+
+(define (zig-input-install-path input)
+  (zig-source-install-path
+   (dirname (dirname (dirname (canonicalize-path input))))))
+
+;; Use ‘zig fetch --name=NAME’ to overwrite dependency NAME and update hash in
+;; build.zig.zon.
+(define (unpack-dependencies . args)
+  "Unpack Zig dependencies from GUIX_ZIG_PACKAGE_PATH.  Note that this phase
+asserts dependency names start with \"zig-\"."
+  (define zig-inputs
+    (append-map
+     (lambda (directory)
+       (map (lambda (input-name)
+              (cons input-name
+                    (string-append directory "/" input-name)))
+            (scandir directory (negate (cut member <> '("." ".."))))))
+     (or (and=> (getenv "GUIX_ZIG_PACKAGE_PATH")
+                (cut string-split <> #\:))
+         '())))
+  ;; zig-aaa-0.1.2-3.456789a -> zig-aaa
+  ;; zig-bbb-2.3.3 -> zig-bbb
+  (define (strip-version input)
+    (let* ((name+version (string-split input #\-))
+           (guix-revision?
+            (not (= (length (string-split (last name+version) #\.))
+                    3))))
+      (string-join
+       (drop-right name+version (if guix-revision? 2 1))
+       "-")))
+  (for-each
+   (match-lambda
+     ((input-name . input-path)
+      (let ((call `("zig" "fetch"
+                    ;; TODO: When supported, use a valid URL instead.
+                    ;; See also <https://github.com/ziglang/zig/pull/21931>.
+                    ,(zig-input-install-path input-path)
+                    ,(string-append "--save=" (strip-version input-name)))))
+        (format #t "running: ~s~%" call)
+        (apply invoke call))))
+   (reverse zig-inputs)))
+
 (define* (build #:key
                 zig-build-flags
                 zig-build-target
-                zig-release-type       ;; "safe", "fast" or "small" empty for a
-                                       ;; debug build"
+                ;; "safe", "fast" or "small", empty for a "debug" build.
+                zig-release-type
+                skip-build?
                 #:allow-other-keys)
   "Build a given Zig package."
-
-  (setenv "DESTDIR" "out")
-  (let ((call `("zig" "build"
-                     "--prefix"             ""            ;; Don't add /usr
-                     "--prefix-lib-dir"     "lib"
-                     "--prefix-exe-dir"     "bin"
-                     "--prefix-include-dir" "include"
-                     ,(string-append "-Dtarget=" (zig-target zig-build-target))
-                     ,@(if zig-release-type
-                         (list (string-append "-Drelease-" zig-release-type))
-                         '())
-                     ,@zig-build-flags)))
-  (format #t "running: ~s~%" call)
-  (apply invoke call)))
+  (when (not skip-build?)
+    (setenv "DESTDIR" "out")
+    (let ((call `("zig" "build"
+                  "--prefix"             ""            ;; Don't add /usr
+                  "--prefix-lib-dir"     "lib"
+                  "--prefix-exe-dir"     "bin"
+                  "--prefix-include-dir" "include"
+                  ,(string-append "-Dtarget=" (zig-target zig-build-target))
+                  ,@(if zig-release-type
+                        (list (string-append "-Drelease-" zig-release-type))
+                        '())
+                  ,@zig-build-flags)))
+      (format #t "running: ~s~%" call)
+      (apply invoke call))))
 
 (define* (check #:key tests?
                 zig-test-flags
@@ -72,15 +116,22 @@
         (setenv "DESTDIR" old-destdir)
         (unsetenv "DESTDIR")))))
 
-(define* (install #:key inputs outputs #:allow-other-keys)
+(define* (install #:key outputs install-source? #:allow-other-keys)
   "Install a given Zig package."
-  (let ((out (assoc-ref outputs "out")))
-    (copy-recursively "out" out)))
+  (let* ((out (assoc-ref outputs "out"))
+         (source-install-path (zig-source-install-path out)))
+    (when (file-exists? "out")
+      (copy-recursively "out" out)
+      (delete-file-recursively "out"))
+    (when install-source?
+      (mkdir-p source-install-path)
+      (copy-recursively "." source-install-path))))
 
 (define %standard-phases
   (modify-phases gnu:%standard-phases
     (delete 'bootstrap)
     (replace 'configure zig-configure)
+    (add-after 'configure 'unpack-dependencies unpack-dependencies)
     (replace 'build build)
     (replace 'check check)
     (replace 'install install)))

Reply via email to