windows-gnullvm: Avoid linking to libunwind statically - #121794
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
|
Failed to set assignee to
|
|
These commits modify compiler targets. |
This comment has been minimized.
This comment has been minimized.
71a9b1b to
ba888f8
Compare
This comment has been minimized.
This comment has been minimized.
ba888f8 to
5b24cc1
Compare
|
I don't see how rust/library/unwind/src/lib.rs Lines 52 to 54 in 878c8a2 I'll test it during the weekend. Also I think it might be the best to just build the unwinder during Rust build and always link it statically like here: rust/library/unwind/src/lib.rs Line 49 in 878c8a2 |
Avoid linking against the static variant of libunwind, which is not always available. Instead, prefer to use the unwind library from the toolchain, which the linker will automatically include, depending on what's available.
5b24cc1 to
7af0f34
Compare
|
Ah, you're right, it looks like that only applies to Linux and Fuchsia targets. rust/library/unwind/Cargo.toml Lines 31 to 34 in 6cbf092 I just clarified my commit message. FWIW, here's a Dockerfile to reproduce this: Details# Build with:
# docker build -t llvm-mingw .
FROM docker.io/mstorsjo/llvm-mingw:latest
# Supported architectures: x86_64, i686, aarch64 and armv7
ARG ARCH=x86_64
# Path settings
ENV RUSTUP_HOME="/usr/local/rustup" \
CARGO_HOME="/usr/local/cargo" \
PATH="/usr/local/cargo/bin:$PATH"
# Install curl
RUN apt-get update -qq && \
apt-get install -qqy --no-install-recommends curl && \
apt-get clean -y && \
rm -rf /var/lib/apt/lists/*
# Install Rust
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y \
--no-modify-path \
--profile minimal \
--target $ARCH-pc-windows-gnullvm \
--default-toolchain nightly \
--component rust-src
WORKDIR /build
# Special flags for Rust
ENV CARGO_PROFILE_RELEASE_DEBUG=false \
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 \
CARGO_PROFILE_RELEASE_INCREMENTAL=false \
CARGO_PROFILE_RELEASE_LTO=true \
CARGO_PROFILE_RELEASE_OPT_LEVEL=z \
CARGO_PROFILE_RELEASE_PANIC=abort
RUN rm /opt/llvm-mingw/$ARCH-w64-mingw32/lib/libunwind.a
RUN cargo new foo --lib --vcs none && \
cd foo && \
echo "pub fn foo() {}" > src/lib.rs && \
cargo rustc --release --crate-type=cdylib --target=$ARCH-pc-windows-gnullvm -Zbuild-std=std,panic_abort && \
llvm-readobj --coff-imports target/$ARCH-pc-windows-gnullvm/release/foo.dll |
|
Not my area of expertise |
|
r? @petrochenkov |
|
The problem linking dynamic libunwind is the need of shipping libunwind together with the library/binary. I'll try if I can get |
|
Ah, I see. LLVM just uses If you pass |
|
Opened #122003 that builds libunwind for these targets so we become independent of host toolchain when it comes to libunwind. Did some testing during Sunday and it seems to work fine but I'll try it with your Dockerfile using toolchain built the official way. |
…try> Build libunwind for pc-windows-gnullvm Alternative to rust-lang#121794 The changes in this PR: - build libunwind for `pc-windows-gnullvm` targets - join paths with `join()` instead of slashes to avoid mixing slashes on windows, this changes it them from `"H:\\projects\\rust\\src/llvm-project/libunwind\\include"` to `"H:\\projects\\rust\\src\\llvm-project\\libunwind\\include"` - include `libunwind/src`, some of the includes are located inside `src` and without this change the build fails with: ``` running: "h:/msys64/clang64/bin/clang++.exe" "-O3" "-ffunction-sections" "-fdata-sections" "--target=x86_64-pc-windows-gnullvm" "-I" "H:\\projects\\rust\\src\\llvm-project\\libunwind\\include" "-nostdinc++" "-fno-exceptions" "-fno-rtti" "-fstrict-aliasing" "-funwind-tables" "-fvisibility=hidden" "-fvisibility-global-new-delete-hidden" "-D_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS" "-D_LIBUNWIND_HIDE_SYMBOLS=1" "-D_LIBUNWIND_IS_NATIVE_ONLY=1" "-o" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnullvm\\native\\libunwind\\Unwind-EHABI.o" "-c" "\\\\?\\H:\\projects\\rust\\src\\llvm-project\\libunwind\\src\\Unwind-EHABI.cpp" cargo:warning=\\?\H:\projects\rust\src\llvm-project\libunwind\src\Unwind-EHABI.cpp:12:10: fatal error: 'Unwind-EHABI.h' file not found cargo:warning= 12 | #include "Unwind-EHABI.h" cargo:warning= | ^~~~~~~~~~~~~~~~ cargo:warning=1 error generated. exit code: 1 ```
…=petrochenkov link libunwind dynamically and allow controlling it via `crt-static` on gnullvm targets Alternative to rust-lang#121794 ``` $ cargo b -r Finished `release` profile [optimized] target(s) in 0.38s $ ntldd target/release/hello.exe | rg unwind libunwind.dll => H:\msys64\clang64\bin\libunwind.dll (0x0000020c35df0000) $ RUSTFLAGS="-C target-feature=+crt-static" cargo b -r Finished `release` profile [optimized] target(s) in 0.23s $ ntldd target/release/hello.exe | rg unwind ```
…=petrochenkov link libunwind dynamically and allow controlling it via `crt-static` on gnullvm targets Alternative to rust-lang#121794 ``` $ cargo b -r Finished `release` profile [optimized] target(s) in 0.38s $ ntldd target/release/hello.exe | rg unwind libunwind.dll => H:\msys64\clang64\bin\libunwind.dll (0x0000020c35df0000) $ RUSTFLAGS="-C target-feature=+crt-static" cargo b -r Finished `release` profile [optimized] target(s) in 0.23s $ ntldd target/release/hello.exe | rg unwind ```
…=petrochenkov link libunwind dynamically and allow controlling it via `crt-static` on gnullvm targets Alternative to rust-lang#121794 ``` $ cargo b -r Finished `release` profile [optimized] target(s) in 0.38s $ ntldd target/release/hello.exe | rg unwind libunwind.dll => H:\msys64\clang64\bin\libunwind.dll (0x0000020c35df0000) $ RUSTFLAGS="-C target-feature=+crt-static" cargo b -r Finished `release` profile [optimized] target(s) in 0.23s $ ntldd target/release/hello.exe | rg unwind ```
Rollup merge of rust-lang#122003 - mati865:gnullvm-build-libunwind, r=petrochenkov link libunwind dynamically and allow controlling it via `crt-static` on gnullvm targets Alternative to rust-lang#121794 ``` $ cargo b -r Finished `release` profile [optimized] target(s) in 0.38s $ ntldd target/release/hello.exe | rg unwind libunwind.dll => H:\msys64\clang64\bin\libunwind.dll (0x0000020c35df0000) $ RUSTFLAGS="-C target-feature=+crt-static" cargo b -r Finished `release` profile [optimized] target(s) in 0.23s $ ntldd target/release/hello.exe | rg unwind ```
…=petrochenkov link libunwind dynamically and allow controlling it via `crt-static` on gnullvm targets Alternative to rust-lang#121794 ``` $ cargo b -r Finished `release` profile [optimized] target(s) in 0.38s $ ntldd target/release/hello.exe | rg unwind libunwind.dll => H:\msys64\clang64\bin\libunwind.dll (0x0000020c35df0000) $ RUSTFLAGS="-C target-feature=+crt-static" cargo b -r Finished `release` profile [optimized] target(s) in 0.23s $ ntldd target/release/hello.exe | rg unwind ```
…r=petrochenkov
windows-gnullvm: always link libunwind statically
Previously shared library was used by default, meaning that programs and libraries couldn't be loaded if `libunwind.dll` was missing from the PATH. Using Wine (on Linux) because it better shows the problem (and is more convenient):
```
❯ cargo new hello &> /dev/null
❯ cargo rustc --target x86_64-pc-windows-gnullvm &> /dev/null
❯ wine target/x86_64-pc-windows-gnullvm/debug/hello.exe
0024:err:module:import_dll Library libunwind.dll (which is needed by L"Z:\\tmp\\hello\\target\\x86_64-pc-windows-gnullvm\\debug\\hello.exe") not found
0024:err:module:loader_init Importing dlls for L"Z:\\tmp\\hello\\target\\x86_64-pc-windows-gnullvm\\debug\\hello.exe" failed, status c0000135
❯ llvm-readobj --coff-imports target/x86_64-pc-windows-gnullvm/debug/hello.exe
...
Import {
Name: libunwind.dll
ImportLookupTableRVA: 0x3D308
ImportAddressTableRVA: 0x3D678
Symbol: _GCC_specific_handler (0)
Symbol: _Unwind_DeleteException (0)
Symbol: _Unwind_GetDataRelBase (0)
Symbol: _Unwind_GetIPInfo (0)
Symbol: _Unwind_GetLanguageSpecificData (0)
Symbol: _Unwind_GetRegionStart (0)
Symbol: _Unwind_GetTextRelBase (0)
Symbol: _Unwind_RaiseException (0)
Symbol: _Unwind_Resume (0)
Symbol: _Unwind_SetGR (0)
Symbol: _Unwind_SetIP (0)
}
...
```
Optionally libunwind could be linked statically via `+crt-static`:
```
❯ cargo rustc --target x86_64-pc-windows-gnullvm -- -C target-feature=+crt-static &> /dev/null
❯ wine target/x86_64-pc-windows-gnullvm/debug/hello.exe
Hello, world!
❯ llvm-readobj --coff-imports target/x86_64-pc-windows-gnullvm/debug/hello.exe | rg 'libunwind.dll' || echo "doesn't depend on shared libunwind"
doesn't depend on shared libunwind
```
After a discussion of approach in rust-lang#159782 with @bjorn3 (thanks BTW!), I changed the proposed approach to always link static libunwind.
I don't have a good solution for rust-lang#121794 that will resurface. I guess the user has three options:
- symlink `libunwind.dll.a` as `libunwind.a`
- add `--unwindlib=none -lunwind` to the linker args
- create linker wrapper
- use self-contained mode which is likely is undesirable
I think the ease of use (not having to deal with additional DLL dependency) outweights the benefit of working with incomplete C toolchain.
The size bloat is also not a problem, sizes (in bytes) of the binary for the literal hello world project:
- debug build:
- shared libunwind 4194816
- static libunwind 4323328
- release build:
- shared libunwind 382464
- static libunwind 423424
Debug diff +125.5 KiB, release diff: +40 KiB.
Size of `libunwind.dll` that has to be provided when linking shared libunwind: 204288 bytes (199.5 KiB).
…r=petrochenkov
windows-gnullvm: always link libunwind statically
Previously shared library was used by default, meaning that programs and libraries couldn't be loaded if `libunwind.dll` was missing from the PATH. Using Wine (on Linux) because it better shows the problem (and is more convenient):
```
❯ cargo new hello &> /dev/null
❯ cargo rustc --target x86_64-pc-windows-gnullvm &> /dev/null
❯ wine target/x86_64-pc-windows-gnullvm/debug/hello.exe
0024:err:module:import_dll Library libunwind.dll (which is needed by L"Z:\\tmp\\hello\\target\\x86_64-pc-windows-gnullvm\\debug\\hello.exe") not found
0024:err:module:loader_init Importing dlls for L"Z:\\tmp\\hello\\target\\x86_64-pc-windows-gnullvm\\debug\\hello.exe" failed, status c0000135
❯ llvm-readobj --coff-imports target/x86_64-pc-windows-gnullvm/debug/hello.exe
...
Import {
Name: libunwind.dll
ImportLookupTableRVA: 0x3D308
ImportAddressTableRVA: 0x3D678
Symbol: _GCC_specific_handler (0)
Symbol: _Unwind_DeleteException (0)
Symbol: _Unwind_GetDataRelBase (0)
Symbol: _Unwind_GetIPInfo (0)
Symbol: _Unwind_GetLanguageSpecificData (0)
Symbol: _Unwind_GetRegionStart (0)
Symbol: _Unwind_GetTextRelBase (0)
Symbol: _Unwind_RaiseException (0)
Symbol: _Unwind_Resume (0)
Symbol: _Unwind_SetGR (0)
Symbol: _Unwind_SetIP (0)
}
...
```
Optionally libunwind could be linked statically via `+crt-static`:
```
❯ cargo rustc --target x86_64-pc-windows-gnullvm -- -C target-feature=+crt-static &> /dev/null
❯ wine target/x86_64-pc-windows-gnullvm/debug/hello.exe
Hello, world!
❯ llvm-readobj --coff-imports target/x86_64-pc-windows-gnullvm/debug/hello.exe | rg 'libunwind.dll' || echo "doesn't depend on shared libunwind"
doesn't depend on shared libunwind
```
After a discussion of approach in rust-lang#159782 with @bjorn3 (thanks BTW!), I changed the proposed approach to always link static libunwind.
I don't have a good solution for rust-lang#121794 that will resurface. I guess the user has three options:
- symlink `libunwind.dll.a` as `libunwind.a`
- add `--unwindlib=none -lunwind` to the linker args
- create linker wrapper
- use self-contained mode which is likely is undesirable
I think the ease of use (not having to deal with additional DLL dependency) outweights the benefit of working with incomplete C toolchain.
The size bloat is also not a problem, sizes (in bytes) of the binary for the literal hello world project:
- debug build:
- shared libunwind 4194816
- static libunwind 4323328
- release build:
- shared libunwind 382464
- static libunwind 423424
Debug diff +125.5 KiB, release diff: +40 KiB.
Size of `libunwind.dll` that has to be provided when linking shared libunwind: 204288 bytes (199.5 KiB).
Rollup merge of #160712 - mati865:gnullvm-static-libunwind, r=petrochenkov windows-gnullvm: always link libunwind statically Previously shared library was used by default, meaning that programs and libraries couldn't be loaded if `libunwind.dll` was missing from the PATH. Using Wine (on Linux) because it better shows the problem (and is more convenient): ``` ❯ cargo new hello &> /dev/null ❯ cargo rustc --target x86_64-pc-windows-gnullvm &> /dev/null ❯ wine target/x86_64-pc-windows-gnullvm/debug/hello.exe 0024:err:module:import_dll Library libunwind.dll (which is needed by L"Z:\\tmp\\hello\\target\\x86_64-pc-windows-gnullvm\\debug\\hello.exe") not found 0024:err:module:loader_init Importing dlls for L"Z:\\tmp\\hello\\target\\x86_64-pc-windows-gnullvm\\debug\\hello.exe" failed, status c0000135 ❯ llvm-readobj --coff-imports target/x86_64-pc-windows-gnullvm/debug/hello.exe ... Import { Name: libunwind.dll ImportLookupTableRVA: 0x3D308 ImportAddressTableRVA: 0x3D678 Symbol: _GCC_specific_handler (0) Symbol: _Unwind_DeleteException (0) Symbol: _Unwind_GetDataRelBase (0) Symbol: _Unwind_GetIPInfo (0) Symbol: _Unwind_GetLanguageSpecificData (0) Symbol: _Unwind_GetRegionStart (0) Symbol: _Unwind_GetTextRelBase (0) Symbol: _Unwind_RaiseException (0) Symbol: _Unwind_Resume (0) Symbol: _Unwind_SetGR (0) Symbol: _Unwind_SetIP (0) } ... ``` Optionally libunwind could be linked statically via `+crt-static`: ``` ❯ cargo rustc --target x86_64-pc-windows-gnullvm -- -C target-feature=+crt-static &> /dev/null ❯ wine target/x86_64-pc-windows-gnullvm/debug/hello.exe Hello, world! ❯ llvm-readobj --coff-imports target/x86_64-pc-windows-gnullvm/debug/hello.exe | rg 'libunwind.dll' || echo "doesn't depend on shared libunwind" doesn't depend on shared libunwind ``` After a discussion of approach in #159782 with @bjorn3 (thanks BTW!), I changed the proposed approach to always link static libunwind. I don't have a good solution for #121794 that will resurface. I guess the user has three options: - symlink `libunwind.dll.a` as `libunwind.a` - add `--unwindlib=none -lunwind` to the linker args - create linker wrapper - use self-contained mode which is likely is undesirable I think the ease of use (not having to deal with additional DLL dependency) outweights the benefit of working with incomplete C toolchain. The size bloat is also not a problem, sizes (in bytes) of the binary for the literal hello world project: - debug build: - shared libunwind 4194816 - static libunwind 4323328 - release build: - shared libunwind 382464 - static libunwind 423424 Debug diff +125.5 KiB, release diff: +40 KiB. Size of `libunwind.dll` that has to be provided when linking shared libunwind: 204288 bytes (199.5 KiB).
Avoid linking against the static variant of libunwind, which is not always available. Instead, prefer to use the unwind library from the toolchain, which the linker will automatically include, depending on what's available.