Subject: [PATCH v4 rust-team 10/22] build-system: cargo: Support installing Cargo workspace.

From: Hilton Chain <[email-masked]>
Date: Tue, 29 Apr 2025 00:23:07 +0800

*guix/build-system/cargo.scm (cargo-build, cargo-cross-build)
[#:cargo-install-paths]: New argument.
* guix/build/cargo-build-system.scm (install): Use it.
* doc/guix.texi (Build Systems)[cargo-build-system]: Document it.

Change-Id: I74ed1972a5716da05afeac8edb2b0e4b6834bf40
---
 doc/guix.texi                     |  5 ++++-
 guix/build-system/cargo.scm       |  4 ++++
 guix/build/cargo-build-system.scm | 17 +++++++++++++----
 3 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 771547fafb..6388f7b28f 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -9499,7 +9499,10 @@ Build Systems
 library crates to package in the @code{package} phase.  Specified crates are
 packaged from left to right, in case there's dependency among them.  For
 example, specifying @code{''("pcre2-sys" "pcre2")} will package
-@code{"pcre2-sys"} first and then @code{"pcre2"}.
+@code{"pcre2-sys"} first and then @code{"pcre2"}.  Parameter
+@code{#:cargo-install-paths} (default: @code{''()}) allows specifying paths of
+binary crates to install in the @code{install} phase, @code{''("crates/atuin")},
+for example.
 @end defvar
 
 @defvar chicken-build-system
diff --git a/guix/build-system/cargo.scm b/guix/build-system/cargo.scm
index 2c47c1feaf..7a07003262 100644
--- a/guix/build-system/cargo.scm
+++ b/guix/build-system/cargo.scm
@@ -100,6 +100,7 @@ (define* (cargo-build name inputs
                       (cargo-test-flags ''())
                       (cargo-package-crates ''())
                       (cargo-package-flags ''("--no-metadata" "--no-verify"))
+                      (cargo-install-paths ''())
                       (features ''())
                       (skip-build? #f)
                       (parallel-build? #t)
@@ -129,6 +130,7 @@ (define* (cargo-build name inputs
                        #:cargo-test-flags #$(sexp->gexp cargo-test-flags)
                        #:cargo-package-crates #$(sexp->gexp cargo-package-crates)
                        #:cargo-package-flags #$(sexp->gexp cargo-package-flags)
+                       #:cargo-install-paths #$(sexp->gexp cargo-install-paths)
                        #:cargo-target #$(cargo-triplet system)
                        #:features #$(sexp->gexp features)
                        #:skip-build? #$skip-build?
@@ -162,6 +164,7 @@ (define* (cargo-cross-build name
                             (cargo-test-flags ''())
                             (cargo-package-crates ''())
                             (cargo-package-flags ''("--no-metadata" "--no-verify"))
+                            (cargo-install-paths ''())
                             (cargo-target (cargo-triplet (or target system)))
                             (features ''())
                             (skip-build? #f)
@@ -194,6 +197,7 @@ (define* (cargo-cross-build name
                        #:cargo-test-flags #$(sexp->gexp cargo-test-flags)
                        #:cargo-package-crates #$(sexp->gexp cargo-package-crates)
                        #:cargo-package-flags #$(sexp->gexp cargo-package-flags)
+                       #:cargo-install-paths #$(sexp->gexp cargo-install-paths)
                        #:cargo-target #$(cargo-triplet (or target system))
                        #:features #$(sexp->gexp features)
                        #:skip-build? #$skip-build?
diff --git a/guix/build/cargo-build-system.scm b/guix/build/cargo-build-system.scm
index 85745d4d91..be96ab309f 100644
--- a/guix/build/cargo-build-system.scm
+++ b/guix/build/cargo-build-system.scm
@@ -379,6 +379,7 @@ (define* (install #:key
                   skip-build?
                   install-source?
                   features
+                  (cargo-install-paths '())
                   #:allow-other-keys)
   "Install a given Cargo package."
   (let* ((out      (assoc-ref outputs "out"))
@@ -393,10 +394,18 @@ (define* (install #:key
     ;; Only install crates which include binary targets,
     ;; otherwise cargo will raise an error.
     (or skip-build?
-        (not (has-executable-target?))
-        (invoke "cargo" "install" "--offline" "--no-track"
-                "--path" "." "--root" out
-                "--features" (string-join features)))
+        ;; NOTE: Cargo workspace installation support:
+        ;; #:skip-build? #f + #:cargo-install-paths.
+        (and (null? cargo-install-paths)
+             (not (has-executable-target?)))
+        (for-each
+         (lambda (path)
+           (invoke "cargo" "install" "--offline" "--no-track"
+                   "--path" path "--root" out
+                   "--features" (string-join features)))
+         (if (null? cargo-install-paths)
+             '(".")
+             cargo-install-paths)))
 
     (when install-source?
       ;; Install crate tarballs and unpacked sources for later use.
-- 
2.49.0