In my Android project, I want to import an external C++ library (generated by JUCE).
That library is made of 4 .a
files, one for each architecture, with headers, as you can see here:
And here is what I did to call a C++ test function from my main activity:
- my activity:
class MainActivity : AppCompatActivity()
{
companion object
{
init
{
System.loadLibrary("native-lib")
}
@JvmStatic private external fun test(): String
}
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d("TAG", "onCreate: ${test()}")
}
}
- 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
- my
CMakeLists.txt
file:
cmake_minimum_required(VERSION 3.18.1)
project(TestJuceClient)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Ofast")
# 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
${log-lib})
- my
app/build.gradle
file:
plugins {
id 'com.android.application'
id 'kotlin-android'
}
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'
}
}
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'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
Everything looks fine but when I build the project, I get the following error:
* 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/736e21o2/arm64-v8a native-lib}
ninja: Entering directory `/Users/mregnauld/ProjetsAndroid/TestJuceClient/app/.cxx/Debug/736e21o2/arm64-v8a'
[1/1] Linking CXX shared library ../../../../build/intermediates/cxx/Debug/736e21o2/obj/arm64-v8a/libnative-lib.so
FAILED: ../../../../build/intermediates/cxx/Debug/736e21o2/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 -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libnative-lib.so -o ../../../../build/intermediates/cxx/Debug/736e21o2/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 -llog -latomic -lm && :
../../../../src/main/cpp/jucedemo/lib/arm64-v8a/libJuceDemo.a(include_juce_audio_devices.cpp.o): In function `juce::OboeAudioIODevice::OboeStream::open(int, oboe::Direction, oboe::SharingMode, int, oboe::AudioFormat, int, int, oboe::AudioStreamCallback*)':
/Users/mregnauld/ProjetsJUCE/JuceDemo/Builds/Android/lib/.cxx/RelWithDebInfo/401i2l3d/arm64-v8a/../../../../../../../../../JUCE/modules/juce_audio_devices/native/juce_android_Oboe.cpp:532: undefined reference to `oboe::DefaultStreamValues::FramesPerBurst'
/Users/mregnauld/ProjetsJUCE/JuceDemo/Builds/Android/lib/.cxx/RelWithDebInfo/401i2l3d/arm64-v8a/../../../../../../../../../JUCE/modules/juce_audio_devices/native/juce_android_Oboe.cpp:532: undefined reference to `oboe::DefaultStreamValues::FramesPerBurst'
/Users/mregnauld/ProjetsJUCE/JuceDemo/Builds/Android/lib/.cxx/RelWithDebInfo/401i2l3d/arm64-v8a/../../../../../../../../../JUCE/modules/juce_audio_devices/native/juce_android_Oboe.cpp:568: undefined reference to `oboe::AudioStreamBuilder::openStream(oboe::AudioStream**)'
../../../../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.
* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:buildCMakeDebug[arm64-v8a]'.
Caused by: org.gradle.internal.UncheckedException: 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/736e21o2/arm64-v8a native-lib}
ninja: Entering directory `/Users/mregnauld/ProjetsAndroid/TestJuceClient/app/.cxx/Debug/736e21o2/arm64-v8a'
[1/1] Linking CXX shared library ../../../../build/intermediates/cxx/Debug/736e21o2/obj/arm64-v8a/libnative-lib.so
FAILED: ../../../../build/intermediates/cxx/Debug/736e21o2/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 -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libnative-lib.so -o ../../../../build/intermediates/cxx/Debug/736e21o2/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 -llog -latomic -lm && :
../../../../src/main/cpp/jucedemo/lib/arm64-v8a/libJuceDemo.a(include_juce_audio_devices.cpp.o): In function `juce::OboeAudioIODevice::OboeStream::open(int, oboe::Direction, oboe::SharingMode, int, oboe::AudioFormat, int, int, oboe::AudioStreamCallback*)':
/Users/mregnauld/ProjetsJUCE/JuceDemo/Builds/Android/lib/.cxx/RelWithDebInfo/401i2l3d/arm64-v8a/../../../../../../../../../JUCE/modules/juce_audio_devices/native/juce_android_Oboe.cpp:532: undefined reference to `oboe::DefaultStreamValues::FramesPerBurst'
/Users/mregnauld/ProjetsJUCE/JuceDemo/Builds/Android/lib/.cxx/RelWithDebInfo/401i2l3d/arm64-v8a/../../../../../../../../../JUCE/modules/juce_audio_devices/native/juce_android_Oboe.cpp:532: undefined reference to `oboe::DefaultStreamValues::FramesPerBurst'
/Users/mregnauld/ProjetsJUCE/JuceDemo/Builds/Android/lib/.cxx/RelWithDebInfo/401i2l3d/arm64-v8a/../../../../../../../../../JUCE/modules/juce_audio_devices/native/juce_android_Oboe.cpp:568: undefined reference to `oboe::AudioStreamBuilder::openStream(oboe::AudioStream**)'
../../../../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.
at com.android.build.gradle.internal.cxx.process.ProcessOutputJunction.execute(ProcessOutputJunction.kt:126)
at com.android.build.gradle.internal.cxx.process.ProcessOutputJunction.execute(ProcessOutputJunction.kt:149)
at com.android.build.gradle.internal.cxx.build.CxxRegularBuilder.executeProcessBatch(CxxRegularBuilder.kt:363)
at com.android.build.gradle.internal.cxx.build.CxxRegularBuilder.build(CxxRegularBuilder.kt:140)
at com.android.build.gradle.tasks.ExternalNativeBuildTask$doTaskAction$$inlined$recordTaskAction$1.invoke(BaseTask.kt:70)
at com.android.build.gradle.internal.tasks.Blocks.recordSpan(Blocks.java:51)
at com.android.build.gradle.tasks.ExternalNativeBuildTask.doTaskAction(ExternalNativeBuildTask.kt:136)
at com.android.build.gradle.internal.tasks.UnsafeOutputsTask$taskAction$$inlined$recordTaskAction$1.invoke(BaseTask.kt:65)
at com.android.build.gradle.internal.tasks.Blocks.recordSpan(Blocks.java:51)
at com.android.build.gradle.internal.tasks.UnsafeOutputsTask.taskAction(UnsafeOutputsTask.kt:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
... 114 more
And for those who are interested, here is the JUCE library project.
I think the problem could come from my CMakeLists.txt
file, but since I'm not a C++ expert, and even after reading the official documentation, I still don't manage to find what I did wrong.
So what should I fix to make my project compile?
Thanks for your help.
UPDATE
I installed the Oboe library as explained here or here, but I still have the same error...