Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross-compiling for Android doesn't seem to propagate architecture correctly #1167

Closed
korDen opened this issue Mar 5, 2022 · 3 comments
Closed

Comments

@korDen
Copy link
Contributor

korDen commented Mar 5, 2022

I have a basic method that I want to invoke through JNI. Think hello world. I have a similar one implemented in C. It works. Rust one fails to link. Let's start with a basic repro.

rust_static_library(
    name = "android-rs",
    srcs = ["src/lib.rs"], // #[no_mangle] pub fn hello_from_jni(...) { ... }
)

// Exact same think but in C++, just as a sanity check.
cc_library(
    name = "android-cc",
    srcs = ["sanity_check.cc"], // extern "C" void hello_from_jni(...) { ... }
)

android_binary(
    name = "android",
    custom_package = "rust.on.android",
    manifest = "AndroidManifest.xml",
    deps = [
        ":android-rs", // fails
        ":android-cc", // succeeds
    ],
)

bazel build :android

Command that fails:
external/androidndk/ndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang -shared -o bazel-out/android-armeabi-v7a-fastbuild/bin/_nativedeps/1_3_0_0_3_1603a52a129c5902439281827f3522ba084d3ca86608ba9c80599aee4f3a27a0.so bazel-out/android-armeabi-v7a-fastbuild/bin/platforms/android/libandroid_rs-3993832558.a external/androidndk/ndk/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libandroid_support.a external/androidndk/ndk/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_static.a external/androidndk/ndk/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++abi.a external/androidndk/ndk/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libunwind.a '-Wl,-soname=libandroid' -lSystem -lresolv -static-libgcc -Wl,-S -target armv7-none-linux-androideabi -gcc-toolchain external/androidndk/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 -Lexternal/androidndk/ndk/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a -no-canonical-prefixes -Wl,-z,relro -Wl,--gc-sections '--sysroot=external/androidndk/ndk/platforms/android-30/arch-arm'

Errors:

external/androidndk/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: error: bazel-out/android-armeabi-v7a-fastbuild/bin/platforms/android/libandroid_rs-3993832558.a: no archive symbol table (run ranlib)
external/androidndk/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: error: cannot find -lSystem
external/androidndk/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: error: cannot find -lresolv

the library that .rs file compiled into is this:
bazel-out/android-armeabi-v7a-fastbuild/bin/platforms/android/libandroid_rs-3993832558.a

which at first glance appears to detect architecture correct, but running lipo -info on it gives the following information:
Non-fat file: bazel-out/android-armeabi-v7a-fastbuild/bin/platforms/android/libandroid_rs-3993832558.a is architecture: x86_64

Which is totally wrong. Also otool says it's an AR file and each object file in it has a Mach header.

By comparison, if I use android_cc and not android_rs, everything compiles and links successfully, and the produced the following:

  1. libandroid.so is ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, not stripped
  2. main.pic.o ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), not stripped

The conclusion I'm getting here is that:

  • lib.rs was compiled for the host architecture (MacOS) and not for the target architecture (android armebi-v7a)
  • incorrect libraries are being linked in (-lSystem and -lresolv)
@korDen
Copy link
Contributor Author

korDen commented Mar 6, 2022

Digged a little bit deeper and the android-rs target is being explicitly compiled with --target=x86_64-apple-darwin flag.

I tried to override target by passing my own target via rustc_flags and it failed with error:

Option 'target' given more than once

Here is complete build configuration when compiling android_rs:

bazel-out/darwin-opt-exec-2B5CBBC6/bin/external/rules_rust/util/process_wrapper/process_wrapper --subst 'pwd=${pwd}' -- bazel-out/android-armeabi-v7a-fastbuild/bin/external/rust_darwin_x86_64/toolchain_for_x86_64-apple-darwin_impl/bin/rustc platforms/android/src/lib.rs '--crate-name=android_rs' '--crate-type=staticlib' '--error-format=human' '--codegen=metadata=-3993832558' '--out-dir=bazel-out/android-armeabi-v7a-fastbuild/bin/platforms/android' '--codegen=extra-filename=-3993832558' '--codegen=opt-level=0' '--codegen=debuginfo=0' '--remap-path-prefix=${pwd}=.' '--emit=dep-info,link' '--color=always' '--target=x86_64-apple-darwin' -L bazel-out/android-armeabi-v7a-fastbuild/bin/external/rust_darwin_x86_64/toolchain_for_x86_64-apple-darwin_impl/lib/rustlib/x86_64-apple-darwin/lib '--edition=2018' '--codegen=linker=external/androidndk/ndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang' --codegen 'link-args=-static-libgcc -target armv7-none-linux-androideabi -gcc-toolchain external/androidndk/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 -Lexternal/androidndk/ndk/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a -no-canonical-prefixes -Wl,-z,relro -Wl,--gc-sections --sysroot=external/androidndk/ndk/platforms/android-30/arch-arm' '-Lnative=external/androidndk/ndk/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a' '-Lnative=external/androidndk/ndk/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a' '-Lnative=external/androidndk/ndk/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a' '-Lnative=external/androidndk/ndk/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a' '-lstatic=android_support' '-lstatic=c++_static' '-lstatic=c++abi' '-lstatic=unwind')

@korDen
Copy link
Contributor Author

korDen commented Mar 6, 2022

I noticed that --codegen does have the right target (well, almost, rust wants a target triple but android is using quadruple), and used it as the target with a small patch like this:

-    rustc_flags.add("--target=" + toolchain.target_flag_value)
+    target_flag_value = toolchain.target_flag_value

(obtain link_args and then)
+            for i in range(0, len(link_args) - 1):
+                if link_args[i] == "-target":
+                    target_flag_value = link_args[i + 1].replace("-none-", "-") # armv7-none-linux-androideabi  -> armv7-linux-androideabi 
+                    break

(at the end)
+    rustc_flags.add("--target=" + target_flag_value)

This fixed the rustc invocation, replacing host target triple with correct target triple, but now I'm facing another issue:

error[E0461]: couldn't find crate std with expected target triple armv7-linux-androideabi

This is something I could fix with rustup (e.g rustup target add armv7-linux-androideabi) but no idea how to fix it with bazel :(

@korDen
Copy link
Contributor Author

korDen commented Mar 9, 2022

#1181 is aiming to fix this issue.

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

No branches or pull requests

1 participant