Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 680652 - sys-devel/crossdev: handle LLVM, Clang, and Rust
Summary: sys-devel/crossdev: handle LLVM, Clang, and Rust
Status: CONFIRMED
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: Current packages (show other bugs)
Hardware: All Linux
: Normal normal with 3 votes (vote)
Assignee: Gentoo Crossdev team
URL:
Whiteboard:
Keywords:
Depends on: 747760
Blocks:
  Show dependency tree
 
Reported: 2019-03-17 09:04 UTC by James Le Cuirot
Modified: 2021-11-06 04:42 UTC (History)
9 users (show)

See Also:
Package list:
Runtime testing required: ---


Attachments
Patch against dev-lang/rust ebuild to add armv7 std crates (rust-std-armv7.patch,1.72 KB, patch)
2019-03-17 10:24 UTC, James Le Cuirot
Details | Diff
patch against the cargo2.eclass (cargo2-cross.patch,2.84 KB, patch)
2019-03-18 12:09 UTC, tt_1
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description James Le Cuirot gentoo-dev 2019-03-17 09:04:28 UTC
I've been trying to cross-compile Firefox today and have it mostly working. The USE flags for LLVM, Clang, and Rust are not enforced though, which is annoying, and Rust is also missing the cross-compiled crates.

I've been thinking about how crossdev could help out here. It's different to the GNU toolchain as all targets are handled by a single installation of each.

I'm thinking that the LLVM_TARGETS flags could simply be handled by a mapping that's used to add to the package.use file. For example:

case ${CTARGET} in
arm*) LLVM_FLAG=ARM ;;
aarch64*) LLVM_FLAG=AArch64 ;;
...
esac

/etc/portage/package.use/cross-${CTARGET}:
dev-lang/rust ${LLVM_FLAG}
sys-devel/clang ${LLVM_FLAG}
sys-devel/llvm ${LLVM_FLAG}

That's the easy part. For the Rust crates, tt_1 sent me a patch against the ebuild that adds a rust-std-armv7 USE flag for a specific CTARGET but that's not flexible or scalable. I was thinking of building up a variable, possibly an array, of targets via /etc/portage/env but however I do it, I get syntax errors because it's not simply FOO=bar. You can put functions in these files but I don't know if that helps. Any ideas?

I have attached tt_1's patch so you can see roughly what is involved. This link may also be helpful. It implies that we could perhaps do the crates as separate packages?

https://github.com/japaric/rust-cross#cross-compiling-the-standard-crates

There's the question of crates outside std but I guess those would just live in SYSROOT like other libraries do. I'm not even sure if we have packaged any? There's no dev-rust category.
Comment 1 Sergei Trofimovich (RETIRED) gentoo-dev 2019-03-17 09:34:06 UTC
(In reply to James Le Cuirot from comment #0)

> I'm thinking that the LLVM_TARGETS flags could simply be handled by a
> mapping that's used to add to the package.use file. For example:
> 
> case ${CTARGET} in
> arm*) LLVM_FLAG=ARM ;;
> aarch64*) LLVM_FLAG=AArch64 ;;
> ...
> esac

Similar mapping is defined in multilib.eclass:multilib_env(). crossdev uses that to not embed most basic information about targets. You can do something similar.

> /etc/portage/package.use/cross-${CTARGET}:
> dev-lang/rust ${LLVM_FLAG}
> sys-devel/clang ${LLVM_FLAG}
> sys-devel/llvm ${LLVM_FLAG}

cross-${CTARGET} file normally contains bits only for cross-*/* packages. They try hard not to influence host's install: don't need host USE-flag or variable tweaks. Everything is self-contained in cross-*/* and ${SYSROOT}.

Affecting host's install sounds fragile. But whatever works for you.

I would suggest pkg_pretend() code in every rust package that would bail out if ${CHOST} requires some USE-flag from ${CBUILD}'s llvm and a clear message for user how they should change LLVM_TARGETS.

Then you would not need special crossdev support at all.

> That's the easy part. For the Rust crates, tt_1 sent me a patch against the
> ebuild that adds a rust-std-armv7 USE flag for a specific CTARGET but that's
> not flexible or scalable. I was thinking of building up a variable, possibly
> an array, of targets via /etc/portage/env but however I do it, I get syntax
> errors because it's not simply FOO=bar. You can put functions in these files
> but I don't know if that helps. Any ideas?
> 
> I have attached tt_1's patch so you can see roughly what is involved. This
> link may also be helpful.

I don't see a patch. Thus I don't really understand the mechanical problems of the above.

