3
votes

I am trying to set a simple project in Android Studio with OpenCL. So I created a new project with NDK support and an empty activity. I have copied the libOpenCL.so from my mobile phone to the folder app\src\main\jniLibs\arm8 and I have downloaded the OpenCL headers from the Khronos webpage and copied them to app\src\main\jni\CL. Furthermore, I have done two modifications to the build.gradle file, I have added a parameter to the cppFlags to include the OpenCL folder and I have set an abi filter to build only for arm8. I copy my build.gradle file here:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.1"
    defaultConfig {
        applicationId "es.um.mompes.testopencl"
        minSdkVersion 22
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++11 -fexceptions -I${projectDir}/src/main/jni"
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
    productFlavors {
        arm8 {
            ndk {
                abiFilter "arm64-v8a"
            }
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}

I have also added a three lines to the generated native-lib.cpp file to test if OpenCL is working. This is my native-lib.cpp:

#include <jni.h>
#include <string>
#include <CL/cl.h>

extern "C"
JNIEXPORT jstring JNICALL
Java_es_um_mompes_testopencl_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    cl_int err;
// Find the number of OpenCL platforms
    cl_uint num_platforms;
    err = clGetPlatformIDs(0, NULL, &num_platforms);
    return env->NewStringUTF(hello.c_str());
}

However, I must be missing something because I am getting an undefined reference error regarding the OpenCL function when I build the project. This is the complete error: Execution failed for task ':app:externalNativeBuildArm8Debug'.

Build command failed. Error while executing process C:\Users\Juan\AppData\Local\Android\Sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build C:\Users\Juan\AndroidStudioProjects\TestOpenCL\app.externalNativeBuild\cmake\arm8Debug\arm64-v8a --target native-lib} [1/1] Linking CXX shared library ........\build\intermediates\cmake\arm8\debug\obj\arm64-v8a\libnative-lib.so FAILED: cmd.exe /C "cd . && C:\Users\Juan\AppData\Local\Android\sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=aarch64-none-linux-android --gcc-toolchain=C:/Users/Juan/AppData/Local/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64 --sysroot=C:/Users/Juan/AppData/Local/Android/sdk/ndk-bundle/sysroot -fPIC -isystem C:/Users/Juan/AppData/Local/Android/sdk/ndk-bundle/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=22 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -fexceptions -IC:\Users\Juan\AndroidStudioProjects\TestOpenCL\app/src/main/jni -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a --sysroot C:/Users/Juan/AppData/Local/Android/sdk/ndk-bundle/platforms/android-22/arch-arm64 -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libnative-lib.so -o ........\build\intermediates\cmake\arm8\debug\obj\arm64-v8a\libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o -llog -lm "C:/Users/Juan/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/arm64-v8a/libgnustl_static.a" && cd ." CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o: In function Java_es_um_mompes_testopencl_MainActivity_stringFromJNI': C:\Users\Juan\AndroidStudioProjects\TestOpenCL\app\src\main\cpp/native-lib.cpp:14: undefined reference toclGetPlatformIDs' clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)

Do you know what am I missing? I've searching for a few hours over the last two days about how to setup OpenCL in Android Studio but everything I find seems to be outdated and doesn't seem to work for my problem.

2
Where did you copy libOpenCL.so from? - zindarod
Hi @Zindarod I copied it from /system/vendor/lib64/libOpenCL.so. - mompes
Post your android device specs. I am assuming that you're not running OpenCL code in an emulator. - zindarod
It is a Xiaomi Redmi Note 3 (the Qualcomm version) with an Adreno 510 GPU. - mompes

2 Answers

1
votes

Look for Android.mk under jni folder. Then add this:

LOCAL_PATH := $(call my-dir) // should already be there
.
.
LOCAL_LDLIBS := $(LOCAL_PATH)/libOpenCL.so

This example takes the libOpenCL.so from the jni root but you can change this for your needs.

Reference: Getting Started with OpenCL on Android

0
votes

I would recommend you replace the automatic Android Studio NDK building with your own so you have total control. Then you can use @RonTLV answer to add the library to the Android.mk and have a proper build.

Android Studio by default ignores Android.mk and generates its own with all the .c/.cpp files in the jni folder.

sourceSets {
    debug.jniLibs.srcDir 'src/main/obj/local' //debug builds have symbols
    release.jniLibs.srcDir 'src/main/libs' //release builds have cleaned libraries
    main.jni.srcDirs = [] //disable automatic ndk-build call with auto-generated Android.mk
}

// call regular ndk-build script manually
task ndkBuild(type: Exec) {
    if (System.properties['os.name'].toLowerCase(Locale.ROOT).contains('windows')) {
        commandLine 'ndk-build.cmd', '-j8', '-C', file('src/main').absolutePath
    } else {
        commandLine 'ndk-build', '-j8', '-C', file('src/main').absolutePath
    }
}

//Make the NDK task depend on Java build Task
tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn ndkBuild
}