Stream: rust-toolchain

Topic: Build error using build-std on a mac with wasm32-wasi target


view this post on Zulip Geoff Goodman (Mar 13 2024 at 13:31):

Hi folks, in hopes of getting rid of some of the panic machinery in std, I've been referring to the awesome min-sized-rust guide.

The project I'm trying to build uses rquickjs and targets wasm32-wasi.

I'm not at all familiar with the toolchain involved here and find myself quite stumped by this error. I haven't been able to find anything on Google (that I understood) to explain what's going on and how to fix it.

cargo +nightly build -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target wasm32-wasi --release -p quicky-wasm
error: linking with `rust-lld` failed: exit status: 1
  |
  = note: LC_ALL="C" PATH="<REDACTED>" VSLANG="1033" "rust-lld" "-flavor" "wasm" "--rsp-quoting=posix" "--export" "lodash" "--export" "wizer.initialize" "-z" "stack-size=1048576" "--stack-first" "--allow-undefined" "--no-demangle" "<REDACTED>/quicky/target/wasm32-wasi/release/deps/quicky_wasm.quicky_wasm.471d786854812ccd-cgu.0.rcgu.o" "-L" "<REDACTED>/quicky/target/wasm32-wasi/release/deps" "-L" "<REDACTED>/quicky/target/release/deps" "-L" "<REDACTED>/quicky/target/wasm32-wasi/release/build/rquickjs-sys-b4b653f5d54f8d95/out" "-L" "<REDACTED>/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/wasm32-wasi/lib" "/var/folders/cd/x5jxg5sn0ws55pk2ptz8qz9r0000gp/T/rustcSPiY3m/librquickjs_sys-e42df950feb7a650.rlib" "-l" "c" "<REDACTED>/quicky/target/wasm32-wasi/release/deps/libcompiler_builtins-dc1c01caff7cab16.rlib" "-L" "<REDACTED>/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/wasm32-wasi/lib" "-L" "<REDACTED>/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/wasm32-wasi/lib/self-contained" "-o" "<REDACTED>/quicky/target/wasm32-wasi/release/deps/quicky_wasm.wasm" "--gc-sections" "--no-entry" "-O2" "--strip-all"
  = note: rust-lld: error: unable to find library -lc

Does this sort of error look familiar to the experts? Any advice on fixing or diving deeper?

๐Ÿฆ€ How to minimize Rust binary size ๐Ÿ“ฆ. Contribute to johnthagen/min-sized-rust development by creating an account on GitHub.
High level bindings to the quickjs javascript engine - DelSkayn/rquickjs

view this post on Zulip Joel Dice (Mar 13 2024 at 14:07):

I haven't tried this myself, but you might need to install wasi-sdk and then set e.g. RUSTFLAGS="-L /opt/wasi-sdk-sockets/share/wasi-sysroot/lib/wasm32-wasi". I _think_ Rust usually bundles a copy of wasi-sdk as part of the toolchain, but since you're building std from source maybe it's not used? Just guessing here.

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:18):

Joel's right, when using -Zbuild-std with wasi targets you'll need to provide link flags to find the wasi sysroot so wasm-ld can find libc.a. That file is typically distributed at $(rustc --print sysroot)/lib/rustlib/wasm32-wasi/lib/self-contained/libc.a

view this post on Zulip Geoff Goodman (Mar 13 2024 at 14:19):

Interesting, so basically that's because the libc for wasi is totally distinct, right?

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:20):

indeed!

view this post on Zulip Geoff Goodman (Mar 13 2024 at 14:20):

Is it typically distributed as a binary like rust's own std or am I 'already' compiling from source?

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:21):

Yes, when you rustup target add wasm32-wasi it'll download libc.a which is packaged along with libstd-*.rlib

view this post on Zulip Geoff Goodman (Mar 13 2024 at 14:22):

So the same feature flags will work with the wasi-sdk right? And that would be because rust's stdlib is where the flags live and it links against the sysroot libc?

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:22):

The rust feature flags won't have any effect on libc itself, no, but you can compile wasi-sdk/wasi-libc with custom flags

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:23):

You're running into one of the major weaknesses of -Zbuild-std which is that while it can easily compile Rust code it can't compile supporting code for all targets, which for wasi includes wasi-libc

view this post on Zulip Geoff Goodman (Mar 13 2024 at 14:23):

Oh I see; is that one of the outstanding hurdles preventing it from landing in stable?

view this post on Zulip Geoff Goodman (Mar 13 2024 at 14:24):

As someone who (currently) only uses rust for WASM, I kinda wished #[no_std] was the _default_ and you had to opt into (a) libc.

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:25):

I believe so yeah, although I might analogize it to you've got an entire track meet's worth of hurdles in front of you and this is one of them on the road to stabilization

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:25):

It turns out that Rust's wasi suppot in the standard library only relies pretty lightly on libc, so it might be reasonable to remove some integration points on an opt-in basis

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:25):

for example have a build mode that doesn't use wasi-libc

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:26):

although these sorts of situations are also great opportunities to improve wasi-libc as well

view this post on Zulip Geoff Goodman (Mar 13 2024 at 14:27):

Is it possible to supply libc stubs when authoring rust code (in the codebase itself) so that the compiler doesn't implicitly reference them from elsewhere?

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:28):

Technically, yes, you could write a bunch of #[no_mangle] symbols, but that'll be brittle because the surface area libstd uses from wasi-libc isn't guaranteed to be a stable set

