tech-pkg archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[PATCH] Cross-building rusty packages



The attached patch is a substantial revision of my previous changes
for Rust cross-builds.

Using this patch (or slightly earlier revisions of it, differing by
minor tweaks and rebases of pkgsrc -- it takes a long time to build
all this stuff), I've been able to:

1. natively compile a Rust cross-toolchain without the
   cross.mk/do-cross.mk scaffolding, that is, using only pkgsrc's
   TARGET_* variables which are set automatically for TOOL_DEPENDS of
   cross-built packages;

2. cross-compile a native Rust toolchain (and build a bootstrap kit as
   a byproduct) using pkgsrc's built-in cross-compilation support; and

3. cross-compile other rusty packages including www/firefox (with some
   other local changes not yet committed).

This puts back one annoying ${ :? : } ternary operator versus the
crossrust-v2.patch I posted a while ago because of tricky ordering
between the assignment of PKGNAME and use of TARGET_MACHINE_PLATFORM
relative to bsd.prefs.mk -- sorry, I don't think there is a better way
to do this right now.

I sought to minimize changes that could even potentially affect native
builds of a native toolchain and native rusty packages by keeping
almost all the logic scoped under !empty(TARGET_MACHINE_PLATFORM) or
${USE_CROSS_COMPILE:tl} == "yes".  There are a couple minor changes
that _could_ affect native builds but I don't think they have any real
consequences -- see the commit message and patch for details.

