gentoo / gentoo-rust

[MIRROR] Rust packages
https://gitweb.gentoo.org/repo/proj/rust.git
80 stars 52 forks source link

upon cross-compiling with emerge-cross-wrappers #394

Open stefson opened 5 years ago

stefson commented 5 years ago

recently I did some research into how to to use rust and cargo to cross-compile, especially for armhf.

I found out, it's rather easy to set up rust for that: if rust-bin is your rust-provider, download rust-std-${PN}-${ARCH-TRIPLE}.tar.xz and install it with: ./install.sh --disable-verify --prefix=/opt/${P}/ --mandir="/usr/share/${P}/man" --disable-ldconfig

which gives you a rust-bin with the ability to cross-compile. (since rustc is more or less a frontend to llvm, you should have it emerged with llvm_target_arm?)

also emerge a full cross toolchain with crossdev, since rustc needs the cross-gcc as a linker.

now, it is common practice to cross-compile with emerge-wrappers, so an emerge-armv7a-unknown-linux-gnueabihf -auvND world should bootstrap a base cross system to work with, inheriting @system, and from there on it should be possible to compile individual packages and copy the tbz2 files from the cross environement over to the memory restrained arm device and emerge with the -k option to grab a binary if possible. Done that with sys-devel/gcc, sys-devel/llvm, dev-libs/boost, etc. pp.

Now, with a host where rustc has the foreign rust-std installed it should just work to emerge, for instance, dev-util/cbindgen this way. It does, however, with a bit of a show stopper:

>>> Completed installing cbindgen-0.6.7 into /usr/armv7a-unknown-linux-gnueabihf/tmp/portage/dev-util/cbindgen-0.6.7/image

 * Final size of build directory: 188124 KiB (183.7 MiB)
 * Final size of installed tree:    8072 KiB (  7.8 MiB)

strip: armv7a-unknown-linux-gnueabihf-strip --strip-unneeded -R .comment -R .GCC.command.line -R .note.gnu.gold-version
   /usr/bin/cbindgen
armv7a-unknown-linux-gnueabihf-strip:/usr/armv7a-unknown-linux-gnueabihf/tmp/portage/dev-util/cbindgen-0.6.7/image/usr/bin/cbindgen: file format not recognized
./
./usr/
./usr/bin/
./usr/bin/cbindgen
>>> Done.

the binary is in fact not a cross-compiled one, but for the hosts arch, thus cross-strip can't do anything about it.

stefson commented 5 years ago

The build.log itself isn't very usefull, as it hides the actuall compile commands from the user. Therefore, the first thing to do in an attempt to debug this is, to reenable cargo build -v in the cargo.eclass in the local portage tree:

    cargo: reenable cargo build -v for debugging

diff --git a/eclass/cargo.eclass b/eclass/cargo.eclass
index 051d5c499a6..8e92cb86277 100644
--- a/eclass/cargo.eclass
+++ b/eclass/cargo.eclass
@@ -122,7 +122,7 @@ cargo_src_compile() {

        export CARGO_HOME="${ECARGO_HOME}"

-       cargo build -j $(makeopts_jobs) $(usex debug "" --release) "$@" \
+       cargo build -v -j $(makeopts_jobs) $(usex debug "" --release) "$@" \
                || die "cargo build failed"
 }

which gives a more verbose build.log to read through: cbindgen-0.6.7-cross.log.zip

stefson commented 5 years ago

next step would be to find out, wether a build outside of portage would work: I copied the folder src and Cargo.toml from /var/tmp/portage/dev-util/cbindgen-0.6.7/work/cbindgen-0.6.7/ to temporary folder, entered it via the cmd line and made it compile via cargo build --target=armv7-unknown-linux-gnueabihf

here is the build log of that approach: cbindgen-0.6.7-cross-non-portage.log.zip

which gives a valid arm binary: file cbindgen cbindgen: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, with debug_info, not stripped

which can be striped with cross-strip: file cbindgen cbindgen: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, stripped

stefson commented 5 years ago

one smoking gun I found is, that upon linking during cross-compile cargo has to be told about where the cross-gcc is to be found via ~/.cargo/config

[target.armv7-unknown-linux-gnueabihf] linker = "armv7a-unknown-linux-gnueabihf-gcc"

otherwise the non-portage build would flake out with error: linking with `cc` failed: exit code: 1

and it seems to me that portage sets its own cargo home config during each install, which makes sense as emerge is run via the the user/group portage:portage, and it doesn't have a folder in /home/

but, to be honest, I think the first problem here is that portage doesn't invoke rustc with the correct --target option at all, but simply issues the native rustc command.

How may I change this behavior, for to emerge the package with cross-portage?

stefson commented 5 years ago

ok, we're getting closer as I switched on --target option via the cargo.eclass


diff --git a/eclass/cargo.eclass b/eclass/cargo.eclass
index 8e92cb86277..b4b5d86ffcb 100644
--- a/eclass/cargo.eclass
+++ b/eclass/cargo.eclass
@@ -122,7 +122,7 @@ cargo_src_compile() {

        export CARGO_HOME="${ECARGO_HOME}"

-       cargo build -v -j $(makeopts_jobs) $(usex debug "" --release) "$@" \
+       cargo build -v --target=armv7-unknown-linux-gnueabihf -j $(makeopts_jobs) $(usex debug "" --release) "$@" \
                || die "cargo build failed"
 }

This is of course very unsophisticated, needs more general approach if ever going to the overlay or the tree even. But it makes emerge run into the linker errors, as it should when picking native gcc to link a foreign binary, which shows that cross-compile has happened at some point:

error: linking with `cc` failed: exit code: 1 full log

stefson commented 5 years ago

Ok, so let's set up the linker as well:


diff --git a/eclass/cargo.eclass b/eclass/cargo.eclass
index b4b5d86ffcb..73f0dcad9cd 100644
--- a/eclass/cargo.eclass
+++ b/eclass/cargo.eclass
@@ -111,6 +111,10 @@ cargo_gen_config() {
        [source.crates-io]
        replace-with = "gentoo"
        local-registry = "/nonexistant"
+
+       [target.armv7-unknown-linux-gnueabihf]
+       linker = "armv7a-unknown-linux-gnueabihf-gcc"
+
        EOF
 }

this solves the linking error, but still emerge installs the native binary in src_install.

>>> Completed installing cbindgen-0.6.7 into /usr/armv7a-unknown-linux-gnueabihf/tmp/portage/dev-util/cbindgen-0.6.7/image

 * Final size of build directory: 237468 KiB (231.9 MiB)
 * Final size of installed tree:    8072 KiB (  7.8 MiB)

strip: armv7a-unknown-linux-gnueabihf-strip --strip-unneeded -R .comment -R .GCC.command.line -R .note.gnu.gold-version
   /usr/bin/cbindgen
armv7a-unknown-linux-gnueabihf-strip:/usr/armv7a-unknown-linux-gnueabihf/tmp/portage/dev-util/cbindgen-0.6.7/image/usr/bin/cbindgen: file format not recognized
./
./usr/
./usr/bin/
./usr/bin/cbindgen
>>> Done.
stefson commented 5 years ago

portage acutally ends up with two binaries now, one native and one cross-compiled one, in seperate folders:

user@tuxbox /usr/armv7a-unknown-linux-gnueabihf/tmp/portage/dev-util/cbindgen-0.6.7/work/cbindgen-0.6.7/target/release $ file cbindgen cbindgen: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, with debug_info, not stripped

user@tuxbox /usr/armv7a-unknown-linux-gnueabihf/tmp/portage/dev-util/cbindgen-0.6.7/work/cbindgen-0.6.7/target/armv7-unknown-linux-gnueabihf/release $ file cbindgen cbindgen: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, with debug_info, not stripped

stefson commented 5 years ago

Ok, finally got there: https://github.com/rust-lang/cargo/pull/5614 added an option to enable cargo install --target

diff --git a/eclass/cargo.eclass b/eclass/cargo.eclass
index 73f0dcad9cd..75e7f0cf388 100644
--- a/eclass/cargo.eclass
+++ b/eclass/cargo.eclass
@@ -136,7 +136,7 @@ cargo_src_compile() {
 cargo_src_install() {
        debug-print-function ${FUNCNAME} "$@"

-       cargo install -j $(makeopts_jobs) --root="${D}/usr" $(usex debug --debug "") "$@" \
+       cargo install --target=armv7-unknown-linux-gnueabihf -j $(makeopts_jobs) --root="${D}/usr" $(usex debug --debug "") "$@" \
                || die "cargo install failed"
        rm -f "${D}/usr/.crates.toml"
stefson commented 5 years ago

lousy ebuild I hacked for rust-std-bin:

https://github.com/stefson/gentoo-extras/blob/master/dev-lang/rust-std/rust-std-1.30.1.ebuild

l29ah commented 4 years ago

Do you plan producing thumb targets for rust-std? Also why haven't you pushed it into ::rust?

stefson commented 4 years ago

how can you not see the thumb code in the ebuild? https://github.com/gentoo/gentoo-rust/blob/master/dev-lang/rust/rust-1.41.0-r666.ebuild#L102

l29ah commented 4 years ago

The ebuild requires you to be on an arm arch or otherwise have arm-none-eabi-gcc to build it. I mean https://github.com/stefson/gentoo-extras/blob/master/dev-lang/rust-std/rust-std-1.41.0.ebuild

stefson commented 4 years ago

You're welcome to use my overlay if you want to, the thumb target is in an extra package named rust-std-neon since I couldn't find a way to make my rust-std ebuild installing both armv7 and thumbv7neon on an amd64 host. You'll need both of them for cross compiling firefox.

Actually I don't think you'll need arm-none-eabi-gcc for compiling the thumbv7neon target. Where did you get that information from?

l29ah commented 4 years ago

On Thu, Feb 27, 2020 at 01:03:08PM -0800, stefson wrote:

You're welcome to use my overlay if you want to, the thumb target is in an extra package named rust-std-neon since I couldn't find a way to make my rust-std ebuild installing both armv7 and thumbv7neon on an amd64 host. You'll need both of them for cross compiling firefox.

My question was why isn't it in ::rust.

Actually I don't think you'll need arm-none-eabi-gcc for compiling the thumbv7neon target. Where did you get that information from?

From trying to build it (in fact thumbv6m-none-eabi, as i need it): couldn't find required command: "arm-none-eabi-gcc"

-- () ascii ribbon campaign - against html mail /\ http://arc.pasp.de/ - against proprietary attachments

stefson commented 4 years ago

bootstrapping additional rust-std from source requires you to have a suitable gcc cross compiler at hand for linking, and yes some of the crates are so stupid to only look for gcc name paterns matching those of debian based distros. You have no choice but to symlink your own cross compiler to the debian name scheme.

That said, please take the ebuild and modify it for your own case. You're not presenting any usefull information to me for helping you with that. Thanks.