Android NDK compilation error after importing a generated JUCE library and Oboe

Thanks to the Projucer, I created this very basic project, just to understand how to generate a static library for Android and how to import it on an Android project.

The library project can be found here

I managed to generate the library and locate the .a files for each configuration (arm64-v8a , armeabi-v7a , x86 , x86_64), in build/intermediates/cmake/release_Release/obj/.

Now I’m trying to import it on an Android project, and here is what I did:

  • in src/main/cpp/jucedemo/lib , I added the 4 directories ( arm64-v8a , armeabi-v7a , x86 , x86_64 ), with the different versions of my libJuceDemo.a in each directory

  • I also added a include directory with the header files in it, as you can see here:

  • I added the Android Oboe library, as explained here or here

  • Then, in my CMakeLists.txt:

cmake_minimum_required(VERSION 3.18.1)
project(TestJuceClient)

set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Ofast")

# Oboe
find_package(oboe REQUIRED CONFIG)

# JUCE
set(JuceDemo_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp/jucedemo)
add_library(JuceDemo STATIC IMPORTED)
set_property(TARGET JuceDemo PROPERTY IMPORTED_LOCATION
        ${JuceDemo_DIR}/lib/${ANDROID_ABI}/libJuceDemo.a)
set_target_properties(JuceDemo PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
        ${JuceDemo_DIR}/lib/include)
include_directories(${JuceDemo_DIR}/lib/include)
include_directories(~/JUCE/modules)

add_library(
        native-lib
        SHARED
        src/main/cpp/native-lib.cpp)

find_library(
        log-lib
        log)

target_link_libraries(
        native-lib
        JuceDemo
        oboe::oboe
        ${log-lib})
  • Then I tried to call the code of the library from my JNI (C++) code of my Android app, as shown here in my native-lib.cpp file:
#pragma clang diagnostic push
#pragma ide diagnostic ignored "hicpp-use-auto"

#include <jni.h>
#include <string>
#include <iostream>
#include "jucedemo/lib/include/JuceTest.h"

extern "C" JNIEXPORT jstring JNICALL Java_com_example_testjuceclient_MainActivity_test(JNIEnv *env, jclass)
{
    jucetest::JuceTest juceTest;
    jstring s = env->NewStringUTF(juceTest.getTexte().c_str());
    return s;
}

#pragma clang diagnostic pop

Now when I build my project, I get the following compilation error:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:buildCMakeDebug[arm64-v8a]'.
> Build command failed.
  Error while executing process /Users/mregnauld/AndroidSDK/cmake/3.18.1/bin/ninja with arguments {-C /Users/mregnauld/ProjetsAndroid/TestJuceClient/app/.cxx/Debug/6h5jam4z/arm64-v8a native-lib}
  ninja: Entering directory `/Users/mregnauld/ProjetsAndroid/TestJuceClient/app/.cxx/Debug/6h5jam4z/arm64-v8a'
  [1/2] Building CXX object CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o
  [2/2] Linking CXX shared library ../../../../build/intermediates/cxx/Debug/6h5jam4z/obj/arm64-v8a/libnative-lib.so
  FAILED: ../../../../build/intermediates/cxx/Debug/6h5jam4z/obj/arm64-v8a/libnative-lib.so 
  : && /Users/mregnauld/AndroidSDK/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ --target=aarch64-none-linux-android21 --gcc-toolchain=/Users/mregnauld/AndroidSDK/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64 --sysroot=/Users/mregnauld/AndroidSDK/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security   -O0 -fno-limit-debug-info  -Ofast  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libnative-lib.so -o ../../../../build/intermediates/cxx/Debug/6h5jam4z/obj/arm64-v8a/libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o  ../../../../src/main/cpp/jucedemo/lib/arm64-v8a/libJuceDemo.a  /Users/mregnauld/.gradle/caches/transforms-3/f8b380a28637ccd98f0014ee9261f2e3/transformed/jetified-oboe-1.6.1/prefab/modules/oboe/libs/android.arm64-v8a/liboboe.so  -llog  -latomic -lm && :
  ../../../../src/main/cpp/jucedemo/lib/arm64-v8a/libJuceDemo.a(include_juce_core.cpp.o): In function `juce::CPUInformation::initialise()':
  /Users/mregnauld/ProjetsJUCE/JuceDemo/Builds/Android/lib/.cxx/RelWithDebInfo/401i2l3d/arm64-v8a/../../../../../../../../../JUCE/modules/juce_core/native/juce_android_SystemStats.cpp:176: undefined reference to `android_getCpuCount'
  /Users/mregnauld/ProjetsJUCE/JuceDemo/Builds/Android/lib/.cxx/RelWithDebInfo/401i2l3d/arm64-v8a/../../../../../../../../../JUCE/modules/juce_core/native/juce_android_SystemStats.cpp:178: undefined reference to `android_getCpuFamily'
  /Users/mregnauld/ProjetsJUCE/JuceDemo/Builds/Android/lib/.cxx/RelWithDebInfo/401i2l3d/arm64-v8a/../../../../../../../../../JUCE/modules/juce_core/native/juce_android_SystemStats.cpp:179: undefined reference to `android_getCpuFeatures'
  clang++: error: linker command failed with exit code 1 (use -v to see invocation)
  ninja: build stopped: subcommand failed.

I guess that I missed something in my CMakeLists.txt file, but since I’m not a C++ expert, I really don’t know what.

Thanks for your help.

OK so here is what I did to make it compile and run (thanks @atsushieno for the help):

  • In my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.18.1)
project(TestJuceClient)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Ofast")

# Oboe
set(OBOE_DIR "${CMAKE_SOURCE_DIR}/../../../JUCE/modules/juce_audio_devices/native/oboe")
add_subdirectory(${OBOE_DIR} ./oboe)

# CPU Features
add_library("cpufeatures" STATIC "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")

# JUCE
set(JuceDemo_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp/jucedemo)
add_library(JuceDemo STATIC IMPORTED)
set_property(TARGET JuceDemo PROPERTY IMPORTED_LOCATION
        ${JuceDemo_DIR}/lib/${ANDROID_ABI}/libJuceDemo.a)
set_target_properties(JuceDemo PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
        ${JuceDemo_DIR}/lib/include)
include_directories(${JuceDemo_DIR}/lib/include)
include_directories(${CMAKE_SOURCE_DIR}/../../../JUCE/modules)

add_library(
        native-lib
        SHARED
        src/main/cpp/native-lib.cpp)

find_library(
        log-lib
        log)

target_link_libraries(
        native-lib
        JuceDemo
        "cpufeatures"
        "oboe"
        ${log-lib})
  • In my app/build.gradle file:
android {
    compileSdk 33

    defaultConfig {
        applicationId "com.example.testjuceclient"
        minSdk 21
        targetSdk 33
        versionCode 1
        versionName "1.0"

        sourceSets {
            main {
                jniLibs.srcDirs = ['src/main/cpp']
            }
        }
        externalNativeBuild {
            cmake {
                version = "3.24.1"
                abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
                arguments "-DANDROID_STL=c++_shared"
            }
        }
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    externalNativeBuild {
        cmake {
            path 'CMakeLists.txt'
        }
    }

    packagingOptions {
        exclude 'META-INF/AL2.0'
        exclude 'META-INF/LGPL2.1'
    }

    buildFeatures {
        prefab true
    }
}

That being said, I haven’t tested yet if it can play a sound.

Hope it helps.