Android Studio下配置OpenCL库函数

近期由于要在移动端优化图像的处理速度,经过短暂调研发现用OpenCL或许可以达到优化的效果,因此就开始在Android Studio上配置ocl的库(使用平台是Mac下的Android Studio)。遇到的坑不少,所以详细记录一下以备用。前提:<font color=#DC143C>具有一定的NDK编译基础!</font>
首先我们通过OpenCL的官方Demo来作为例子,该链接下有“OpenCL samples for Android”的分类下有两个Sample Demo,随便哪个都行。下载下来可以看到是使用Eclipse编译的,而熟悉Android
Studio的朋友也知道,在AS下编译使用NDK和Eclipse的差别还是很大的。将下载下来的Eclipse工程导入AS中(这个应该都会,就不说了),然后点击运行......用脚趾头想当然是跑不起来的啦,不急,继续往下撸。
首先看一下工程的jni目录下的文件,一共三个(以AndroidBasicOpenCL工程为例):Android.mk、Application.mk、step.cpp,make文件我们暂且不表,工程中使用的JNI代码都是在step.cpp文件当中(Sample的作者也是很懒,连.h文件都懒得写(╯°Д°)╯︵ ┻━┻),点开该c++文件我们就发现一大堆头文件找不到的错误,一些是android NDK自带的库函数,最重要的还是#include<CL/cl.h>头文件找不到。本文章的主要问题就是解决该头文件的引用问题。
顺着思路往下走,既然找不到头文件,就只好手动引用进去了,遍历整个工程发现OCL的头文件一个影子也没见到,那就去Github上自己下吧!将列表里的所有头文件都下载下来,并在工程里jni目录下新建OpenCL文件夹,把所有的头文件都Copy进去,看下图:

project_structure.png

再编译一下发现还是找不到,为啥?编过NDK的童鞋都知道是make文件没有配置过。那就去Android.mk里面看看吧,原始导入到AS的make文件是长这个样子的:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

# To allow building native part of application with OpenCL,
# OpenCL header files and statically linked library are required.
# They are used from Intel OpenCL SDK installation directories,
# that are determined below: 

ifeq ($(TARGET_ARCH),x86)
    OCL_POSTFIX := android32
else ifeq ($(TARGET_ARCH),x86_64)
    OCL_POSTFIX := android64
else
    # Unsupported target, do nothing
endif

ifneq ($(OS),Windows_NT)
    ifndef INTELOCLSDKROOT
        INTELOCLSDKROOT := /etc/alternatives/opencl-intel-tools
    endif

    # Setting LOCAL_CFLAGS with -I is not good in comparison to LOCAL_C_INCLUDES
    # according to NDK documentation, but this only variant that works correctly

    LOCAL_CFLAGS    += -I$(INTELOCLSDKROOT)/include
    LOCAL_MODULE    := step
    LOCAL_SRC_FILES := step.cpp
    LOCAL_LDFLAGS   += -llog -ljnigraphics -L$(INTELOCLSDKROOT)/lib64/$(OCL_POSTFIX) -lOpenCL
else
    # Setting LOCAL_CFLAGS with -I is not good in comparison to LOCAL_C_INCLUDES
    # according to NDK documentation, but this only variant that works correctly

    LOCAL_CFLAGS    += -I"$(INTELOCLSDKROOT)\include"
    LOCAL_MODULE    := step
    LOCAL_SRC_FILES := step.cpp
    LOCAL_LDFLAGS   += -llog -ljnigraphics -L"$(INTELOCLSDKROOT)\lib\$(OCL_POSTFIX)" -lOpenCL
endif
LOCAL_ARM_MODE :=arm
include $(BUILD_SHARED_LIBRARY)

由于这里是Mac OS平台下,所以直接看ifneq ($(OS),Windows_NT)下的逻辑,这里定义了一个常量INTELOCLSDKROOT下的路径,推测是编写该Sample的作者的PC系统路径下的OpenCL函数库所在,原生默认的无论在MacOS下还是在Windows下都验证过该路径并不存在,因此这里暂时忽略之。这个路径既然没什么卵用,那与之相关的代码不妨也全部注释掉自己写,首先了解NDK编译的童鞋应该知道LOCAL_MODULELOCAL_SRC_FILES的含义,在这里我们也就用到这两个,其他的都可以用#注释掉无视。我习惯在Gradle文件中去构建make中的部分系统变量,这里也把Gradle的代码贴出来:

import org.apache.tools.ant.taskdefs.condition.Os

apply plugin: 'com.android.application'

android {    
     compileSdkVersion 21    
     buildToolsVersion "23.0.3"
     defaultConfig {        
             applicationId "com.intel.sample.androidbasicocl"
             minSdkVersion 14
             targetSdkVersion 19
             ndk {            
                  moduleName "step"            
                  stl "stlport_static"           
                  ldLibs "log","z","-I${file("src/main/libs")}".toString()
                  cFlags += "-I${file("src/main/jni/OpenCL")}".toString()        
       }    
}    
sourceSets.main {        
             jniLibs.srcDir 'src/main/libs' 
             jni.srcDirs = [] 
    }
task ndkBuild(type: Exec) {
        def ndkDir = android.ndkDirectory.getAbsolutePath()
        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
           commandLine ndkDir + '/ndk-build.cmd', '-C', file('src/main/jni').absolutePath
        } else {
            commandLine ndkDir + '/ndk-build', '-C', file('src/main/jni').absolutePath
        }
}
tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }    
buildTypes {        
        release 
              {            
               minifyEnabled false            
               proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'        
          }    
      }
}

重点看ndk编译模块下的代码,NDK编译的模块名是step,stl支持c++的静态库,这些没啥好说的,关键是ldLibs以及cFlags两个系统变量。ldLibs声明链接时使用到的库是android的log和z,后面一个库很关键,是OpenCL的so库,后面再说。cFlags则是声明编译gcc时的flag,对应前文加入的OpenCL头文件。再下面的ndkBuild task可以忽略,因为本来是想在AS上直接编so的,后来发现不行,就用命令行来编了。
前面有说到需要使用OpenCL的so库放入工程当中,不然就算找到了头文件也会在编译的时候因为找不到cl的相关引用而报错。那么这个so哪里来呢?可以从网上找,资源还是有的,就不推荐了,我是从手机系统里抠!出!来!的!没错,因为有部分手机是不支持OCL的(看是否支持可以下载名为“OpenCL-Z”的应用来测试),刚好我的测试机是支持的,所以我从手机根目录/system/vendor/lib/libOpenCL.so的路径下找到了这个库,并Copy出来放到了工程jniLibs/armeabi/目录下,其他CPU架构的类似,不表。好了,准备工作就绪,下面就需要编译成so库了。
不知道为什么,我的Mac上把NDK的路径放入.bash_profile里面还是不能引用,那就只能用绝对路径玩了,先知道自己的NDK ndk-build编译文件的路径(Windows下应该是ndk-build.cmd)的文件路径,一般都是/Users/YourName/Library/Android/sdk/ndk-bundle,然后在bash命令行下进入到工程的jni目录下面,运行/Users/YourName/Library/Android/sdk/ndk-bundle/ndk-build果然还是报错!(╯°Д°)╯︵ ┻━┻错误是

ndk-build error.png

直接写解决方法:在Application.mk文件当中添加以下代码:
APP_BUILD_SCRIPT := Android.mk
同样在jni目录下,用bash命令行写:
/Users/YourName/Library/Android/sdk/ndk-bundle/ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk
至此,编译成功!
compile success.png

Log显示编出来的so是放在了libs/armeabi/目录下面,把库移到jniLibs/armeabi/下面,并把生成的这个文件删除,即可运行成功。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • Android游戏开发实践(1)之NDK与JNI开发02 承接上篇Android游戏开发实践(1)之NDK与JNI...
    AlphaGL阅读 3,686评论 0 24
  • 一、NDK产生的背景 Android平台从诞生起,就已经支持C、C++开发。众所周知,Android的SDK基于J...
    Ten_Minutes阅读 3,398评论 1 27
  • 《简介儿时一个我》我对家园的最初印像始于五岁。那时的我剃着光头,鼻孔经常有清涕伴随。我的眼睛是属于太阳光最毒时出来...
    文字奴隶阅读 317评论 40 4
  • 尽叹红尘恼, 仙宫又路迢。 醉赏田园景, 心平自逍遥。
    湘水碧波阅读 211评论 0 3