> It implies that we could perhaps do the crates as
> separate packages?
> 
> https://github.com/japaric/rust-cross#cross-compiling-the-standard-crates
> 
> There's the question of crates outside std but I guess those would just live
> in SYSROOT like other libraries do. I'm not even sure if we have packaged
> any? There's no dev-rust category.

For each end-user tool cargo.eclass packages every source crate dependency needed to build a tool standalone (effectively bypassing gentoo's package management). That could simplify cross-compilation if rust already knows how to build some of them for ${CBUILD} and some of them for ${CHOST}.
Comment 2 James Le Cuirot gentoo-dev 2019-03-17 10:24:55 UTC
Created attachment 569462 [details, diff]
Patch against dev-lang/rust ebuild to add armv7 std crates

Sorry, the patch upload messed up.
Comment 3 Sergei Trofimovich (RETIRED) gentoo-dev 2019-03-17 11:14:32 UTC
(In reply to James Le Cuirot from comment #2)
> Created attachment 569462 [details, diff] [details, diff]
> Patch against dev-lang/rust ebuild to add armv7 std crates

> --- a/dev-lang/rust/rust-1.32.0.ebuild
> +++ b/dev-lang/rust/rust-1.32.0.ebuild
> -IUSE="clippy cpu_flags_x86_sse2 debug doc libressl rls rustfmt system-llvm wasm ${ALL_LLVM_TARGETS[*]}"
> +IUSE="clippy cpu_flags_x86_sse2 debug doc libressl rls rustfmt rust-std-armv7 system-llvm wasm ${ALL_LLVM_TARGETS[*]}"
> ...
> @@ -126,6 +126,10 @@ src_configure() {
> ...
> +	if use rust-std-armv7; then
> +		rust_targets="${rust_targets},\"armv7-unknown-linux-gnueabihf\""
> +	fi
> ...
> +	if use rust-std-armv7; then
> +		cat <<- EOF >> "${S}"/config.toml
> +			[target.armv7-unknown-linux-gnueabihf]
> +			cc = "armv7a-unknown-linux-gnueabihf-gcc"
> +			cxx = "armv7a-unknown-linux-gnueabihf-g++"
> +			linker = "armv7a-unknown-linux-gnueabihf-gcc"
> +			ar = "armv7a-unknown-linux-gnueabihf-ar"
> +			llvm-config = "/usr/armv7a-unknown-linux-gnueabihf/usr/lib/llvm/7/bin/llvm-config"
> +		EOF
> +	fi
> }

You would need to decide on the flexibility of cross toolchains you want.
For example gentoo's gcc allows you to:
1. have multiple equivalent cross-toolchains:
  - x86_64-HEAD-linux-gnu
  - x86_64-pc-linux-gnu
2. Not couple cross-toolchain package versions with native package versions:
  - x86_64-pc-linux-gnu-gcc-8.3.0 with sanitizer enabled
  - x86_64-HEAD-linux-gnu-gcc-8.3.0-r1 with sanitizer disabled
  (also allows passing different CFLAGS/CXXFLAGS from default install)
3. cross-libc can have a different version.

If you want to follow similar flexibility you might end up needing a similar extra package:
    cross-${CTARGET}/rust (symlink to dev-lang/rust)
and install / DEPEND on what is missing.

If you don't need all that complexity/flexibility you could do static LLVM_TARGET->${CTARGET} mapping. I think you could even avoid most of gcc toolchain and use clang for C stuff:
    cc = "clang -<tuple arg?>"
    linker = "clang -<tuple arg?>"

Don't know if rust needs libc for basic setup to work. If rust does not libc you could avoid fiddling with crossdev completely and have LLVM_TARGET define everything for you.
Comment 4 James Le Cuirot gentoo-dev 2019-03-17 11:21:51 UTC
(In reply to Sergei Trofimovich from comment #1)
> Similar mapping is defined in multilib.eclass:multilib_env(). crossdev uses
> that to not embed most basic information about targets. You can do something
> similar.

Handy!

> cross-${CTARGET} file normally contains bits only for cross-*/* packages.
> They try hard not to influence host's install: don't need host USE-flag or
> variable tweaks. Everything is self-contained in cross-*/* and ${SYSROOT}.
> 
> Affecting host's install sounds fragile. But whatever works for you.
> 
> I would suggest pkg_pretend() code in every rust package that would bail out
> if ${CHOST} requires some USE-flag from ${CBUILD}'s llvm and a clear message
> for user how they should change LLVM_TARGETS.
> 
> Then you would not need special crossdev support at all.

I thought that the existing approach was more because the GNU toolchains have to be built separately. Whether we use package.use or pkg_pretend, the host's install is going to be affected regardless. The pkg_pretend approach requires more manual effort by the user so I felt it was a poor last resort. Not everyone will need this so it could be done through one of the "extra fun" crossdev options.

> For each end-user tool cargo.eclass packages every source crate dependency
> needed to build a tool standalone (effectively bypassing gentoo's package
> management). That could simplify cross-compilation if rust already knows how
> to build some of them for ${CBUILD} and some of them for ${CHOST}.

Knowing how Rust likes to statically link everything, that's what I guessed.
Comment 5 tt_1 2019-03-18 12:03:52 UTC
Not sure wether I can give some helfpull insight here, but I'll try nonetheless. 

When I first thought about this I wanted to cross-compile dev-lang/rust itself with the help of the cross-toolchain provided by crossdev+wrappers. Making this work is a mountain to climb, so I went for the approach to build a fitting rust-std instead. 

The patch I hacked together in #2 is a proof of concept, it lacks a few things such as stripping the foreign rust-std libraries with cross-binutils, but it does the job of providing dev-lang/rust with the ability to cross-compile. Given that there is a cross-gcc available, since rustc needs it for linking. 

The www-client/firefox ebuild can detect and use it for its compilation, which is what I had intended. 

So, given that users can think for themselves, I'd say to enable the ability to cross-emerge firefox/thunderbird it is sufficent to add a rust-std{-bin} ebuild to the tree, which is where going for different CHOSTS could be mapped to different LLVM_FLAGS. Which could be painfull on its own, so maybe even with a new use_extend of RUST_STD?
Comment 6 tt_1 2019-03-18 12:04:37 UTC
If the ebuild in question of cross-compilation does inherit cargo2.eclass, it needs some additional work. Cargo wants to be informed about the linker on a per target base, and it tries to find this in ~/.cargo/config.

Which works fine, unless you're using portage. The cargo2.eclass takes care of exporting all values to a local folder within the temp or work folder I believe, and probes here instead of at ~/.cargo; which works around user settings needed. 

So simply add this to cargo_gen_config() 

	[target.${TARGET_RUST_HOST]
	linker = "${TARGET_CHOST}-gcc"

Next cargo build has to be executed with the additional --target=${TARGET_RUST_HOST command, same goes for cargo install. 

This makes it possible to cross-compile with portage, given that there is a cross-compiler present. Stripping with cross-binutils not enabled yet.
Comment 7 tt_1 2019-03-18 12:09:31 UTC
Created attachment 569592 [details, diff]
patch against the cargo2.eclass

this is to demonstrate the problem, not meant for the tree.
Comment 8 tt_1 2019-03-23 15:35:59 UTC
for clang its best practice to use some kind of wrapper. 

at least these three values have to be added to each individual clang command: 

--target
--sysroot
-isysroot

I'll do some more research and post a wrapper once I got it to work.
Comment 9 tt_1 2019-12-13 23:14:44 UTC
here's a working wrapper for cross compiling with clang: 

#!/bin/bash

SYSROOT="/usr/armv7a-unknown-linux-gnueabihf"
TARGET="armv7a-linux-gnueabihf"
COMPILER_PATH="${SYSROOT}/usr/armv7a-unknown-linux-gnueabihf/gcc-bin/9.2.0/"

exec env COMPILER_PATH="${COMPILER_PATH}" \
	clang --target=${TARGET} \
		--sysroot="${SYSROOT}" \
		-isysroot "${SYSROOT}" \
		-L"${COMPILER_PATH}" \
		"$@"



I took libpng an test emerged it, it also passes firefox src_configure, given that it's put into /usr/lib/llvm/x/bin/ and made executeable. 

sys-devel/binutils must have multitarget use flag enabled.
Comment 10 Larry the Git Cow gentoo-dev 2020-06-12 00:31:09 UTC
The bug has been referenced in the following commit(s):

https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=0326022d60e80c438d0ea90f489eebb722320417

commit 0326022d60e80c438d0ea90f489eebb722320417
Author:     Georgy Yakovlev <gyakovlev@gentoo.org>
AuthorDate: 2020-06-11 22:12:30 +0000
Commit:     Georgy Yakovlev <gyakovlev@gentoo.org>
CommitDate: 2020-06-12 00:30:49 +0000

    dev-lang/rust: add experimental cross support to 1.44.0
    
    Brief usage how-to in the ebuild
    Bug: https://bugs.gentoo.org/680652
    Bug: https://bugs.gentoo.org/680652
    Package-Manager: Portage-2.3.100, Repoman-2.3.22
    Signed-off-by: Georgy Yakovlev <gyakovlev@gentoo.org>

 dev-lang/rust/rust-1.44.0.ebuild | 57 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=0326022d60e80c438d0ea90f489eebb722320417

commit 0326022d60e80c438d0ea90f489eebb722320417
Author:     Georgy Yakovlev <gyakovlev@gentoo.org>
AuthorDate: 2020-06-11 22:12:30 +0000
Commit:     Georgy Yakovlev <gyakovlev@gentoo.org>
CommitDate: 2020-06-12 00:30:49 +0000

    dev-lang/rust: add experimental cross support to 1.44.0
    
    Brief usage how-to in the ebuild
    Bug: https://bugs.gentoo.org/680652
    Bug: https://bugs.gentoo.org/680652
    Package-Manager: Portage-2.3.100, Repoman-2.3.22
    Signed-off-by: Georgy Yakovlev <gyakovlev@gentoo.org>

 dev-lang/rust/rust-1.44.0.ebuild | 57 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
Comment 11 Larry the Git Cow gentoo-dev 2020-09-25 07:38:26 UTC
The bug has been referenced in the following commit(s):

https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=e2701fa0f4b3b3a3d971c2274c36b4ea4bce7181

commit e2701fa0f4b3b3a3d971c2274c36b4ea4bce7181
Author:     Georgy Yakovlev <gyakovlev@gentoo.org>
AuthorDate: 2020-09-25 07:26:47 +0000
Commit:     Georgy Yakovlev <gyakovlev@gentoo.org>
CommitDate: 2020-09-25 07:37:58 +0000

    sys-devel/rust-std: new package, for crossdev #679878
    
    EXPERIMENTAL!
    
    Bug: https://bugs.gentoo.org/680652
    Bug: https://bugs.gentoo.org/679878
    Bug: https://bugs.gentoo.org/689336
    Package-Manager: Portage-3.0.8, Repoman-3.0.1
    Signed-off-by: Georgy Yakovlev <gyakovlev@gentoo.org>

 sys-devel/rust-std/Manifest               |   1 +
 sys-devel/rust-std/metadata.xml           |  21 +++++
 sys-devel/rust-std/rust-std-1.46.0.ebuild | 146 ++++++++++++++++++++++++++++++
 3 files changed, 168 insertions(+)
Comment 12 Georgy Yakovlev gentoo-dev 2020-09-25 07:39:28 UTC
# rust-std + crossdev = <3

EXPERIMENTAL! not sure if stage0 stdlib is good enough, but it produces working binaries just fine.

TLDR: (your file paths may differ)

assuming you already have `aarch64-unknown-linux-gnu` toolchain bootstrapped via crossdev.

```bash
cd /var/db/repos/crossdev/cross-aarch64-unknown-linux-gnu
ln -s /var/db/repos/gentoo/sys-devel/rust-std
echo 'cross-aarch64-unknown-linux-gnu/rust-std **' >> /etc/portage/package.accept_keywords/aarch64
emerge cross-aarch64-unknown-linux-gnu/rust-std -av
cd /some/rust/source
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-unknown-linux-gnu-gcc
cargo build --target aarch64-unknown-linux-gnu
```

for crates that link to libstdc++ you may need to add something like this:
`CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-arg=-Wl,-rpath-link,/usr/lib/gcc/aarch64-unknown-linux-gnu/9.3.0"`
More info on that: https://bugs.gentoo.org/549994


## Package if used as cross- will install new stdlib to `/usr/lib64/rust-<ver>/rustlib/aarch64-unknown-linux-gnu`, for example.

currently this method is not as flexible as fully custom target support via rust ebuild itself,
because rust-toolchain.eclass' rust_abi() function needs better triple transformations.
for example it will always transform CHOST x86-64-gentoo-linux-musl to RHOST x86-64-unknown-linux-musl
but it can be fixed, of course. https://bugs.gentoo.org/671736

There's a workaround, ERUST_STD_RTARGET=whatever-weird-rust-triple allows setting any custom one.
that will set `build.target` in `config.toml`

it's very fast, one can get a new target in couple of minutes, instead of waiting for full bootstrap
of dev-lang/rust with RUST_CROSS_TARGETS.

Please provide feedback in https://bugs.gentoo.org/679878
Comment 13 SpanKY gentoo-dev 2021-10-27 08:49:33 UTC
i don't see what value crossdev can add for llvm.  it's a monolithic build and includes dedicated knobs for enabling specific arches.  having crossdev drop flags onto it independent of what already exists feels like overstepping.

Rust also is a monolithic build, but requires the list of tuples at its build time.  so also seems like an issue a bit out of scope for crossdev as the Rust ebuild would figure out how to expose the config to users.

so i'm not sure what the expectation is for this bug.