Subject: [bug#72553] [PATCH 3/4] gnu: rust: Use gexps; fix enable-profiling phase.

From: Christopher Baines <[email-masked]>
Date: Sat, 10 Aug 2024 08:11:46 +0100

From: Maxim Cournoyer <[email-masked]>

This is a follow up commit to 8219ab0443129c71eef83ee4bd3aae0a0a12b6f9, which
had a few problems.

* gnu/packages/rust.scm (rust) [arguments]: Use gexps.  Replace
unpack-profiler-rt phase with copy-compiler-rt-source.  Rename
the enable-profiling phase to enable-profiler; streamline substitute
regexp/replacement.

Change-Id: I058de60f25c6a96cf4bbcd3a7dd4a682341e2ac5
---
 gnu/packages/rust.scm | 493 +++++++++++++++++++++---------------------
 1 file changed, 246 insertions(+), 247 deletions(-)

diff --git a/gnu/packages/rust.scm b/gnu/packages/rust.scm
index fe503b0d5f..13e57cd3f5 100644
--- a/gnu/packages/rust.scm
+++ b/gnu/packages/rust.scm
@@ -11,7 +11,7 @@
 ;;; Copyright © 2020, 2021 Jakub Kądziołka <[email-masked]>
 ;;; Copyright © 2020 Pierre Langlois <[email-masked]>
 ;;; Copyright © 2020 Matthew James Kraai <[email-masked]>
-;;; Copyright © 2021 Maxim Cournoyer <[email-masked]>
+;;; Copyright © 2021, 2024 Maxim Cournoyer <[email-masked]>
 ;;; Copyright © 2021 (unmatched parenthesis <[email-masked]>
 ;;; Copyright © 2022 Zheng Junjie <[email-masked]>
 ;;; Copyright © 2022 Jim Newsome <[email-masked]>
@@ -1072,257 +1072,256 @@ (define-public rust
          (strip-keyword-arguments '(#:tests?)
            (package-arguments base-rust))
          ((#:phases phases)
-          `(modify-phases ,phases
-             (add-after 'unpack 'relax-gdb-auto-load-safe-path
-               ;; Allow GDB to load binaries from any location, otherwise the
-               ;; gdbinfo tests fail.  This is only useful when testing with a
-               ;; GDB version newer than 8.2.
-               (lambda _
-                 (setenv "HOME" (getcwd))
-                 (with-output-to-file (string-append (getenv "HOME") "/.gdbinit")
-                   (lambda _
-                     (format #t "set auto-load safe-path /~%")))
-                 ;; Do not launch gdb with '-nx' which causes it to not execute
-                 ;; any init file.
-                 (substitute* "src/tools/compiletest/src/runtest.rs"
-                   (("\"-nx\".as_ref\\(\\), ")
-                    ""))))
-             (add-after 'unpack 'disable-tests-requiring-git
-               (lambda _
-                 (substitute* "src/tools/cargo/tests/testsuite/git.rs"
-                   ,@(make-ignore-test-list
-                      '("fn fetch_downloads_with_git2_first_")))))
-             (add-after 'unpack 'disable-tests-requiring-mercurial
-               (lambda _
-                 (with-directory-excursion "src/tools/cargo/tests/testsuite/cargo_init"
-                   (substitute* '("mercurial_autodetect/mod.rs"
-                                  "simple_hg_ignore_exists/mod.rs")
-                     ,@(make-ignore-test-list
-                        '("fn case"))))))
-             (add-after 'unpack 'disable-tests-using-cargo-publish
-               (lambda _
-                 (with-directory-excursion "src/tools/cargo/tests/testsuite"
-                   (substitute* "alt_registry.rs"
-                     ,@(make-ignore-test-list
-                        '("fn warn_for_unused_fields")))
-                   (substitute* '("cargo_add/locked_unchanged/mod.rs"
-                                  "cargo_add/lockfile_updated/mod.rs"
-                                  "cargo_remove/update_lock_file/mod.rs")
-                     ,@(make-ignore-test-list
-                        '("fn case")))
-                   (substitute* "git_shallow.rs"
-                     ,@(make-ignore-test-list
-                        '("fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_followup_fetches"
-                          "fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again"
-                          "fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_shallowness"
-                          "fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch"
-                          "fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_shallowness"
-                          "fn gitoxide_shallow_clone_followed_by_non_shallow_update"
-                          "fn gitoxide_clones_shallow_two_revs_same_deps"
-                          "fn gitoxide_git_dependencies_switch_from_branch_to_rev"
-                          "fn shallow_deps_work_with_revisions_and_branches_mixed_on_same_dependency")))
-                   (substitute* "install.rs"
-                     ,@(make-ignore-test-list
-                        '("fn failed_install_retains_temp_directory")))
-                   (substitute* "offline.rs"
-                     ,@(make-ignore-test-list
-                        '("fn gitoxide_cargo_compile_offline_with_cached_git_dep_shallow_dep")))
-                   (substitute* "patch.rs"
-                     ,@(make-ignore-test-list
-                        '("fn gitoxide_clones_shallow_old_git_patch"))))))
-             ,@(if (target-riscv64?)
-                   ;; Keep this phase separate so it can be adjusted without needing
-                   ;; to adjust the skipped tests on other architectures.
-                   `((add-after 'unpack 'disable-tests-broken-on-riscv64
-                       (lambda _
-                         (with-directory-excursion "src/tools/cargo/tests/testsuite"
-                           (substitute* "build.rs"
-                             ,@(make-ignore-test-list
-                                 '("fn uplift_dwp_of_bin_on_linux")))
-                           (substitute* "cache_lock.rs"
-                             ,@(make-ignore-test-list
-                                 '("fn multiple_download")))))))
-                   `())
-             (add-after 'unpack 'disable-tests-broken-on-aarch64
-               (lambda _
-                 (with-directory-excursion "src/tools/cargo/tests/testsuite/"
-                   (substitute* "build_script_extra_link_arg.rs"
-                     ,@(make-ignore-test-list
-                        '("fn build_script_extra_link_arg_bin_single")))
-                   (substitute* "build_script.rs"
-                     ,@(make-ignore-test-list
-                        '("fn env_test")))
-                   (substitute* "collisions.rs"
-                     ,@(make-ignore-test-list
-                        '("fn collision_doc_profile_split")))
-                   (substitute* "concurrent.rs"
-                     ,@(make-ignore-test-list
-                        '("fn no_deadlock_with_git_dependencies")))
-                   (substitute* "features2.rs"
-                     ,@(make-ignore-test-list
-                        '("fn dep_with_optional_host_deps_activated"))))))
-             (add-after 'unpack 'patch-command-exec-tests
-               ;; This test suite includes some tests that the stdlib's
-               ;; `Command` execution properly handles in situations where
-               ;; the environment or PATH variable are empty, but this fails
-               ;; since we don't have `echo` available at its usual FHS
-               ;; location.
-               (lambda _
-                 (substitute* "tests/ui/command/command-exec.rs"
-                   (("Command::new\\(\"echo\"\\)")
-                    (format #f "Command::new(~s)" (which "echo"))))))
-             (add-after 'unpack 'patch-command-uid-gid-test
-               (lambda _
-                 (substitute* "tests/ui/command/command-uid-gid.rs"
-                   (("/bin/sh") (which "sh"))
-                   (("/bin/ls") (which "ls")))))
-             (add-after 'unpack 'skip-shebang-tests
-               ;; This test make sure that the parser behaves properly when a
-               ;; source file starts with a shebang. Unfortunately, the
-               ;; patch-shebangs phase changes the meaning of these edge-cases.
-               ;; We skip the test since it's drastically unlikely Guix's
-               ;; packaging will introduce a bug here.
-               (lambda _
-                 (delete-file "tests/ui/parser/shebang/sneaky-attrib.rs")))
-             (add-after 'unpack 'patch-process-tests
-               (lambda* (#:key inputs #:allow-other-keys)
-                 (let ((bash (assoc-ref inputs "bash")))
-                   (with-directory-excursion "library/std/src"
-                     (substitute* "process/tests.rs"
-                       (("\"/bin/sh\"")
-                        (string-append "\"" bash "/bin/sh\"")))
-                     ;; The three tests which are known to fail upstream on QEMU
-                     ;; emulation on aarch64 and riscv64 also fail on x86_64 in
-                     ;; Guix's build system.  Skip them on all builds.
-                     (substitute* "sys/unix/process/process_common/tests.rs"
-                       ;; We can't use make-ignore-test-list because we will get
-                       ;; build errors due to the double [ignore] block.
-                       (("target_arch = \"arm\"" arm)
-                        (string-append "target_os = \"linux\",\n"
-                                       "        " arm)))))))
-             (add-after 'unpack 'disable-interrupt-tests
-               (lambda _
-                 ;; This test hangs in the build container; disable it.
-                 (substitute* "src/tools/cargo/tests/testsuite/freshness.rs"
-                   ,@(make-ignore-test-list
-                      '("fn linking_interrupted")))
-                 ;; Likewise for the ctrl_c_kills_everyone test.
-                 (substitute* "src/tools/cargo/tests/testsuite/death.rs"
-                   ,@(make-ignore-test-list
-                      '("fn ctrl_c_kills_everyone")))))
-             (add-after 'unpack 'adjust-rpath-values
-               ;; This adds %output:out to rpath, allowing us to install utilities in
-               ;; different outputs while reusing the shared libraries.
-               (lambda* (#:key outputs #:allow-other-keys)
-                 (let ((out (assoc-ref outputs "out")))
-                   (substitute* "src/bootstrap/src/core/builder.rs"
-                     ((" = rpath.*" all)
-                      (string-append all
-                                     "                "
-                                     "rustflags.arg(\"-Clink-args=-Wl,-rpath="
-                                     out "/lib\");\n"))))))
-             (add-after 'unpack 'unpack-profiler-rt
-               ;; Copy compiler-rt sources to where libprofiler_builtins looks
-               ;; for its vendored copy.
-               (lambda* (#:key inputs #:allow-other-keys)
-                 (mkdir-p "src/llvm-project/compiler-rt")
-                 (copy-recursively
-                   (string-append (assoc-ref inputs "clang-source")
-                                  "/compiler-rt")
-                   "src/llvm-project/compiler-rt")))
-             (add-after 'configure 'enable-profiling
-               (lambda _
-                 (substitute* "config.toml"
-                   (("^profiler =.*$") "")
-                   (("\\[build\\]") "\n[build]\nprofiler = true\n"))))
-             (add-after 'configure 'add-gdb-to-config
-               (lambda* (#:key inputs #:allow-other-keys)
-                 (let ((gdb (assoc-ref inputs "gdb")))
-                   (substitute* "config.toml"
-                     (("^python =.*" all)
-                      (string-append all
-                                     "gdb = \"" gdb "/bin/gdb\"\n"))))))
-             (replace 'build
-               ;; Phase overridden to also build more tools.
-               (lambda* (#:key parallel-build? #:allow-other-keys)
-                 (let ((job-spec (string-append
-                                  "-j" (if parallel-build?
-                                           (number->string (parallel-job-count))
-                                           "1"))))
-                   (invoke "./x.py" job-spec "build"
-                           "library/std" ;rustc
-                           "src/tools/cargo"
-                           "src/tools/clippy"
-                           "src/tools/rust-analyzer"
-                           "src/tools/rustfmt"))))
-             (replace 'check
-               ;; Phase overridden to also test more tools.
-               (lambda* (#:key tests? parallel-build? #:allow-other-keys)
-                 (when tests?
-                   (let ((job-spec (string-append
-                                    "-j" (if parallel-build?
-                                             (number->string (parallel-job-count))
-                                             "1"))))
-                     (invoke "./x.py" job-spec "test" "-vv"
-                             "library/std"
-                             "src/tools/cargo"
-                             "src/tools/clippy"
-                             "src/tools/rust-analyzer"
-                             "src/tools/rustfmt")))))
-             (replace 'install
-               ;; Phase overridden to also install more tools.
-               (lambda* (#:key outputs #:allow-other-keys)
-                 (invoke "./x.py" "install")
-                 (substitute* "config.toml"
-                   ;; Adjust the prefix to the 'cargo' output.
-                   (("prefix = \"[^\"]*\"")
-                    (format #f "prefix = ~s" (assoc-ref outputs "cargo"))))
-                 (invoke "./x.py" "install" "cargo")
-                 (substitute* "config.toml"
-                   ;; Adjust the prefix to the 'tools' output.
-                   (("prefix = \"[^\"]*\"")
-                    (format #f "prefix = ~s" (assoc-ref outputs "tools"))))
-                 (invoke "./x.py" "install" "clippy")
-                 (invoke "./x.py" "install" "rust-analyzer")
-                 (invoke "./x.py" "install" "rustfmt")))
-             (add-after 'install 'install-rust-src
-               (lambda* (#:key outputs #:allow-other-keys)
-                 (let ((out (assoc-ref outputs "rust-src"))
-                       (dest "/lib/rustlib/src/rust"))
-                   (mkdir-p (string-append out dest))
-                   (copy-recursively "library" (string-append out dest "/library"))
-                   (copy-recursively "src" (string-append out dest "/src")))))
-             (add-after 'install 'remove-uninstall-script
-               (lambda* (#:key outputs #:allow-other-keys)
-                 ;; This script has no use on Guix
-                 ;; and it retains a reference to the host's bash.
-                 (delete-file (string-append (assoc-ref outputs "out")
-                                             "/lib/rustlib/uninstall.sh"))))
-             (add-after 'install-rust-src 'wrap-rust-analyzer
-               (lambda* (#:key outputs #:allow-other-keys)
-                 (let ((bin (string-append (assoc-ref outputs "tools") "/bin")))
-                   (rename-file (string-append bin "/rust-analyzer")
-                                (string-append bin "/.rust-analyzer-real"))
-                   (call-with-output-file (string-append bin "/rust-analyzer")
-                     (lambda (port)
-                       (format port "#!~a
+          #~(modify-phases #$phases
+              (add-after 'unpack 'relax-gdb-auto-load-safe-path
+                ;; Allow GDB to load binaries from any location, otherwise the
+                ;; gdbinfo tests fail.  This is only useful when testing with a
+                ;; GDB version newer than 8.2.
+                (lambda _
+                  (setenv "HOME" (getcwd))
+                  (with-output-to-file (string-append (getenv "HOME") "/.gdbinit")
+                    (lambda _
+                      (format #t "set auto-load safe-path /~%")))
+                  ;; Do not launch gdb with '-nx' which causes it to not execute
+                  ;; any init file.
+                  (substitute* "src/tools/compiletest/src/runtest.rs"
+                    (("\"-nx\".as_ref\\(\\), ")
+                     ""))))
+              (add-after 'unpack 'disable-tests-requiring-git
+                (lambda _
+                  (substitute* "src/tools/cargo/tests/testsuite/git.rs"
+                    #$@(make-ignore-test-list
+                        '("fn fetch_downloads_with_git2_first_")))))
+              (add-after 'unpack 'disable-tests-requiring-mercurial
+                (lambda _
+                  (with-directory-excursion "src/tools/cargo/tests/testsuite/cargo_init"
+                    (substitute* '("mercurial_autodetect/mod.rs"
+                                   "simple_hg_ignore_exists/mod.rs")
+                      #$@(make-ignore-test-list
+                          '("fn case"))))))
+              (add-after 'unpack 'disable-tests-using-cargo-publish
+                (lambda _
+                  (with-directory-excursion "src/tools/cargo/tests/testsuite"
+                    (substitute* "alt_registry.rs"
+                      #$@(make-ignore-test-list
+                          '("fn warn_for_unused_fields")))
+                    (substitute* '("cargo_add/locked_unchanged/mod.rs"
+                                   "cargo_add/lockfile_updated/mod.rs"
+                                   "cargo_remove/update_lock_file/mod.rs")
+                      #$@(make-ignore-test-list
+                          '("fn case")))
+                    (substitute* "git_shallow.rs"
+                      #$@(make-ignore-test-list
+                          '("fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_followup_fetches"
+                            "fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again"
+                            "fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_shallowness"
+                            "fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch"
+                            "fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_shallowness"
+                            "fn gitoxide_shallow_clone_followed_by_non_shallow_update"
+                            "fn gitoxide_clones_shallow_two_revs_same_deps"
+                            "fn gitoxide_git_dependencies_switch_from_branch_to_rev"
+                            "fn shallow_deps_work_with_revisions_and_branches_mixed_on_same_dependency")))
+                    (substitute* "install.rs"
+                      #$@(make-ignore-test-list
+                          '("fn failed_install_retains_temp_directory")))
+                    (substitute* "offline.rs"
+                      #$@(make-ignore-test-list
+                          '("fn gitoxide_cargo_compile_offline_with_cached_git_dep_shallow_dep")))
+                    (substitute* "patch.rs"
+                      #$@(make-ignore-test-list
+                          '("fn gitoxide_clones_shallow_old_git_patch"))))))
+              #$@(if (target-riscv64?)
+                     ;; Keep this phase separate so it can be adjusted without needing
+                     ;; to adjust the skipped tests on other architectures.
+                     #~((add-after 'unpack 'disable-tests-broken-on-riscv64
+                          (lambda _
+                            (with-directory-excursion "src/tools/cargo/tests/testsuite"
+                              (substitute* "build.rs"
+                                #$@(make-ignore-test-list
+                                    '("fn uplift_dwp_of_bin_on_linux")))
+                              (substitute* "cache_lock.rs"
+                                #$@(make-ignore-test-list
+                                    '("fn multiple_download")))))))
+                     #~())
+              (add-after 'unpack 'disable-tests-broken-on-aarch64
+                (lambda _
+                  (with-directory-excursion "src/tools/cargo/tests/testsuite/"
+                    (substitute* "build_script_extra_link_arg.rs"
+                      #$@(make-ignore-test-list
+                          '("fn build_script_extra_link_arg_bin_single")))
+                    (substitute* "build_script.rs"
+                      #$@(make-ignore-test-list
+                          '("fn env_test")))
+                    (substitute* "collisions.rs"
+                      #$@(make-ignore-test-list
+                          '("fn collision_doc_profile_split")))
+                    (substitute* "concurrent.rs"
+                      #$@(make-ignore-test-list
+                          '("fn no_deadlock_with_git_dependencies")))
+                    (substitute* "features2.rs"
+                      #$@(make-ignore-test-list
+                          '("fn dep_with_optional_host_deps_activated"))))))
+              (add-after 'unpack 'patch-command-exec-tests
+                ;; This test suite includes some tests that the stdlib's
+                ;; `Command` execution properly handles in situations where
+                ;; the environment or PATH variable are empty, but this fails
+                ;; since we don't have `echo` available at its usual FHS
+                ;; location.
+                (lambda _
+                  (substitute* "tests/ui/command/command-exec.rs"
+                    (("Command::new\\(\"echo\"\\)")
+                     (format #f "Command::new(~s)" (which "echo"))))))
+              (add-after 'unpack 'patch-command-uid-gid-test
+                (lambda _
+                  (substitute* "tests/ui/command/command-uid-gid.rs"
+                    (("/bin/sh") (which "sh"))
+                    (("/bin/ls") (which "ls")))))
+              (add-after 'unpack 'skip-shebang-tests
+                ;; This test make sure that the parser behaves properly when a
+                ;; source file starts with a shebang. Unfortunately, the
+                ;; patch-shebangs phase changes the meaning of these edge-cases.
+                ;; We skip the test since it's drastically unlikely Guix's
+                ;; packaging will introduce a bug here.
+                (lambda _
+                  (delete-file "tests/ui/parser/shebang/sneaky-attrib.rs")))
+              (add-after 'unpack 'patch-process-tests
+                (lambda* (#:key inputs #:allow-other-keys)
+                  (let ((bash (assoc-ref inputs "bash")))
+                    (with-directory-excursion "library/std/src"
+                      (substitute* "process/tests.rs"
+                        (("\"/bin/sh\"")
+                         (string-append "\"" bash "/bin/sh\"")))
+                      ;; The three tests which are known to fail upstream on QEMU
+                      ;; emulation on aarch64 and riscv64 also fail on x86_64 in
+                      ;; Guix's build system.  Skip them on all builds.
+                      (substitute* "sys/unix/process/process_common/tests.rs"
+                        ;; We can't use make-ignore-test-list because we will get
+                        ;; build errors due to the double [ignore] block.
+                        (("target_arch = \"arm\"" arm)
+                         (string-append "target_os = \"linux\",\n"
+                                        "        " arm)))))))
+              (add-after 'unpack 'disable-interrupt-tests
+                (lambda _
+                  ;; This test hangs in the build container; disable it.
+                  (substitute* "src/tools/cargo/tests/testsuite/freshness.rs"
+                    #$@(make-ignore-test-list
+                        '("fn linking_interrupted")))
+                  ;; Likewise for the ctrl_c_kills_everyone test.
+                  (substitute* "src/tools/cargo/tests/testsuite/death.rs"
+                    #$@(make-ignore-test-list
+                        '("fn ctrl_c_kills_everyone")))))
+              (add-after 'unpack 'adjust-rpath-values
+                ;; This adds %output:out to rpath, allowing us to install utilities in
+                ;; different outputs while reusing the shared libraries.
+                (lambda* (#:key outputs #:allow-other-keys)
+                  (let ((out (assoc-ref outputs "out")))
+                    (substitute* "src/bootstrap/src/core/builder.rs"
+                      ((" = rpath.*" all)
+                       (string-append all
+                                      "                "
+                                      "rustflags.arg(\"-Clink-args=-Wl,-rpath="
+                                      out "/lib\");\n"))))))
+              (add-after 'unpack 'copy-compiler-rt-source
+                ;; Note: Keep the clang-runtime version in sync with the LLVM
+                ;; version used to build Rust.
+                (lambda _
+                  (let ((compiler-rt "src/llvm-project/compiler-rt"))
+                    (mkdir-p compiler-rt)
+                    (copy-recursively
+                     (string-append #$(package-source clang-runtime-15)
+                                    "/compiler-rt")
+                     compiler-rt))))
+              (add-after 'configure 'enable-profiler
+                (lambda _
+                  (substitute* "config.toml"
+                    (("^profiler =.*") "")
+                    (("\\[build]")
+                     "[build]\nprofiler = true\n"))))
+              (add-after 'configure 'add-gdb-to-config
+                (lambda* (#:key inputs #:allow-other-keys)
+                  (let ((gdb (assoc-ref inputs "gdb")))
+                    (substitute* "config.toml"
+                      (("^python =.*" all)
+                       (string-append all
+                                      "gdb = \"" gdb "/bin/gdb\"\n"))))))
+              (replace 'build
+                ;; Phase overridden to also build more tools.
+                (lambda* (#:key parallel-build? #:allow-other-keys)
+                  (let ((job-spec (string-append
+                                   "-j" (if parallel-build?
+                                            (number->string (parallel-job-count))
+                                            "1"))))
+                    (invoke "./x.py" job-spec "build"
+                            "library/std" ;rustc
+                            "src/tools/cargo"
+                            "src/tools/clippy"
+                            "src/tools/rust-analyzer"
+                            "src/tools/rustfmt"))))
+              (replace 'check
+                ;; Phase overridden to also test more tools.
+                (lambda* (#:key tests? parallel-build? #:allow-other-keys)
+                  (when tests?
+                    (let ((job-spec (string-append
+                                     "-j" (if parallel-build?
+                                              (number->string (parallel-job-count))
+                                              "1"))))
+                      (invoke "./x.py" job-spec "test" "-vv"
+                              "library/std"
+                              "src/tools/cargo"
+                              "src/tools/clippy"
+                              "src/tools/rust-analyzer"
+                              "src/tools/rustfmt")))))
+              (replace 'install
+                ;; Phase overridden to also install more tools.
+                (lambda* (#:key outputs #:allow-other-keys)
+                  (invoke "./x.py" "install")
+                  (substitute* "config.toml"
+                    ;; Adjust the prefix to the 'cargo' output.
+                    (("prefix = \"[^\"]*\"")
+                     (format #f "prefix = ~s" (assoc-ref outputs "cargo"))))
+                  (invoke "./x.py" "install" "cargo")
+                  (substitute* "config.toml"
+                    ;; Adjust the prefix to the 'tools' output.
+                    (("prefix = \"[^\"]*\"")
+                     (format #f "prefix = ~s" (assoc-ref outputs "tools"))))
+                  (invoke "./x.py" "install" "clippy")
+                  (invoke "./x.py" "install" "rust-analyzer")
+                  (invoke "./x.py" "install" "rustfmt")))
+              (add-after 'install 'install-rust-src
+                (lambda* (#:key outputs #:allow-other-keys)
+                  (let ((out (assoc-ref outputs "rust-src"))
+                        (dest "/lib/rustlib/src/rust"))
+                    (mkdir-p (string-append out dest))
+                    (copy-recursively "library" (string-append out dest "/library"))
+                    (copy-recursively "src" (string-append out dest "/src")))))
+              (add-after 'install 'remove-uninstall-script
+                (lambda* (#:key outputs #:allow-other-keys)
+                  ;; This script has no use on Guix
+                  ;; and it retains a reference to the host's bash.
+                  (delete-file (string-append (assoc-ref outputs "out")
+                                              "/lib/rustlib/uninstall.sh"))))
+              (add-after 'install-rust-src 'wrap-rust-analyzer
+                (lambda* (#:key outputs #:allow-other-keys)
+                  (let ((bin (string-append (assoc-ref outputs "tools") "/bin")))
+                    (rename-file (string-append bin "/rust-analyzer")
+                                 (string-append bin "/.rust-analyzer-real"))
+                    (call-with-output-file (string-append bin "/rust-analyzer")
+                      (lambda (port)
+                        (format port "#!~a
 if test -z \"${RUST_SRC_PATH}\";then export RUST_SRC_PATH=~S;fi;
 exec -a \"$0\" \"~a\" \"$@\""
-                               (which "bash")
-                               (string-append (assoc-ref outputs "rust-src")
-                                              "/lib/rustlib/src/rust/library")
-                               (string-append bin "/.rust-analyzer-real"))))
-                   (chmod (string-append bin "/rust-analyzer") #o755))))))))
+                                (which "bash")
+                                (string-append (assoc-ref outputs "rust-src")
+                                               "/lib/rustlib/src/rust/library")
+                                (string-append bin "/.rust-analyzer-real"))))
+                    (chmod (string-append bin "/rust-analyzer") #o755))))))))
       (inputs
        (modify-inputs (package-inputs base-rust)
                       (prepend curl libffi `(,nghttp2 "lib") zlib)))
-      (native-inputs (cons*
-                      ;; Keep in sync with the llvm used to build rust.
-                      `("clang-source" ,(package-source clang-runtime-15))
-                      ;; Add test inputs.
-                      `("gdb" ,gdb/pinned)
-                      `("procps" ,procps)
-                      (package-native-inputs base-rust))))))
+      ;; Add test inputs.
+      (native-inputs (cons* `("gdb" ,gdb/pinned)
+                            `("procps" ,procps)
+                            (package-native-inputs base-rust))))))
 
 (define*-public (make-rust-sysroot target)
   (make-rust-sysroot/implementation target rust))
-- 
2.45.2