Why might linking C libary in build.rs fail when .cargo/config works?

I'm trying to build a project A for Android using cargo-apk. The project uses another crate B which wraps a C API for a C++ static library.

If I add the following to .cargo/config for project A everything runs fine. Adding it to project B doesn't...

rustflags = ["-C", "link-arg=-lc++_static", "-C", "link-arg=-lc++abi"]

If instead I add the following to build.rs in either project, I get runtime errors for missing cxxabi symbols.

println!("cargo:rustc-link-lib=c++_static");
println!("cargo:rustc-link-lib=c++abi");

... and the following a compile time link error...

println!("cargo:rustc-link-lib=static=c++_static");
println!("cargo:rustc-link-lib=static=c++abi");

As far as I can tell these lines should do the same thing, so I'm at a loss as to what the issue might be. Ideally I would like linking to work in crate B so that I know that distributing crate A won't cause the same linker issues for others. My best guess is it's a quirk of cargo-apk (relevant code?), but I'm not sure I'd know the issue if I saw it.

Aside: for the curious, A is bevy, B is a rewrite of glsl-to-spirv known to work on desktop.

The problem was that link order mattered in build.rs.

Specifying all println!("cargo:rustc-link-lib=...") dependents before the println!("cargo:rustc-link-lib=c++_shared")* dependency resolved the runtime link error when added to crate B.

My best guess as to why is that specifying link arguments in .cargo/config may have coincidentally ordered linking, but I did not dive in to verify.

*note using the shared c++ standard library.

2 Likes

As a bonus, anyone encountering linking errors for Android will probably run across a missing symbol containing "cxxabi" and run across old documentation that links libc++abi, and conclude that resolves the issue. In my case, that did fix it for some weird cases, but was no longer necessary when I corrected the link order in build.rs. For android, it seems linking c++_static or c++_shared is sufficient. Note shared must be bundled into the apk, which cargo-apk does when it sees a dependency on c++_shared.