Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

rust: enable build on LLVM-only systems #304

Closed
wants to merge 1 commit into from

Conversation

konimex
Copy link
Contributor

@konimex konimex commented Jul 30, 2021

Since this is one hell of a hack (i.e. worse than the last patches I sent related to these things), I decided to wait until 1.54.0 since rust-lang/rust#84124 finally landed (and in kiss-llvm and Wyverkiss, rust is now patch-less).

Anyway, the most obvious things, of course, is setting llvm-libunwind = "system" since the default is no for dynamic linking to libgcc_s.so (and we don't have libgcc_s.so).

The ugly part of this patch is, of course, the libgcc_s.so hacks for LLVM-only systems. Since the bootstrap binary looks for libgcc_s.so.1 (and therefore, dynamically linked), we need to work around this by fooling it using the good old $LD_LIBRARY_PATH. We also need to fool some parts since it looks for -lgcc_s, so we also add libgcc_s.so which only contains INPUT(-lunwind) so that -lgcc_s is more or less "aliased" to -lunwind and use $LIBRARY_PATH to fool $CC. (Surprisingly, the two unwinding functions between GCC and LLVM libunwind are compatible, though I can't say if this is an ABI compatibility or not).

Comment on lines +76 to +88
# Since libgcc_s.so is needed for Rust's own bootstrap binary, and
# it's dynamically linked, we'll have to add two files, libgcc_s.so.1
# for the symlink, and libgcc_s.so so the linker points to libunwind.
case $("$CC" -print-file-name=libunwind.so) in */*)
mkdir -p libgcc
ln -sf /usr/lib/libunwind.so.1 libgcc/libgcc_s.so.1
cat > libgcc/libgcc_s.so <<EOF
INPUT(-lunwind)
EOF
export LD_LIBRARY_PATH="$PWD/libgcc:$LD_LIBRARY_PATH"
export LIBRARY_PATH="$PWD/libgcc:$LIBRARY_PATH"
esac

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is upstream doing anything about this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I know of. But I think they should've statically compiled the bootstrap binary instead of making it dynamically linked. Also, it's ugly so I understand if this ended up not being merged.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They can't statically compile it because proc_macro doesn't support static linking or at least that's what the upstream rust people said when I bought up the idea. I can say that libunwind.so is mostly ABI compatible on x86_64 systems, on aarch64 and others the rust binary requires symbols such as __clear_cache which are provided by compiler-rt. I solved this with the below command:

clang -shared -o build/libgcc_s.so.1 \
-Wl,--allow-multiple-definition -Wl,--whole-archive \
$(clang -print-libgcc-file-name) -lunwind

Copy link
Contributor Author

@konimex konimex Aug 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try this later on my build file. Thanks!

@dylanaraps
Copy link
Member

Does this work @konimex ?

diff --git a/extra/rust/build b/extra/rust/build
index edfbd012..3de1aad1 100755
--- a/extra/rust/build
+++ b/extra/rust/build
@@ -49,6 +49,10 @@ full-bootstrap = false
 [install]
 prefix = "/usr"
 
+[target.x86_64-unknown-linux-musl]
+llvm-config = "/usr/bin/llvm-config"
+crt-static  = false
+
 [rust]
 channel           = "stable"
 rpath             = false
@@ -59,12 +63,30 @@ jemalloc          = false
 debug-assertions  = false
 codegen-tests     = false
 codegen-units-std = 1
-
-[target.x86_64-unknown-linux-musl]
-llvm-config = "/usr/bin/llvm-config"
-crt-static  = false
 EOF
 
+# Workaround to get Rust to build in llvm-only environments.
+case $("$CC" -print-file-name=libunwind.so) in */*)
+    printf 'llvm-libunwind = "system"\n' >> config.toml
+
+    # libgcc_s.so is needed for Rust's bootstrap binaries, on llvm-only systems
+    # this library does not exist. This hack creates it as alias to libunwind.
+    {
+        mkdir -p libgcc
+
+        printf 'INPUT(-lunwind)\n' > \
+            libgcc/libgcc_s.so
+
+        ln -sf "$KISS_ROOT/usr/lib/libunwind.so.1" \
+            libgcc/libgcc_s.so.1
+
+        export \
+            LD_LIBRARY_PATH="$PWD/libgcc:$LD_LIBRARY_PATH" \
+            LIBRARY_PATH="$PWD/libgcc:$LIBRARY_PATH"
+    }
+esac
+
+
 python3 ./x.py build -j "$(nproc)"
 python3 ./x.py install

@dylanaraps
Copy link
Member

Also, could something like patchelf be used to do this (replace libgcc_s with libunwind)?

@konimex
Copy link
Contributor Author

konimex commented Aug 16, 2021

The patch works from my end.

Regarding patchelf, theoretically patchelf --replace-needed liboriginal.so.1 libreplacement.so.1 build/x86_64-unknown-linux-musl/stage0/bin/{cargo,rustc,rustdoc} (and build/x86_64-unknown-linux-musl/stage0/lib/lib{std,rustc_driver,test}-*.so) should work. However, our current build file only extracts the bootstrap binaries when ./x.py build is invoked, therefore we'll need to extract them first so it'll work (that's if they don't overwrite the files when we invoke ./x.py build), also it only plugs one side, on the bootstrap bin needing libgcc_s.so.1, but -lgcc_s will still be called when we actually build it, so the INPUT(-lunwind) linker script and LIBRARY_PATH env will still be needed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants