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

Android failed to load dynamic library: dlopen failed: library "libc++shared.so" not found #900

Closed
zhpixel517 opened this issue Jul 19, 2024 · 5 comments

Comments

@zhpixel517
Copy link

Hi all,
I'm trying to run cpal on an Android device inside my Flutter application. When I run the app, I am greeted with this error:

Failed to load dynamic library 'librust_lib_flutter_rust_test.so': 
dlopen failed: library "libc++_shared.so" not found: 
needed by /data/app/~~zyZDDuG_hSM2uJQAOeqDBQ==/com.example.flutter_rust_test-sBfBRTor8WZZGQJgZMG0PA==/lib/arm64/librust_lib_flutter_rust_test.so in namespace clns-4

The project builds fine, but I run this code and then the error is thrown:

let host = cpal::default_host();

  let input_device = host.default_input_device().unwrap();
  let output_device = host.default_output_device().unwrap();

  let input_config = cpal::StreamConfig {
      channels: 1,
      sample_rate: cpal::SampleRate(48000),
      buffer_size: cpal::BufferSize::Default,
  };
  // let output_config: cpal::StreamConfig = input_config.clone();
  let output_config = cpal::StreamConfig {
      channels: 1,
      sample_rate: cpal::SampleRate(48000),
      buffer_size: cpal::BufferSize::Default,
  };

  let input_stream = input_device
      .build_input_stream(
          &input_config,
          move |data: &[f32], _: &_| {
              // do something
          },
          move |err| {
              eprintln!("There was an input error: {:?}", err);
          },
          None,
      )
      .unwrap();

I know that this is the same problem as #720 - and I tried this solution from that issue:

I'm using this code to initialize the context. Just make it part of your fancy lib.

use jni::{JNIEnv, JavaVM};
use std::ffi::c_void;

#[no_mangle]
pub extern "C" fn JNI_OnLoad(vm: jni::JavaVM, res: *mut std::os::raw::c_void) -> jni::sys::jint {
    let env = vm.get_env().unwrap();
    let vm = vm.get_java_vm_pointer() as *mut c_void;
    unsafe {
        ndk_context::initialize_android_context(vm, res);
    }
    jni::JNIVersion::V6.into()
}

no success here. I'm also not entirely sure where exactly to put this code. I tried putting it inside my build.rs and also with my main application code as well with no results.

I also tried taking issue #563 's advice here:

This can be solved by enabling the shared-stdcxx feature for oboe

oboe = { version = "0.4", features = [ "java-interface", "shared-stdcxx" ] }

