Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bugzilla DB migration completed. Please report issues to Infra team via email via infra@gentoo.org or IRC
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 1 vote (vote)
Assignee: Gentoo Crossdev team
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-03-17 09:04 UTC by James Le Cuirot
Modified: 2020-06-12 02:40 UTC (History)
5 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 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 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(+)