view this post on Zulip Geoff Goodman (Mar 13 2024 at 14:32):

So if you define symbols like that, what happens? It prevents the linker from looking for them elsewhere?

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:39):

No you'd get conflicts and linker errors if they were also defined elsewhere

view this post on Zulip Alex Crichton (Mar 13 2024 at 14:39):

otherwise should work ok

view this post on Zulip Geoff Goodman (Mar 14 2024 at 12:55):

In rquickjs' build.rs file, they dynamically pull a copy of the wasi-sdk (https://github.com/DelSkayn/rquickjs/blob/master/sys/build.rs#L13). If I have an alternative copy of the wasi-sdk that I use to build my own lib, how does that work with respect to deduplication in the final binary?

view this post on Zulip Geoff Goodman (Mar 14 2024 at 12:57):

I know for Javy, the team allows a custom wasi sdk via WASI_SDK env var. Is that the sort of approach that would be favoured so that both c and rust code can link against a single wasi libc?

(I'm patching together a loose understanding of how compiling and linking work and might have a fundamentally wrong mental model.)

view this post on Zulip Alex Crichton (Mar 14 2024 at 14:10):

The precise answer I think depends on exactly what the final linker invocation looks like which is tough to predict. You might get symbol conflicts or everything might work out, it all depends. I'd recommend setting WASI_SDK and using that for both quickjs and linking as that's probably the most robust

view this post on Zulip Geoff Goodman (Mar 16 2024 at 02:42):

I've spent some time banging my head against this and feel like I might be in too deep. I've lifted some of the logic from rquickjs (lifted from javy: https://github.com/DelSkayn/rquickjs/blob/master/sys/build.rs#L199). I dumped that in my build.rs and set WASI_SDK to the resulting path.

fn main() {
    if env::var("CARGO_CFG_TARGET_OS").unwrap() == "wasi" {
        let wasi_sdk_path = get_wasi_sdk_path();
        if !wasi_sdk_path.try_exists().unwrap() {
            panic!(
                "wasi-sdk not installed in specified path of {}",
                wasi_sdk_path.display()
            );
        }
        env::set_var("WASI_SDK", wasi_sdk_path.to_str().unwrap());
    }
}

I'm not actually sure if that's 'working'. The idea is that the WASI_SDK env var is understood by rquickjs's own build script. My thinking is that I can then instruct rquickjs and std to use that same instance.

But what I can't get working is how to get rid of the linker paths that seem to be injected by cargo and instead use 'the paths' (not sure which) in this downloaded sdk.

The linker seems to be run link this:

LC_ALL="C" PATH="<REDACTED>" VSLANG="1033" "rust-lld" "-flavor" "wasm" "--rsp-quoting=posix" "--export" "wizer.initialize" "-z" "stack-size=1048576" "--stack-first" "--allow-undefined" "--no-demangle" \
  "$PROJECT_ROOT/js-rs-wasm-bridge/target/wasm32-wasi/release/deps/js_rs_wasm_bridge.js_rs_wasm_bridge.238c6f55f859b731-cgu.0.rcgu.o" \
  "-L" "$PROJECT_ROOT/js-rs-wasm-bridge/target/wasm32-wasi/release/deps" \
  "-L" "$PROJECT_ROOT/js-rs-wasm-bridge/target/release/deps" \
  "-L" "$PROJECT_ROOT/js-rs-wasm-bridge/target/wasm32-wasi/release/build/rquickjs-sys-f16313b4d9f51e5b/out" \
  "-L" "$HOME/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/wasm32-wasi/lib" "/var/folders/zw/14fs16lx58z4xs0t1kkgrls00000gn/T/rustcIK3zuh/librquickjs_sys-4622d9f4f719ba74.rlib" \
  "-l" "c" "$PROJECT_ROOT/js-rs-wasm-bridge/target/wasm32-wasi/release/deps/libcompiler_builtins-5cd41716d77b1ead.rlib" \
  "-L" "$HOME/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/wasm32-wasi/lib" \
  "-L" "$HOME/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/wasm32-wasi/lib/self-contained" \
  "-o" "$PROJECT_ROOT/js-rs-wasm-bridge/target/wasm32-wasi/release/deps/js_rs_wasm_bridge.wasm" "--gc-sections" "--no-entry" "-O2"```

view this post on Zulip Geoff Goodman (Mar 16 2024 at 03:14):

I've discovered that I can inject -L args via cargo:rustc-link-arg but injecting -L ${WASI_SDK}/share/wasi-sysroot/lib/wasm32-wasi hasn't changed the error :(

view this post on Zulip Geoff Goodman (Mar 16 2024 at 03:28):

I got it working with this it seems:

    println!(
        "cargo:rustc-link-search={}",
        wasi_sdk_path
            .join("share/wasi-sysroot/lib/wasm32-wasi")
            .display()
    );

view this post on Zulip Geoff Goodman (Mar 16 2024 at 03:36):

A problem remains that it seems like my lib's build.rs runs well _after_ the rquickjs dependency's build.rs runs. As a result, it seems like I can't interject early enough to set up the SDK for both deps. Maybe I'm misunderstanding linking and we only care about the final linking but not sure..

view this post on Zulip bjorn3 (Mar 16 2024 at 09:37):

You can't set an env var for another build script. env::set_var only affects the current process and it's children and cargo doesn't provide a way to set env vars for other build scripts. You will have to set WASI_SDK when invoking cargo.


Last updated: Nov 26 2024 at 00:12 UTC