Then I also had to copy libc++_shared.so into my jniLibs directory (there's likely a way to automate this...)

Originally posted by @trobanga in #563 (comment)

Doing this created some strange errors. I see that it has usage of IPHONEOS_DEPLOYMENT_TARGET which wouldn't make sense for compiling to an android application:

  cargo:warning=oboe/src/common/OboeDebug.h:21:10: fatal error: 'android/log.h' file not found
  cargo:warning=#include <android/log.h>
  cargo:warning=         ^~~~~~~~~~~~~~~
  cargo:warning=1 error generated.
  cargo:warning=In file included from oboe/src/common/StabilizedCallback.cpp:18:
  cargo:warning=oboe/src/common/AudioClock.h:50:45: error: use of undeclared identifier 'TIMER_ABSTIME'
  cargo:warning=        return 0 - clock_nanosleep(clockId, TIMER_ABSTIME, &time, NULL);
  cargo:warning=                                            ^
  cargo:warning=oboe/src/common/AudioClock.h:67:24: error: use of undeclared identifier 'clock_nanosleep'
  cargo:warning=            return 0 - clock_nanosleep(clockId, 0, &time, NULL);
  cargo:warning=                       ^
  cargo:warning=2 errors generated.
  exit status: 1
  cargo:warning=ToolExecError: Command env -u IPHONEOS_DEPLOYMENT_TARGET "c++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-2" "-fno-omit-frame-pointer" "-arch" "arm64" "-static" "-I" "oboe/include" "-I" "oboe/src" "-I" "oboe-ext/include" "-I" "oboe-ext/src" "-Wall" "-Wextra" "-std=c++17" "-Wall" "-Wextra-semi" "-Wshadow" "-Wshadow-field" "-fno-rtti" "-fno-exceptions" "-DOBOE_ENABLE_LOGGING=1" "-o" "/Users/zacharyhaslam/FlutterApplications/flutter_rust_test/rust/target/debug/build/oboe-sys-54157a8a77fee849/out/library/oboe/src/common/StabilizedCallback.o" "-c" "oboe/src/common/StabilizedCallback.cpp" with args "c++" did not execute successfully (status code exit status: 1).
  exit status: 1
  cargo:warning=ToolExecError: Command env -u IPHONEOS_DEPLOYMENT_TARGET "c++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-2" "-fno-omit-frame-pointer" "-arch" "arm64" "-static" "-I" "oboe/include" "-I" "oboe/src" "-I" "oboe-ext/include" "-I" "oboe-ext/src" "-Wall" "-Wextra" "-std=c++17" "-Wall" "-Wextra-semi" "-Wshadow" "-Wshadow-field" "-fno-rtti" "-fno-exceptions" "-DOBOE_ENABLE_LOGGING=1" "-o" "/Users/zacharyhaslam/FlutterApplications/flutter_rust_test/rust/target/debug/build/oboe-sys-54157a8a77fee849/out/library/oboe/src/common/Trace.o" "-c" "oboe/src/common/Trace.cpp" with args "c++" did not execute successfully (status code exit status: 1).cargo:warning=oboe-ext/src/AudioStreamCallbackWrapper.cpp:3:10: fatal error: 'android/log.h' file not found
  cargo:warning=#include <android/log.h>
  cargo:warning=         ^~~~~~~~~~~~~~~
  cargo:warning=1 error generated.
  exit status: 0
  exit status: 0
  exit status: 0
  exit status: 1
  cargo:warning=ToolExecError: Command env -u IPHONEOS_DEPLOYMENT_TARGET "c++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-2" "-fno-omit-frame-pointer" "-arch" "arm64" "-static" "-I" "oboe/include" "-I" "oboe/src" "-I" "oboe-ext/include" "-I" "oboe-ext/src" "-Wall" "-Wextra" "-std=c++17" "-Wall" "-Wextra-semi" "-Wshadow" "-Wshadow-field" "-fno-rtti" "-fno-exceptions" "-DOBOE_ENABLE_LOGGING=1" "-o" "/Users/zacharyhaslam/FlutterApplications/flutter_rust_test/rust/target/debug/build/oboe-sys-54157a8a77fee849/out/library/oboe-ext/src/AudioStreamCallbackWrapper.o" "-c" "oboe-ext/src/AudioStreamCallbackWrapper.cpp" with args "c++" did not execute successfully (status code exit status: 1).
  --- stderr
  error occurred: Command env -u IPHONEOS_DEPLOYMENT_TARGET "c++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-2" "-fno-omit-frame-pointer" "-arch" "arm64" "-static" "-I" "oboe/include" "-I" "oboe/src" "-I" "oboe-ext/include" "-I" "oboe-ext/src" "-Wall" "-Wextra" "-std=c++17" "-Wall" "-Wextra-semi" "-Wshadow" "-Wshadow-field" "-fno-rtti" "-fno-exceptions" "-DOBOE_ENABLE_LOGGING=1" "-o" "/Users/zacharyhaslam/FlutterApplications/flutter_rust_test/rust/target/debug/build/oboe-sys-54157a8a77fee849/out/library/oboe-ext/src/AudioStreamCallbackWrapper.o" "-c" "oboe-ext/src/AudioStreamCallbackWrapper.cpp" with args "c++" did not execute successfully (status code exit status: 1).

However, I'm using flutter_rust_bridge which uses a code gen tool that handles most of the compilation for me. I think it automatically compiles for iOS and Android at the same time. I'm not super good at diagnosing configuration errors on Android, so I'm not entirely sure where I could be going wrong here. I also posted this issue on the flutter_rust_bridge github which might provide some more clarity.

I've seen people mention dragging a libc++_shared.so file into a jniLibs directory, but neither are present in my project files. I also tried making my own empty jniLibs folder to no success either.

Long story short, no matter what I seem to try, I can't seem to get rid of this error. Any ideas here?

@trobanga
Copy link

You need to find the correct libc++_shared.so for your target in the Android SDK you are using and copy it to jniLibs.

@zhpixel517
Copy link
Author

zhpixel517 commented Jul 22, 2024

@trobanga do you know which is the correct one for this case? there are several on my system:

./Library/Android/sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so
./Library/Android/sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so
./Library/Android/sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so
./Library/Android/sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib/i686-linux-android/libc++_shared.so
./Library/Android/sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib/riscv64-linux-android/libc++_shared.so

I saw another example of this where somebody included arm64-v8a, armeabi-v7a, x86, x86_64 inside this jniLibs folder and each one had a libc++_shared.so inside it. Do I just need to include one libc++_shared.so for the particular architecture of Android phone I'm building for, or should I include all of them like the example? If I do include each in a folder, the example doesn't quite match with the architectures I have on my system. I have aarch64-linux-android, i686-linux-android, x86_64-linux-android, arm-linux-androideabi, riscv64-linux-android instead.

@trobanga
Copy link

Yes, just follow the example and put the lib from aarch64-linux-android into arm64-v8a, arm-linux-androideabi into armeabi-v7a, i868 -> x86, x64 -> x86_64.
x86 and x86_64 are only needed, if you want to run your app in a simulator.

@MateusHBR
Copy link

MateusHBR commented Jul 25, 2024

I solved this problem in my experiment in the past, I don't remember exactly which package was necessary to include, but I know that CPAL uses Jni bridge under the hood because just Oboe in Android don't provide the input and other device specific features. Try to import CPAL with the mentioned features and all of those [android] packages mentioned with their features to see if it solves your problem. I remember that is not necessary include directly a binary inside jni folder because cargo deals with the binaries compilation for you.

I will try to find the docs that helped me to solve that issue, but I found diving into CPAL docs and issues.

Screenshot 2024-07-25 at 09 29 01

@zhpixel517
Copy link
Author

Yes, just follow the example and put the lib from aarch64-linux-android into arm64-v8a, arm-linux-androideabi into armeabi-v7a, i868 -> x86, x64 -> x86_64. x86 and x86_64 are only needed, if you want to run your app in a simulator.

I was able to fix it following this advice. Thank you @trobanga. I also had to add this into my app/src/build.gradle:

android {
     // ....
      sourceSets {
        main {
            jni.srcDirs = []
            jniLibs.srcDirs = ['src/jniLibs']
        }
    }
}

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

3 participants