在 Android 中调用 OpenCL 函数时未定义的引用

Posted

技术标签:

【中文标题】在 Android 中调用 OpenCL 函数时未定义的引用【英文标题】:Undefined reference when calling a OpenCL function in Android 【发布时间】:2018-02-17 10:41:01 【问题描述】:

我正在尝试使用 OpenCL 在 android Studio 中设置一个简单的项目。所以我创建了一个支持 NDK 的新项目和一个空活动。我已将 libOpenCL.so 从我的手机复制到文件夹 app\src\main\jniLibs\arm8 并从 Khronos 网页下载 OpenCL 标头并将它们复制到 app\src\main\jni\CL。此外,我对 build.gradle 文件进行了两次修改,我在 cppFlags 中添加了一个参数以包含 OpenCL 文件夹,并且我已经设置了一个 abi 过滤器来仅为 arm8 构建。我在这里复制我的 build.gradle 文件:

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'

我还在生成的 native-lib.cpp 文件中添加了三行代码来测试 OpenCL 是否正常工作。这是我的 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());

但是,我一定遗漏了一些东西,因为在构建项目时我收到了关于 OpenCL 函数的未定义引用错误。这是完整的错误: 任务 ':app:externalNativeBuildArm8Debug' 执行失败。

构建命令失败。 使用参数执行进程 C:\Users\Juan\AppData\Local\Android\Sdk\cmake\3.6.4111459\bin\cmake.exe 时出错 --build C:\Users\Juan\AndroidStudioProjects\TestOpenCL\app.externalNativeBuild \cmake\arm8Debug\arm64-v8a --target native-lib [1/1] 链接 CXX 共享库 ........\build\intermediates\cmake\arm8\debug\obj\arm64-v8a\libnative-lib.so 失败: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,--致命警告 -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-argume nts -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:在函数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:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)

你知道我错过了什么吗?在过去的两天里,我搜索了几个小时来了解如何在 Android Studio 中设置 OpenCL,但我发现的所有内容似乎都已过时,似乎对我的问题不起作用。

【问题讨论】:

你是从哪里复制 libOpenCL.so 的? 嗨 @Zindarod 我从 /system/vendor/lib64/libOpenCL.so 复制了它。 发布您的安卓设备规格。我假设您没有在模拟器中运行 OpenCL 代码。 这是一款小米红米 Note 3(高通版),搭载 Adreno 510 GPU。 【参考方案1】:

jni 文件夹下查找Android.mk。然后添加:

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

此示例从 jni 根目录获取 libOpenCL.so,但您可以根据需要进行更改。

参考:Getting Started with OpenCL on Android

【讨论】:

我已经在 jni 下添加了 Android.mk 和 Application.mk 文件,如 Arrayfire 链接中所述,但我仍然遇到相同的错误。我不知道这些文件是否真的被使用了。我是否必须更改标志才能强制使用这些参数? 尝试将 -OpenCL 添加到编译器 CFLAGS(如 -std=gnu11 -lOpenCL) 如果我在 build.gradle 文件的参数“cppFlags”中添加标志,它甚至不会同步 gradle 文件,因为它找不到库。虽然如果我在 Android.mk 文件中添加标志,它不会抱怨,但我仍然收到“未定义的引用”错误。【参考方案2】:

我建议您将自动构建的 Android Studio NDK 替换为您自己的,这样您就可以完全控制。 然后您可以使用@RonTLV 答案将库添加到 Android.mk 并进行正确的构建。

默认情况下,Android Studio 会忽略 Android.mk,并使用 jni 文件夹中的所有 .c/.cpp 文件生成自己的文件。

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

【讨论】:

以上是关于在 Android 中调用 OpenCL 函数时未定义的引用的主要内容,如果未能解决你的问题,请参考以下文章

在Android中锁定屏幕时未调用BroadcastReceiver

Android开发之《硬件加速》

在函数中调用时未定义 BeautifulSoup

从opencl内核中调用一个具有通过值概念的函数。

在 Codeigniter 中调用扩展辅助函数时未定义的函数

Qt TextField 在 Android 设备上启动时未调用键盘