[Solved] Static linking for Android x86

Hi guys,

I'm trying to cross compile a library crate called app_backend to target i686-linux-android on a ubuntu host. I've set rustflags = ["-C", "target-feature=+crt-static"] inside my cargo config. The crate compiles fine and generates the .so file. However, when I try to load this .so file from the Java code of my android app I get the following error:

java.lang.UnsatisfiedLinkError: dlopen failed: could not load library "libstd-881292fbd446dc98.so" needed by "libapp_backend.so"; caused by library "libstd-881292fbd446dc98.so" not found

I'm guessing is because libapp_backend.so is dynamically linking to libstd-xxxx.so. In other words crt-static flag seems to have no effect. Any ideas how I can make static linking work in this scenario. I'm very new to android and cross-compiling. So please point out if my understanding is wrong of if there's something else I'm missing.

Thanks in advance :slight_smile:

My ~/.cargo/config file looks like this:

[target.i686-linux-android]
ar = "/home/<username>/<some-path>/NDK/x86/bin/i686-linux-android-ar"
linker = "/home/<username>/<some-path>/NDK/x86/bin/i686-linux-android-clang"
rustflags = ["-C", "target-feature=+crt-static"]

Edit
Maybe my entire mental model is wrong here. What I'm really after here is that I want libapp_backend.so to be a completely self contained binary. It should have not any dependency on any other .so file. I know that when we build an executable it totally makes sense to have statically linking and have a single binary at the end of it. Does similar thinking make sense when your final output is not an executable but itself an .so? I don't know. Please correct me if my whole expectation is wrong here.

Just as a sanity check, are you compiling as dylib or cdylib?

If you are compiling as dylib then the error message kinda makes sense... It's wanting to load a version of the Rust standard library dynamically, but couldn't find it. A dylib contains just the code for that crate, deferring loading any libraries it depends upon until load time. Whereas a cdylib is designed so you can package up your crate (and all its dependencies) so they can be used by other languages through its C interface (see the RFC for more).

1 Like

You beat me to it Michael. A while back I just went through rust docs and found the mention of cdylib and tried it and it just worked!! I also ran into the cdylib RFC later.

The documentation does not make the distinction between dylib and cdylib very clear, by the way, especially the aspect of including or not including other dependencies within it.

Thanks for the suggestion :slight_smile:

Another thing to remember is that a cdylib is kinda like a static library in that all Rust dependencies are compiled in. This usually isn't an issue but it bit me at work when I was trying to load multiple Rust modules and found logging (which is a global static variable under the hood) wasn't being shared between the two DLLs because each cdylib had its own copy of the env_logger library.

1 Like

Yup. That makes sense. Thanks for the heads-up :slight_smile: