Rust & LTO: I think I figured out what's wrong #157
Labels
No Label
blocked upstream
bug
build-failure
duplicate
enhancement
help wanted
informational
invalid
invalid/corrupt package
packaging issue
priority: high
question
support
wontfix
No Milestone
No project
No Assignees
4 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: ALHP/ALHP.GO#157
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Background
I use the default v3 makepkg file on my Arch Linux computer for the AUR, in addition to using the ALHP repositories. I noticed that any package containing rust code failed, so in the meantime, I just disabled LTO by removing
-Clto=fat
from theRUSTFLAGS
line. I had some extra time on my hands this weekend, so I decided to debug this.I have an x86-64-v3 CPU on my computer.
Results
Instead of using:
RUSTFLAGS="-Copt-level=3 -Ctarget-cpu=x86-64-v<?> -Clto=fat -Ccodegen-units=1 -Clinker-plugin-lto"
Use:
RUSTFLAGS="-Copt-level=3 -Ctarget-cpu=x86_64-v<?> -Clto=fat -Ccodegen-units=1 -Clinker-plugin-lto=no -Cembed-bitcode=yes"
Process
I used exa from the community repository because it's written entirely in rust, invokes
cargo
(i.e., compiles like a normal rust package) and is officially supported by Arch Linux, so the chances of running into a package-specific issue were much lower. This way, one may verify the configuration.Step 1
Using the default LTO v3 makepkg file directly to build
exa
, one gets this error:The rust documentation notes here that such an error would occur.
Solution: Add
-C embed-bitcode=yes
toRUSTFLAGS
(-C embed-bitcode=no
is the default without this).Step 2
Rebuilding, one gets a lot of errors like this:
This took me a bit to figure out, but the gist is: the
.o
files being made by rust are LLVM bitcode files, which thegcc
linker (by defaultbfd
) doesn't know how to handle. Changing the linker tolld
orclang
didn't seem to work either, howeverclang
andlld
are known to compile more quickly but produce slower binaries, so I'd like to stick togcc
andbfd
,gold
, ormold
as much as possible. Arch Linux and ALHP usebfd
by default, so I see no reason to change that here.Solution: To make
rustc
generate normal object files instead of LLVM bitcode, replaceClinker-plugin-lto
withClinker-plugin-lto=no
inRUSTFLAGS
.Yay! Now
exa
builds, and the binary works!Step 3
I thought that maybe it would be a good idea to try building other packages in the AUR that use rust, just to test. I tested lottieconv, authenticator, and lolcate.
I got this error for all of them:
This is caused by failing to set
--target
while invokingcargo fetch
orcargo b. As far as everything I have seen, all packages in the official Arch Linux repository specify
--target` explicitly, so this shouldn't be an issue.For anyone reading this, one can specify
--target
incargo build
in AUR packages (which may not be specific to one architecture) by harnessing theCHOST
shell variable provided in the defaultmakepkg.conf
. Usecargo build --target ${CHOST//-pc-/-unknown-}
.I'd understand if this bug makes the ALHP devs hesitant to make this change, however it only affects AUR packages, not official ones.
EDIT: You can add
--target ${CHOST//-pc-/-unknown-}
directly to theRUSTFLAGS
variable, but it doesn't seem to fix the bug mentioned above in Step 3.EDIT 2: Adding
CARGO_BUILD_TARGET="${CHOST//-pc-/-unknown-}"
to/etc/makepkg.conf
and then patching/usr/share/makepkg/buildenv.sh
to exportCARGO_BUILD_TARGET
fixes the issue noted in Step 3.Okay, the issue noted in step 3 seems to seriously be an issue with packages building with meson that invoke cargo in the back. This is particularly common among GNOME project stuff. Maybe this isn't such a good idea, but maybe someone has another solution.
@anonfunc According to https://users.rust-lang.org/t/status-of-lto-option/49032/8, we should use
export CARGO_PROFILE_RELEASE_LTO=fat
instead of manually adding-Clto=fat
and-Clinker-plugin-lto
, thereforecargo
can decide whether to use lto. Force enabling lto will make packages that use compile-time code generation fail to be built.@saltedcoffii Thanks for your detailed exploration. ALHP already has detection of those
errors. So we waste only a little bit of buildtime here, and these packages are not build with lto, but that fortunately only affects a few packages. Exporting new envs is currently blocked by #149, so even if we wanted to set a new
CARGO_BUILD_TARGET
, its not possible until that issue is fixed. But I'm not sure that is worth it for the few packages this affects. Have you compared packages that are not affected by this bug with and without your newCARGO_BUILD_TARGET
?@AvianaCruz Do you have any documentation that explicitly states that
CARGO_PROFILE_RELEASE_LTO
lets cargo decide when to use lto? I could not find anything about that, neither on your linked page nor on https://doc.rust-lang.org/cargo/reference/profiles.html.@anonfunc https://doc.rust-lang.org/cargo/reference/environment-variables.html#:~:text=CARGO_PROFILE_%3Cname%3E_LTO
This page also does not state it lets cargo choose which LTO behavior to adopt. It just links to here, where there is also nothing stated, and then to here, where we have the same settings that apply to
-C lto
. As far as I understand, the env is just another way to set lto, but not different to-C lto
.@anonfunc This is the explanation: https://users.rust-lang.org/t/error-lto-can-only-be-run-for-executables-cdylibs-and-static-library-outputs/73369/4
Also the issue: https://github.com/rust-lang/cargo/issues/6375#issuecomment-560124129
(Cargo profile is a stable feature now so that there is no need to add
-Zconfig-profile
.)@anonfunc
cargo
plays as a build tool which generates compiler flags. Rust has a feature that generates code at compile time, and the code which generates code doesn't exists in the final binary, so it can not be linked. Letcargo
deciding lto avoids the problem that tries to link non-exist code to binary.I mean, it certainly won't hurt if it still enables LTO in cases where we have LTO enabled currently. Let's try it out as soon as a fix for #149 is implemented.
@anonfunc "rust" package should not be compiled with x86-64 level targeting flags, because it results in its shipped stdlibs also being compiled with higher x86-64 level.
Therefore every binaries compiled with the rust toolchain will be not compatible with CPU of lower x86-64 level because rust statically linking everything by default, including the stdlib which is shipped with the rust toolchain and not recompiled during the build stages.
@AvianaCruz That's unfortunate. ALHP does not currently feature a dedicated list for the x86-64-vN flag, so we need to backlist it completely then.
@anonfunc
ripgrep
fails to build because of the error:options
-C embed-bitcode=noand
-C ltoare incompatible
too and has apparently been the case since December of last year; I thought you said it detects this...?It should detect these errors, yes. But I'm planing on switching to
CARGO_BUILD_TARGET
soon anyways, which should resolve this issue.Together with the new build-queue (
ece8c4c7d9
)CARGO_BUILD_TARGET
is now also included. We'll see how it goes.It seems to work fine. If there are any suggestions on how to improve it even further, please open a separate issue. Any feedback to
CARGO_BUILD_TARGET
can go in here.