I also have analogous patches queued up for pkgsrc-wip to rust181
through rust184.  These patches depend on the CARGO_TARGET_DIR patch
(https://mail-index.NetBSD.org/tech-pkg/2025/02/06/msg030459.html).

OK?
From b844dbdba7adabccec61c161093467728eb8b234 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 6 Feb 2025 13:54:57 +0000
Subject: [PATCH] lang/rust: Add support for cross-compiling Rust packages.

This does several things:

1. Enables lang/rust to build a cross-compiler package.
2. Enables lang/rust to be cross-compiled itself.
3. Enables other packages written in Rust to be cross-compiled.

Details:

1. Enables lang/rust to build a cross-compiler package, which is
   named, e.g., rust-NetBSD-10.0-aarch64-1.82.0 instead of
   rust-1.82.0, with all its files installed under
   ${PREFIX}/rust-NetBSD-10.0-aarch64 so it doesn't conflict.

   => The installation directory is called RUST_PREFIX in the
      Makefile -- which is just PREFIX when TARGET_* is not set,
      i.e., when we're building a normal Rust toolchain, not a
      cross-toolchain, so no change to native builds.

   => The Rust architecture determination is moved to a data-driven
      table in lang/rust/arch.mk.  (For now, the conditional-driven
      table is preserved in order to avoid the possibility of
      regressions in native builds -- we can clean this up later and
      reduce the makefile once we confirm they agree.)

   NOTE: This adds two patches that potentially affect native builds,
   but I don't think it will cause any trouble:

   (a) Use `-L=@PREFIX@/lib/libatomic' instead of
       `-L@PREFIX@/lib/libatomic' in the compiler's target spec.

       => This is unlikely to affect native builds -- the `-L='
          notation means the path is to be taken relative to sysroot,
          but in native builds the sysroot is empty (or /), so it
          should only change things when the sysroot is nonempty as
          in cross-builds.

   (b) Add @RUST_PREFIX@/lib to a couple of library search paths that
       already have @PREFIX@/lib.

       => In native builds, RUST_PREFIX and PREFIX coincide, so this
          should be harmless.

2. Enables lang/rust to be cross-compiled itself using pkgsrc's
   normal cross-compilation procedures.

   => This TOOL_DEPENDS on the cross-compiler package of (1).

   => This produces a Rust bootstrap kit as a side effect under the
      wrkdir, without having to configure the rust-specific
      cross.mk/do-cross.mk machinery.

3. Enables packages which are written in Rust using rust.mk or
   cargo.mk to be cross-compiled using the cross-compiler package of
   (1).

   => rust.mk and cargo.mk are adapted to:

      - pull in the appropriate TOOL_DEPENDS for Rust cross-compiler
        packages;

      - create `rustc' and `cargo' tools that point at the right
        place -- ${TOOLBASE}/rust-${RUST_ARCH}/bin/cargo for
        cross-builds, plus a native-cc tool that uses ${NATIVE_CC} in
        cross-builds;

      - pass `--target ${RUST_ARCH}' to cargo, and

      - set CARGO_TARGET_DIR with the extra RUST_ARCH path component
        so packages' do-install targets can use it to find the build
        products in native and cross builds alike.

   => I believe the logic for cross-built TOOL_DEPENDS should also
      work for native builds.  But to avoid the possibility of
      regressions, I have kept all these changes under
      USE_CROSS_COMPILE yes conditionals.

Proposed on tech-pkg:

https://mail-index.NetBSD.org/tech-pkg/2025/01/12/msg030371.html
---
 lang/rust/Makefile                            | 234 ++++++++++++++++--
 lang/rust/arch.mk                             |  64 +++++
 lang/rust/cargo.mk                            |  37 +++
 lang/rust/distinfo                            |   6 +-
 lang/rust/options.mk                          |   8 +-
 ...iler_rustc__target_src_spec_base_netbsd.rs |   2 +-
 .../patches/patch-src_bootstrap_bootstrap.py  |   3 +-
 .../patch-src_bootstrap_src_core_builder.rs   |   4 +-
 lang/rust/rust.mk                             |  34 +++
 9 files changed, 365 insertions(+), 27 deletions(-)
 create mode 100644 lang/rust/arch.mk

diff --git a/lang/rust/Makefile b/lang/rust/Makefile
index 6a3d5f502923..45754d824d36 100644
--- a/lang/rust/Makefile
+++ b/lang/rust/Makefile
@@ -1,7 +1,7 @@
 # $NetBSD: Makefile,v 1.322 2025/02/02 13:34:47 he Exp $
 
 DISTNAME=	rustc-1.82.0-src
-PKGNAME=	${DISTNAME:S/rustc/rust/:S/-src//}
+PKGNAME=	${DISTNAME:S/rustc/rust${PKGNAME_TARGET_SUFFIX}/:S/-src//}
 CATEGORIES=	lang
 MASTER_SITES=	https://static.rust-lang.org/dist/
 
@@ -12,6 +12,8 @@ LICENSE=	mit OR apache-2.0
 
 CONFLICTS+=	rust-bin-[0-9]*
 
+PKGNAME_TARGET_SUFFIX=	${empty(TARGET_MACHINE_PLATFORM):?:-${TARGET_MACHINE_PLATFORM}}
+
 # LLVM uses -std=c++17
 USE_CXX_FEATURES+=	c++17
 USE_GCC_RUNTIME=	yes
@@ -35,9 +37,9 @@ HAS_CONFIGURE=		yes
 PYTHON_FOR_BUILD_ONLY=	tool
 CONFIG_SHELL=		${TOOL_PYTHONBIN}
 CONFIGURE_SCRIPT=	src/bootstrap/configure.py
-CONFIGURE_ARGS+=	--prefix=${PREFIX}
-CONFIGURE_ARGS+=	--mandir=${PREFIX}/${PKGMANDIR}
-CONFIGURE_ARGS+=	--sysconfdir=${PKG_SYSCONFDIR}
+CONFIGURE_ARGS+=	--prefix=${RUST_PREFIX}
+CONFIGURE_ARGS+=	--mandir=${RUST_PREFIX}/${PKGMANDIR}
+CONFIGURE_ARGS+=	--sysconfdir=${PKG_SYSCONFDIR} # XXX RUST_PREFIX?
 CONFIGURE_ARGS+=	--python=${TOOL_PYTHONBIN}
 CONFIGURE_ARGS+=	--release-channel=stable
 CONFIGURE_ARGS+=	--local-rust-root=${RUST_BOOTSTRAP_PATH}
@@ -88,6 +90,22 @@ TEST_TARGET=	check
 CHECK_RELRO_SUPPORTED=	no
 CHECK_SSP_SUPPORTED=	no
 
+# Avoid conflicts when you want native-rust-native-compiler vs
+# native-rust-cross-compiler (vs native-rust-cross-compiler targeting
+# another architecture).
+#
+# There is an annoying ordering constraint here: we have to set
+# WRKDIR_BASENAME before including bsd.prefs.mk, but bsd.prefs.mk
+# defines TARGET_MACHINE_PLATFORM.  So we make the conditional be based
+# on TARGET_MACHINE_ARCH, which is passed through recursive make flags
+# (and is used to determine TARGET_MACHINE_PLATFORM).
+#
+# XXX Find a better way to do this -- shouldn't stomp on user's
+# WRKDIR_BASENAME or ignore OBJHOSTNAME.
+.if !empty(TARGET_MACHINE_ARCH)
+WRKDIR_BASENAME=	work-${TARGET_MACHINE_PLATFORM}${_CROSSDIR_SUFFIX}
+.endif
+
 .include "../../mk/bsd.prefs.mk"
 
 # Allow overriding MAKE_JOBS_SAFE
@@ -103,7 +121,7 @@ MAKE_JOBS_SAFE=		yes
 BUILD_TARGET=	${rust.BUILD_TARGET}
 .endif
 
-.if !empty(TARGET)
+.if !empty(TARGET) || !empty(TARGET_MACHINE_PLATFORM)
 # Use "dist" build target for cross compile of bootstrap
 BUILD_TARGET?=		dist
 .else
@@ -145,9 +163,9 @@ CONFIGURE_ARGS+=	--set llvm.targets="Mips"
 CONFIGURE_ARGS+=	--set llvm.targets="Mips;X86"
 .endif
 
-CHECK_INTERPRETER_SKIP+=	lib/rustlib/src/rust/library/backtrace/ci/*.sh
-CHECK_INTERPRETER_SKIP+=	lib/rustlib/src/rust/library/core/src/unicode/printable.py
-CHECK_INTERPRETER_SKIP+=	lib/rustlib/src/rust/library/stdarch/ci/*.sh
+CHECK_INTERPRETER_SKIP+=	${RUST_PREFIX_SUBDIR}lib/rustlib/src/rust/library/backtrace/ci/*.sh
+CHECK_INTERPRETER_SKIP+=	${RUST_PREFIX_SUBDIR}lib/rustlib/src/rust/library/core/src/unicode/printable.py
+CHECK_INTERPRETER_SKIP+=	${RUST_PREFIX_SUBDIR}lib/rustlib/src/rust/library/stdarch/ci/*.sh
 CHECK_PORTABILITY_SKIP+=	tests/run-make/dump-ice-to-disk/check.sh
 CHECK_PORTABILITY_SKIP+=	vendor/libdbus-sys-0.2.5/vendor/dbus/tools/cmake-format
 
@@ -201,12 +219,181 @@ BUILDLINK_TRANSFORM.NetBSD+=	rm:-Wl,--enable-new-dtags
 BUILDLINK_TRANSFORM+=	opt:x86_64:arm64
 .endif
 
+# XXX Copypasta of arch.mk -- remove me and use arch.mk once we verify
+# that it produces the same RUST_ARCH on all platforms.
+RUST_MACHINE_ARCH.i386=		i586		# not really
+RUST_MACHINE_ARCH.aarch64eb=	aarch64_be
+RUST_MACHINE_ARCH.riscv64=	riscv64gc
+
+RUST_LOWER_OPSYS.solaris=	illumos
+
+.if empty(TARGET_MACHINE_PLATFORM)
+
+RUST_PREFIX=		${PREFIX}
+RUST_PREFIX_SUBDIR=	# empty
+
+.else				# !empty(TARGET_MACHINE_PLATFORM)
+
+# Put Rust cross-toolchain packages in a prefix that doesn't conflict
+# with the native Rust toolchain package, or with each other.
+#
+# XXX Consider using ${TARGET_MACHINE_PLATFORM} so this has the OS
+# version embedded too; otherwise, e.g., 9.0 and 10.0 packages will
+# collide -- alternatively, package should be named with
+# ${TARGET_RUST_ARCH} instead of ${TARGET_MACHINE_PLATFORM}.
+#
+# XXX Make a PLIST substitution for RUST_PREFIX_SUBDIR.
+RUST_PREFIX=		${PREFIX}/rust-${TARGET_RUST_ARCH}
+RUST_PREFIX_SUBDIR=	rust-${TARGET_RUST_ARCH}/
+
+# XXX Copypasta of arch.mk -- remove me and use arch.mk once we verify
+# that it produces the same RUST_ARCH on all platforms.
+TARGET_RUST_MACHINE_ARCH=	\
+	${RUST_MACHINE_ARCH.${TARGET_MACHINE_ARCH}:U${TARGET_MACHINE_ARCH}}
+.  if empty(TARGET_LOWER_VENDOR)
+TARGET_RUST_LOWER_VENDOR=	unknown
+.  else
+TARGET_RUST_LOWER_VENDOR=	${TARGET_LOWER_VENDOR}
+.  endif
+TARGET_RUST_LOWER_OPSYS=	\
+	${RUST_LOWER_OPSYS.${TARGET_LOWER_OPSYS}:U${TARGET_LOWER_OPSYS}}
+TARGET_RUST_ARCH=		\
+	${TARGET_RUST_MACHINE_ARCH}-${TARGET_RUST_LOWER_VENDOR}-${TARGET_RUST_LOWER_OPSYS}${TARGET_APPEND_ABI}
+
+# Include both the target and the native architectures.  This is
+# necessary, e.g., to natively compile build.rs scripts while
+# cross-building.
+CONFIGURE_ARGS+=	--target=${TARGET_RUST_ARCH:Q},${RUST_ARCH:Q}
+
+LDFLAGS+=			${COMPILER_RPATH_FLAG}${RUST_PREFIX}/lib
+BUILDLINK_PASSTHRU_RPATHDIRS+=	${RUST_PREFIX}/lib
+
+# Note that these tools -- target-cc, target-cxx -- do not go through
+# the wrappers framework, because we're building the cross-compiler
+# right now rather than using it -- the wrappers apply to the native
+# cc/cxx/linker.  So we have to set sysroot ourselves.  But fortunately
+# the C cross-compiler is only used for a small part of this, to
+# cross-compile compiler-rt, so the risk of bypassing pkgsrc wrappers
+# is minimal -- in fact, since this cross-compiler doesn't even know
+# about pkgsrc's cross-localbase, it is even less likely to
+# accidentally pick anything up it shouldn't anyway.
+TOOLS_CREATE+=		target-cc
+TOOLS_PATH.target-cc=	${TOOLDIR}/bin/${TARGET_MACHINE_GNU_PLATFORM}-gcc # XXX shouldn't hard-code gcc
+TOOLS_ARGS.target-cc=	--sysroot=${CROSS_DESTDIR:Q}
+TOOLS_CREATE+=		target-cxx
+TOOLS_PATH.target-cxx=	${TOOLDIR}/bin/${TARGET_MACHINE_GNU_PLATFORM}-c++
+TOOLS_ARGS.target-cxx=	--sysroot=${CROSS_DESTDIR:Q}
+
+CONFIGURE_ARGS+=	\
+	--set=target.${TARGET_RUST_ARCH:Q}.cc=${TOOLS_CMD.target-cc:Q}
+CONFIGURE_ARGS+=	\
+	--set=target.${TARGET_RUST_ARCH:Q}.cxx=${TOOLS_CMD.target-cxx:Q}
+CONFIGURE_ARGS+=	\
+	--set=target.${TARGET_RUST_ARCH:Q}.linker=${TOOLS_CMD.target-cc:Q}
+# XXX
+CONFIGURE_ARGS+=	\
+	--set=target.${TARGET_RUST_ARCH:Q}.ar=${TOOLDIR:Q}/bin/${TARGET_MACHINE_GNU_PLATFORM:Q}-ar
+
+.endif				# empty(TARGET_MACHINE_PLATFORM)
+
 #
 # Rust unfortunately requires itself to build.  On platforms which aren't
 # supported by upstream (where they offer binary bootstraps), or where we do
 # not trust random binaries from the Internet, we need to build and provide our
 # own bootstrap.  See the stage0-bootstrap below for more details.
 #
+.if ${USE_CROSS_COMPILE:tl} == "yes"	# {
+
+# XXX Copypasta of arch.mk -- remove me and use arch.mk once we verify
+# that it produces the same RUST_ARCH on all platforms.
+RUST_MACHINE_ARCH=	${RUST_MACHINE_ARCH.${MACHINE_ARCH}:U${MACHINE_ARCH}}
+.  if empty(LOWER_VENDOR)
+RUST_LOWER_VENDOR=	unknown
+.  else
+RUST_LOWER_VENDOR=	${LOWER_VENDOR}
+.  endif
+RUST_LOWER_OPSYS=	${RUST_LOWER_OPSYS.${LOWER_OPSYS}:U${LOWER_OPSYS}}
+RUST_ARCH=		\
+	${RUST_MACHINE_ARCH}-${RUST_LOWER_VENDOR}-${RUST_LOWER_OPSYS}${APPEND_ABI}
+
+NATIVE_RUST_MACHINE_ARCH=	\
+	${RUST_MACHINE_ARCH.${NATIVE_MACHINE_ARCH}:U${NATIVE_MACHINE_ARCH}}
+.  if empty(NATIVE_LOWER_VENDOR)
+NATIVE_RUST_LOWER_VENDOR=	unknown
+.  else
+NATIVE_RUST_LOWER_VENDOR=	${NATIVE_LOWER_VENDOR}
+.  endif
+NATIVE_RUST_LOWER_OPSYS=	\
+	${RUST_LOWER_OPSYS.${NATIVE_LOWER_OPSYS}:U${NATIVE_LOWER_OPSYS}}
+NATIVE_RUST_ARCH=		\
+	${NATIVE_RUST_MACHINE_ARCH}-${NATIVE_RUST_LOWER_VENDOR}-${NATIVE_RUST_LOWER_OPSYS}${NATIVE_APPEND_ABI}
+
+# XXX Doesn't actually require the latest version!  In principle we
+# should be able to bootstrap this all the way back to OCaml via some
+# series of older versions.
+#
+# XXX Use a native bootstrap kit if available and desired -- requires
+# changing all the MACHINE_PLATFORMs below to NATIVE_MACHINE_PLATFORMs.
+TOOL_DEPENDS+=		rust-${MACHINE_PLATFORM}>=${PKGVERSION}:../../${PKGPATH}
+RUST_BOOTSTRAP_PATH=	${TOOLBASE}/rust-${RUST_ARCH}
+
+# Cross-build to run on MACHINE_PLATFORM, phrased for Rust as
+# RUST_ARCH.
+CONFIGURE_ARGS+=	--host=${RUST_ARCH:Q}
+
+TOOLS_CREATE+=		native-cc native-cxx native-ar
+TOOLS_SCRIPT.native-cc=	exec ${NATIVE_CC} "$$@"
+TOOLS_SCRIPT.native-cxx=exec ${NATIVE_CXX} "$$@"
+TOOLS_SCRIPT.native-ar=	exec ${NATIVE_AR} "$$@"
+
+CONFIGURE_ARGS+=	\
+	--set=target.${NATIVE_RUST_ARCH:Q}.cc=${TOOLS_CMD.native-cc:Q}
+CONFIGURE_ARGS+=	\
+	--set=target.${NATIVE_RUST_ARCH:Q}.cxx=${TOOLS_CMD.native-cxx:Q}
+CONFIGURE_ARGS+=	\
+	--set=target.${NATIVE_RUST_ARCH:Q}.linker=${TOOLS_CMD.native-cc:Q}
+CONFIGURE_ARGS+=	\
+	--set=target.${NATIVE_RUST_ARCH:Q}.ar=${TOOLS_CMD.native-ar:Q}
+
+# Not all of the build respects --set=target options, so try harder.
+#
+# For example:
+#
+# warning: libz-sys@1.1.18: ToolExecError: Command "aarch64--netbsd-gcc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-m64" "-I" "src/zlib" "-fvisibility=hidden" "-DZ_SOLO" "-DSTDC" "-D_LARGEFILE64_SOURCE" "-D_POSIX_SOURCE" "-o" "/home/riastradh/pkgsrc/current/crosswork/wip/rust183/work.NetBSD-10.0-aarch64/rustc-1.83.0-src/build/x86_64-unknown-netbsd/stage1-tools/release/build/libz-sys-bfca60dc728da21b/out/lib/0dc752f03a07a721-zutil.o" "-c" "src/zlib/zutil.c" with args aarch64--netbsd-gcc did not execute successfully (status code exit status: 1).
+#
+# error: failed to run custom build command for `libz-sys v1.1.18`
+#
+# Caused by:
+#   process didn't exit successfully: `/home/riastradh/pkgsrc/current/crosswork/wip/rust183/work.NetBSD-10.0-aarch64/rustc-1.83.0-src/build/x86_64-unknown-netbsd/stage1-tools/release/build/libz-sys-f4e66731319f71b4/build-script-build` (exit status: 1)
+#   --- stdout
+# ...
+#   TARGET = Some(x86_64-unknown-netbsd)
+# ...
+#   HOST = Some(x86_64-unknown-netbsd)
+#   cargo:rerun-if-env-changed=CC_x86_64-unknown-netbsd
+#   CC_x86_64-unknown-netbsd = None
+#   cargo:rerun-if-env-changed=CC_x86_64_unknown_netbsd
+#   CC_x86_64_unknown_netbsd = None
+#   cargo:rerun-if-env-changed=HOST_CC
+#   HOST_CC = None
+#   cargo:rerun-if-env-changed=CC
+#   CC = Some(aarch64--netbsd-gcc)
+#
+# https://github.com/rust-lang/rust/issues/136090
+#
+MAKE_ENV+=		HOST_CC=${TOOLS_CMD.native-cc:Q}
+MAKE_ENV+=		HOST_CXX=${TOOLS_CMD.native-cxx:Q}
+MAKE_ENV+=		HOST_AR=${TOOLS_CMD.native-ar:Q}
+
+# Prevent Rust from picking up CFLAGS/CXXFLAGS/LDFLAGS for the target
+# system when natively compiling things to run on the build system.  We
+# pass any necessary arguments through the tool wrappers anyway.
+MAKE_ENV+=		HOST_CFLAGS=
+MAKE_ENV+=		HOST_CXXFLAGS=
+MAKE_ENV+=		HOST_LDFLAGS=
+
+.else					# } {
+
 DISTFILES:=		${DEFAULT_DISTFILES}
 
 .if ${MACHINE_PLATFORM:MDarwin-*-aarch64} || make(distinfo) || make (makesum) || make(mdi)
@@ -383,6 +570,8 @@ SITES.${RUST_STAGE0}=		${MASTER_SITE_LOCAL:=rust/}
 SITES.${RUST_STD_STAGE0}=	${MASTER_SITE_LOCAL:=rust/}
 .endif
 
+.endif					# }
+
 # You may override RUST_BOOTSTRAP_PATH and RUST_ARCH in mk.conf
 # if you have a local bootstrap compiler.
 .if !defined(RUST_ARCH) && !defined(RUST_BOOTSTRAP_PATH)
@@ -406,7 +595,7 @@ SUBST_FILES.prefix+=	compiler/rustc_target/src/spec/base/netbsd.rs
 SUBST_FILES.prefix+=	src/bootstrap/src/core/build_steps/compile.rs
 SUBST_FILES.prefix+=	src/bootstrap/src/core/builder.rs
 SUBST_FILES.prefix+=	src/bootstrap/bootstrap.py
-SUBST_VARS.prefix=	PREFIX
+SUBST_VARS.prefix=	PREFIX RUST_PREFIX
 
 #
 # Generate list of subst entries for various .cargo-checksum.json files.  These
@@ -548,11 +737,20 @@ do-install:
 	cd ${WRKSRC} &&							\
 	${SETENV} ${MAKE_ENV} ${INSTALL_ENV} 				\
 		${TOOL_PYTHONBIN} ./x.py install -j ${_MAKE_JOBS_N}
+.if !empty(TARGET_MACHINE_PLATFORM)
+	${RUN}								\
+	${GTAR} -C ${WRKDIR:Q}						\
+		-xzf ${WRKSRC:Q}/build/dist/rust-std-${PKGVERSION_NOREV:Q}-${TARGET_RUST_ARCH:Q}.tar.xz
+	${RUN}								\
+	cd ${WRKDIR:Q}/rust-std-${PKGVERSION_NOREV:Q}-${TARGET_RUST_ARCH:Q} && \
+	${SETENV} ${MAKE_ENV} ${INSTALL_ENV}				\
+		./install.sh --prefix=${RUST_PREFIX:Q} --destdir=${DESTDIR:Q}
+.endif
 
 SUBST_CLASSES+=		destdir
 SUBST_STAGE.destdir=	post-install
-SUBST_FILES.destdir=	${DESTDIR}${PREFIX}/lib/rustlib/manifest-*
-SUBST_SED.destdir=	-e 's|file:${DESTDIR}${PREFIX}|file:${PREFIX}|'
+SUBST_FILES.destdir=	${DESTDIR}${RUST_PREFIX}/lib/rustlib/manifest-*
+SUBST_SED.destdir=	-e 's|file:${DESTDIR}${RUST_PREFIX}|file:${RUST_PREFIX}|'
 
 GENERATE_PLIST+=	${FIND} ${DESTDIR}${PREFIX} \( -type f -o -type l \) -print | \
 			${SED} -e 's,${DESTDIR}${PREFIX}/,,' | ${SORT} ;
@@ -607,8 +805,8 @@ stage0-bootstrap: install
 	)
 .endif
 .if ${OS_VARIANT} == "SmartOS"
-	${CP} -R ${DESTDIR}/${PREFIX}/bin ${BOOTSTRAP_TMPDIR}/
-	${CP} -R ${DESTDIR}/${PREFIX}/lib ${BOOTSTRAP_TMPDIR}/
+	${CP} -R ${DESTDIR}/${RUST_PREFIX}/bin ${BOOTSTRAP_TMPDIR}/
+	${CP} -R ${DESTDIR}/${RUST_PREFIX}/lib ${BOOTSTRAP_TMPDIR}/
 	${MKDIR} ${BOOTSTRAP_TMPDIR}/lib/pkgsrc
 	set -e; \
 	for lib in libgcc_s.so.1 libstdc++.so.6; do \
@@ -617,12 +815,12 @@ stage0-bootstrap: install
 	done; \
 	for lib in libLLVM.so.18.1 libcrypto.so.3 libcurl.so.4 \
 		   libssl.so.3 libz.so.1 libzstd.so.1; do \
-		${CP} ${PREFIX}/lib/$${lib} ${BOOTSTRAP_TMPDIR}/lib/pkgsrc/; \
+		${CP} ${RUST_PREFIX}/lib/$${lib} ${BOOTSTRAP_TMPDIR}/lib/pkgsrc/; \
 	done; \
 	for lib in libiconv.so.2 libidn2.so.0 libintl.so.8 liblber.so.2 \
 		   libldap.so.2 libnghttp2.so.14 libsasl2.so.3 \
 		   libssh2.so.1 libunistring.so.5; do \
-		${CP} ${PREFIX}/lib/$${lib} ${BOOTSTRAP_TMPDIR}/lib/pkgsrc/; \
+		${CP} ${RUST_PREFIX}/lib/$${lib} ${BOOTSTRAP_TMPDIR}/lib/pkgsrc/; \
 	done; \
 	for f in ${BOOTSTRAP_TMPDIR}/bin/*; do \
 		/bin/file -b "$$f" | grep ^ELF >/dev/null || continue; \
@@ -643,7 +841,7 @@ stage0-bootstrap: install
 	@${ECHO} "Verify correct library paths using the following:"
 	@${ECHO} ""
 	@${ECHO} "	cd ${BOOTSTRAP_TMPDIR}"
-	@${ECHO} "	find . -type f | xargs ldd 2>/dev/null | egrep 'not.found|${PREFIX}'"
+	@${ECHO} "	find . -type f | xargs ldd 2>/dev/null | egrep 'not.found|${RUST_PREFIX}'"
 	@${ECHO} ""
 	@${ECHO} "If there is no output then this bootstrap kit is ready to go:"
 	@${ECHO} ""
@@ -666,8 +864,8 @@ stage0-bootstrap: install
 # rust i386 and sparc64 bootstraps are built for 8.0
 # and still depend on libstdc++.so.8.
 # Pull in compat80 on 9.x and newer.
-.if (${MACHINE_PLATFORM:MNetBSD-*-i386} || \
-     ${MACHINE_PLATFORM:MNetBSD-*-sparc64}) \
+.if (${NATIVE_MACHINE_PLATFORM:MNetBSD-*-i386} || \
+     ${NATIVE_MACHINE_PLATFORM:MNetBSD-*-sparc64}) \
     && empty(OS_VERSION:M8.*)
 TOOL_DEPENDS+=	compat80>=0:../../emulators/compat80
 .endif
diff --git a/lang/rust/arch.mk b/lang/rust/arch.mk
new file mode 100644
index 000000000000..f8b75dc5ac5c
--- /dev/null
+++ b/lang/rust/arch.mk
@@ -0,0 +1,64 @@
+#	$NetBSD$
+#
+# Common logic to map pkgsrc idea of machine platforms into Rust idea
+# of architectures.
+#
+# System-provided variables:
+#
+# RUST_ARCH
+#	The Rust architecture triple that this package is built for.
+#
+# NATIVE_RUST_ARCH
+#	The Rust architecture triple that we are doing the build on.
+#
+# TARGET_RUST_ARCH
+#	If nonempty, the Rust architecture triple that this package may
+#	be intended to support as a cross-compiler target.
+#
+#	Nonempty if and only if TARGET_MACHINE_PLATFORM is nonempty,
+#	i.e., this package is being built as a TOOL_DEPENDS dependency
+#	of another package and thus may be being built as a
+#	cross-compiler.
+#
+
+RUST_MACHINE_ARCH.i386=		i586		# not really
+RUST_MACHINE_ARCH.aarch64eb=	aarch64_be
+RUST_MACHINE_ARCH.riscv64=	riscv64gc
+
+RUST_LOWER_OPSYS.solaris=	illumos
+
+RUST_MACHINE_ARCH=	${RUST_MACHINE_ARCH.${MACHINE_ARCH}:U${MACHINE_ARCH}}
+.if empty(LOWER_VENDOR)
+RUST_LOWER_VENDOR=	unknown
+.else
+RUST_LOWER_VENDOR=	${LOWER_VENDOR}
+.endif
+RUST_LOWER_OPSYS=	${RUST_LOWER_OPSYS.${LOWER_OPSYS}:U${LOWER_OPSYS}}
+RUST_ARCH=		\
+	${RUST_MACHINE_ARCH}-${RUST_LOWER_VENDOR}-${RUST_LOWER_OPSYS}${APPEND_ABI}
+
+NATIVE_RUST_MACHINE_ARCH=	\
+	${RUST_MACHINE_ARCH.${NATIVE_MACHINE_ARCH}:U${NATIVE_MACHINE_ARCH}}
+.if empty(NATIVE_LOWER_VENDOR)
+NATIVE_RUST_LOWER_VENDOR=	unknown
+.else
+NATIVE_RUST_LOWER_VENDOR=	${NATIVE_LOWER_VENDOR}
+.endif
+NATIVE_RUST_LOWER_OPSYS=	\
+	${RUST_LOWER_OPSYS.${NATIVE_LOWER_OPSYS}:U${NATIVE_LOWER_OPSYS}}
+NATIVE_RUST_ARCH=		\
+	${NATIVE_RUST_MACHINE_ARCH}-${NATIVE_RUST_LOWER_VENDOR}-${NATIVE_RUST_LOWER_OPSYS}${NATIVE_APPEND_ABI}
+
+.if !empty(TARGET_MACHINE_PLATFORM)
+TARGET_RUST_MACHINE_ARCH=	\
+	${RUST_MACHINE_ARCH.${TARGET_MACHINE_ARCH}:U${TARGET_MACHINE_ARCH}}
+.  if empty(TARGET_LOWER_VENDOR)
+TARGET_RUST_LOWER_VENDOR=	unknown
+.  else
+TARGET_RUST_LOWER_VENDOR=	${TARGET_LOWER_VENDOR}
+.  endif
+TARGET_RUST_LOWER_OPSYS=	\
+	${RUST_LOWER_OPSYS.${TARGET_LOWER_OPSYS}:U${TARGET_LOWER_OPSYS}}
+TARGET_RUST_ARCH=		\
+	${TARGET_RUST_MACHINE_ARCH}-${TARGET_RUST_LOWER_VENDOR}-${TARGET_RUST_LOWER_OPSYS}${TARGET_APPEND_ABI}
+.endif
diff --git a/lang/rust/cargo.mk b/lang/rust/cargo.mk
index 7dbc30f57aed..b6967fecdd5a 100644
--- a/lang/rust/cargo.mk
+++ b/lang/rust/cargo.mk
@@ -72,13 +72,46 @@ print-cargo-depends:
 
 .if ${RUST_TYPE} == "native"
 CARGO=			cargo
+.elif ${USE_CROSS_COMPILE:tl} == "yes"
+# XXX Nix this conditional once we verify no fallout for native builds:
+# using TOOLS_CREATE to create a cargo tool, and writing
+# ${TOOLBASE}/bin/cargo instead of ${PREFIX}/bin/cargo, and similarly
+# for rustc, should all work just fine for native builds.
+.  include "arch.mk"
+CARGO=			cargo
+TOOLS_CREATE+=		cargo
+.  if ${USE_CROSS_COMPILE:tl} == "yes"
+TOOLS_PATH.cargo=	${TOOLBASE}/rust-${RUST_ARCH}/bin/cargo
+.  else
+TOOLS_PATH.cargo=	${TOOLBASE}/bin/cargo
+.  endif
+TOOLS_CREATE+=		rustc
+.  if ${USE_CROSS_COMPILE:tl} == "yes"
+TOOLS_PATH.rustc=	${TOOLBASE}/rust-${RUST_ARCH}/bin/rustc
+.  else
+TOOLS_PATH.rustc=	${TOOLBASE}/bin/rustc
+.  endif
 .else
 CARGO=			${PREFIX}/bin/cargo
 .endif
+
+.if ${USE_CROSS_COMPILE:tl} == "yes"
+ALL_ENV+=		CARGO_TARGET_${NATIVE_RUST_ARCH:S/-/_/g:tu}_LINKER=native-cc
+TOOLS_CREATE+=		native-cc
+TOOLS_SCRIPT.native-cc=	exec ${NATIVE_CC} "$$@"
+.endif				# ${USE_CROSS_COMPILE:tl} == "yes"
+
 DEFAULT_CARGO_ARGS=	--offline -j${_MAKE_JOBS_N}	\
 			  ${CARGO_NO_DEFAULT_FEATURES:M[yY][eE][sS]:C/[yY][eE][sS]/--no-default-features/}	\
 			  ${CARGO_FEATURES:C/.*/--features/W}	\
 			  ${CARGO_FEATURES:S/ /,/Wg}
+.if ${USE_CROSS_COMPILE:tl} == "yes"
+# XXX Consider setting CARGO_BUILD_TARGET=${RUST_ARCH:Q} in the
+# environment instead, for the benefit of packages built with tools
+# like py-maturin which call cargo but not directly with our do-build
+# target or CARGO_ARGS.
+DEFAULT_CARGO_ARGS+=	--target ${RUST_ARCH:Q}
+.endif
 CARGO_ARGS?=		build --release ${DEFAULT_CARGO_ARGS}
 CARGO_INSTALL_ARGS?=	install --path . --root ${DESTDIR}${PREFIX} ${DEFAULT_CARGO_ARGS}
 
@@ -86,7 +119,11 @@ CARGO_INSTALL_ARGS?=	install --path . --root ${DESTDIR}${PREFIX} ${DEFAULT_CARGO
 # tuple (architecture/vendor/OS) and for the directory where build
 # products go.  The name CARGO_TARGET_DIR (or CARGO_BUILD_TARGET_DIR)
 # is what cargo uses for the directory of build products.
+.if ${USE_CROSS_COMPILE:tl} == "yes"
+CARGO_TARGET_SUBDIR=	target/${RUST_ARCH}/release
+.else
 CARGO_TARGET_SUBDIR=	target/release
+.endif
 CARGO_TARGET_DIR=	${WRKSRC}/${CARGO_TARGET_SUBDIR}
 
 MAKE_ENV+=		RUSTFLAGS=${RUSTFLAGS:Q}
diff --git a/lang/rust/distinfo b/lang/rust/distinfo
index 60bac3f5ed33..5715f127b419 100644
--- a/lang/rust/distinfo
+++ b/lang/rust/distinfo
@@ -110,7 +110,7 @@ SHA512 (rustc-1.82.0-src.tar.gz) = 0a4b4aeffe02fae35bafd64429d15009c23e5f698c0c5
 Size (rustc-1.82.0-src.tar.gz) = 434309696 bytes
 SHA1 (patch-compiler_rustc__codegen__ssa_src_back_linker.rs) = f2af6e3b4925e8ca21b7cd783f7831b72700384a
 SHA1 (patch-compiler_rustc__llvm_build.rs) = a4a66d449fc9eb99d648d02a041778a68f4f7ce8
-SHA1 (patch-compiler_rustc__target_src_spec_base_netbsd.rs) = 7d910631f49acf2c33fdd191fd3e0f261efae234
+SHA1 (patch-compiler_rustc__target_src_spec_base_netbsd.rs) = 8e6e53b44c044230089ab0740cc929fd8671d50c
 SHA1 (patch-compiler_rustc__target_src_spec_mod.rs) = a22b5d28997ed9a5565deec9c34322165d563d00
 SHA1 (patch-compiler_rustc__target_src_spec_targets_aarch64__be__unknown__netbsd.rs) = 620eaf74c1dd030973af53dfe4f9aa998be5b123
 SHA1 (patch-compiler_rustc__target_src_spec_targets_aarch64__unknown__netbsd.rs) = 1a02f2dd61a5f9cc4be1f66ac3404c961810c731
@@ -122,11 +122,11 @@ SHA1 (patch-library_backtrace_src_symbolize_gimli.rs) = 9d5ef634c5a454e474ea5fee
 SHA1 (patch-library_backtrace_src_symbolize_gimli_elf.rs) = 3b84a462c6bc8245d579452e4c37e3ce13314952
 SHA1 (patch-library_std_src_sys_pal_unix_mod.rs) = bfc59ae4568547e3ed71c8b31ba5b5b5363d5d40
 SHA1 (patch-library_stdarch_crates_std__detect_tests_cpu-detection.rs) = 97c3ad8ea39c25d41256fcad80fae1e6e4970124
-SHA1 (patch-src_bootstrap_bootstrap.py) = 6f1d3068da49f19c3e092230ba1c7d99af628d3a
+SHA1 (patch-src_bootstrap_bootstrap.py) = 6ce15a434d163f921cc77c15c4b0c759a4de39f5
 SHA1 (patch-src_bootstrap_src_core_build__steps_compile.rs) = e928203ed4734c93cc33c5a3f7879cf18dcecc83
 SHA1 (patch-src_bootstrap_src_core_build__steps_dist.rs) = 22e37d6260cbd93ca3c6d119b58e48750836b17c
 SHA1 (patch-src_bootstrap_src_core_build__steps_install.rs) = cc6558df42c9c9ac28fdb2ff180bdaa7f22ce816
-SHA1 (patch-src_bootstrap_src_core_builder.rs) = 6d76366201097adc56e494fa05ebbc1696bb2d98
+SHA1 (patch-src_bootstrap_src_core_builder.rs) = 071c9a5151fb6dd5a8eabb7d5973d3e2a403062b
 SHA1 (patch-src_bootstrap_src_core_config_config.rs) = fa9d93602693bce064aa155ad0a204b176b47d99
 SHA1 (patch-src_bootstrap_src_lib.rs) = d29bc3c0b335d5e788eecbb02fc08966beef0fb1
 SHA1 (patch-src_llvm-project_llvm_CMakeLists.txt) = 7abfabb6ec70df229a69355f8c76825610165c37
diff --git a/lang/rust/options.mk b/lang/rust/options.mk
index 2fe51498b3f8..25d105dd9010 100644
--- a/lang/rust/options.mk
+++ b/lang/rust/options.mk
@@ -14,8 +14,12 @@ PKG_SUGGESTED_OPTIONS+=		rust-internal-llvm
 .  endif
 .endif
 
-# If cross-building, always use the internal LLVM
-.if !empty(TARGET)
+# If cross-building, always use the internal LLVM so we don't have to
+# deal with llvm-config for the cross-built system.
+#
+# XXX We ought to be able to use llvm-config here but it'll take some
+# work to make that happen, since llvm-config is a native executable.
+.if !empty(TARGET) || ${USE_CROSS_COMPILE:tl} == "yes"
 PKG_SUGGESTED_OPTIONS+=		rust-internal-llvm
 .endif
 
diff --git a/lang/rust/patches/patch-compiler_rustc__target_src_spec_base_netbsd.rs b/lang/rust/patches/patch-compiler_rustc__target_src_spec_base_netbsd.rs
index a5bdec2e50e0..7cbe33eb4c45 100644
--- a/lang/rust/patches/patch-compiler_rustc__target_src_spec_base_netbsd.rs
+++ b/lang/rust/patches/patch-compiler_rustc__target_src_spec_base_netbsd.rs
@@ -14,7 +14,7 @@ search the directory containing the symlinks to -latomic.
 +        &[
 +            // For the benefit of powerpc, when libatomic-links is installed,
 +            "-Wl,-R@PREFIX@/lib/libatomic",
-+            "-Wl,-L@PREFIX@/lib/libatomic",
++            "-Wl,-L=@PREFIX@/lib/libatomic",
 +        ];
 +    let pre_link_args = TargetOptions::link_args(
 +        LinkerFlavor::Gnu(Cc::Yes, Lld::No),
diff --git a/lang/rust/patches/patch-src_bootstrap_bootstrap.py b/lang/rust/patches/patch-src_bootstrap_bootstrap.py
index 3166c52a7f37..f29c058d0056 100644
--- a/lang/rust/patches/patch-src_bootstrap_bootstrap.py
+++ b/lang/rust/patches/patch-src_bootstrap_bootstrap.py
@@ -36,10 +36,11 @@ Also use @PREFIX@ and not $ORIGIN in rpath.
          else:
              kernel += 'eabihf'
      elif cputype == 'mips':
-@@ -734,6 +745,7 @@ class RustBuild(object):
+@@ -734,6 +745,8 @@ class RustBuild(object):
  
          patchelf = "{}/bin/patchelf".format(nix_deps_dir)
          rpath_entries = [
++            "@RUST_PREFIX@/lib",
 +	    "@PREFIX@/lib",
              os.path.join(os.path.realpath(nix_deps_dir), "lib")
          ]
diff --git a/lang/rust/patches/patch-src_bootstrap_src_core_builder.rs b/lang/rust/patches/patch-src_bootstrap_src_core_builder.rs
index 6142279cb0c8..3559cae00d44 100644
--- a/lang/rust/patches/patch-src_bootstrap_src_core_builder.rs
+++ b/lang/rust/patches/patch-src_bootstrap_src_core_builder.rs
@@ -1,7 +1,7 @@
 $NetBSD: patch-src_bootstrap_src_core_builder.rs,v 1.6 2025/02/02 13:34:47 he Exp $
 
 Find external libunwind on Linux.
-Use @PREFIX@, not $ORIGIN in rpath.
+Use @RUST_PREFIX@ and @PREFIX@, not $ORIGIN in rpath.
 
 --- src/bootstrap/src/core/builder.rs.orig	2006-07-24 01:21:28.000000000 +0000
 +++ src/bootstrap/src/core/builder.rs
@@ -22,7 +22,7 @@ Use @PREFIX@, not $ORIGIN in rpath.
              } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") {
                  self.rustflags.arg("-Clink-args=-Wl,-z,origin");
 -                Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}"))
-+                Some(format!("-Wl,-rpath,@PREFIX@/{libdir}"))
++                Some(format!("-Wl,-rpath,@RUST_PREFIX@/{libdir},-rpath,@PREFIX@/{libdir}"))
              } else {
                  None
              };
diff --git a/lang/rust/rust.mk b/lang/rust/rust.mk
index 82185914b67b..9b7cefbb6882 100644
--- a/lang/rust/rust.mk
+++ b/lang/rust/rust.mk
@@ -40,17 +40,51 @@ RUST_RUNTIME?=	no
 RUST_TYPE?=	src
 
 .if ${RUST_TYPE} == "bin"
+# XXX Remove this ${USE_CROSS_COMPILE} conditional once we confirm no
+# fallout in native builds from the TOOL_DEPENDS approach.
+.if ${USE_CROSS_COMPILE:tl} == "yes"
+.  include "arch.mk"
+.  if ${USE_CROSS_COMPILE:tl} == "yes"
+TOOL_DEPENDS+=			rust-${MACHINE_PLATFORM}-bin>=${RUST_REQ}:../../lang/rust-bin
+BUILDLINK_PASSTHRU_DIRS+=	${TOOLBASE}/rust-${RUST_ARCH}/lib/rustlib
+.  else
+TOOL_DEPENDS+=			rust-bin>=${RUST_REQ}:../../lang/rust-bin
+BUILDLINK_PASSTHRU_DIRS+=	${TOOLBASE}/lib/rustlib
+.  endif
+.  if ${RUST_RUNTIME} != "no"
+BUILDLINK_API_DEPENDS.rust-bin+=	rust-bin>=${RUST_REQ}
+.    include "${RUST_DIR}-bin/buildlink3.mk"
+.  endif
+.else
 .  if ${RUST_RUNTIME} == "no"
 BUILDLINK_DEPMETHOD.rust-bin?=		build
 .  endif
 BUILDLINK_API_DEPENDS.rust-bin+=	rust-bin>=${RUST_REQ}
 .  include "${RUST_DIR}-bin/buildlink3.mk"
 .endif
+.endif
 
 .if ${RUST_TYPE} == "src"
+# XXX Remove this ${USE_CROSS_COMPILE} conditional once we confirm no
+# fallout in native builds from the TOOL_DEPENDS approach.
+.if ${USE_CROSS_COMPILE:tl} == "yes"
+.  include "arch.mk"
+.  if ${USE_CROSS_COMPILE:tl} == "yes"
+TOOL_DEPENDS+=			rust-${MACHINE_PLATFORM}>=${RUST_REQ}:../../lang/rust
+BUILDLINK_PASSTHRU_DIRS+=	${TOOLBASE}/rust-${RUST_ARCH}/lib/rustlib
+.  else
+TOOL_DEPENDS+=			rust>=${RUST_REQ}:../../lang/rust
+BUILDLINK_PASSTHRU_DIRS+=	${TOOLBASE}/lib/rustlib
+.  endif
+.  if ${RUST_RUNTIME} != "no"
+BUILDLINK_API_DEPENDS.rust+=		rust>=${RUST_REQ}
+.    include "${RUST_DIR}/buildlink3.mk"
+.  endif
+.else
 .  if ${RUST_RUNTIME} == "no"
 BUILDLINK_DEPMETHOD.rust?=		build
 .  endif
 BUILDLINK_API_DEPENDS.rust+=		rust>=${RUST_REQ}
 .  include "${RUST_DIR}/buildlink3.mk"
 .endif
+.endif


Home | Main Index | Thread Index | Old Index