在 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 to
clGetPlatformIDs' 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