跳至内容

Junyi's Lab

TVM RPC Android 部署踩坑

## 先说结论

环境:Ubuntu 18.04 LTS (非虚拟机)

手机:Xiaomi Mi 5s, 3GB RAM, 64GB ROM

系统:原生 Android 10

遇到问题:android_rpc 无法编译部署

解决方法:核心思路是分析 gradle task 执行顺序,分析相关脚本,检查环境变量。这个问题需要具体情况具体分析,请仔细查看本文【问题解决】部分的相关描述。


## 部署 android_rpc

按照官方教程来走,先是基于源代码安装 TVM 库,安装之前要把 LLVM 装好。

然后安装 Gradle,Maven

然后编译 TVM4J

编译好之后我开始按照官方教程尝试部署 apps/android_rpc 这个项目

因为上次部署 TVM 的经验教训让我知道了严格按照官方教程走的重要性。

只可惜,这次就算按照官方教程来部署,得到的结果依然是:

失败。


## 踩坑

Gradle 版本不对,Ubuntu 18.04 默认给安装的是 3.x 版本,后来添加的源,upgrade 一下才可以。

然后又遇到了你懂的特色互联网防火墙的问题:Maven 下载速度特别慢。

解决了网络的问题之后,我心想能不能把项目丢到 AndroidStudio 里面跑啊,然后我就试了一下

于是

给自己带来了另一个坑

Android Studio 推荐我更新 Gradle

我手贱点了更新

然后版本号对不上了

搞了半天踩意识到是自己手贱更新了Gradle。

折腾了好长一段时间,遇到了新的问题:

cannot find class file 'org.apache.tvm.LibInfo'

叼,烦死了。

我无论怎么 make clean 都不行,

然后我重新把 TVM 编译了一遍(我真是傻逼)

clean 了一下,make 了一下,编译完了

依!然!报!错!

折腾了好长一段时间,到了晚上12点,用官方提供的工具怎么也解决不了问题,

Google 了一次又一次,全是失败告终。


## 灵机一动

配置这么大型的项目,而且网上没有多少参考资料,搜索也几乎很难找到结果。手中的设备千差万别,想要真正部署起来真的太麻烦了。在我快疯了的时候,突然想到:草!我干嘛不看看他的脚本怎么写的呢?

说干就干,我在src/main/jni/build.sh这个脚本里发现了这么一段话:

javah -o $CURR_DIR/org_apache_tvm_native_c_api.h -cp "$ROOT_DIR/jvm/core/target/*" org.apache.tvm.LibInfo exit -1

没错,就是这句话⬆️执行失败导致 exit -1,在这句话前面还设置了一堆环境变量:

PATH="$PATH:/usr/local/bin"
CURR_DIR=$(cd `dirname $0`; pwd)
ROOT_DIR="$CURR\_DIR/../../../../../.."

我把脚本里的命令都打到 bash 里,然后一步步运行,

你猜怎么着?

报错了!(草)

然后我就查这个 jni 的用法,查到了之后,发现,还是报错

为什么呢?环境变量有问题吗

果然有问题。


## 问题解决

(上面的那些就是发发牢骚,这里才是解决问题的部分)

我不想继续描述我是怎么发现这个问题的了,就是作出假设 -> 一步步的推翻自己的假设 -> 反馈思考 -> 做出新的假设

重复上面的过程直到问题解决或者我放弃思考。

到处翻,发现 android_rpc 项目中的 build.gradle 里面指定了一个 task:(其实是报错给我说的这个 build.gradle 出了错)

task buildJni(type: Exec, description: 'Build JNI libs') {
    commandLine 'sh', 'src/main/jni/build.sh'
}

这个 task 的意思是执行 build.sh 这个 script (刚才我们发现问题的那个脚本)

但是这个 script 里面的 javah 那句话(JNI的命令)会提示找不到 class file ‘org.apache.tvm.LibInfo’

奇怪的是 jar 包里有 LibInfo.class 这个文件,而且我去看了一下 tvm/jvm/core 文件夹里面,也是有 LibInfo.java 的,所以不应该是我们的包的问题,应该是路径什么的出了错。

build.sh 里面的变量打印出来发现,如果我在 tvm/apps/android_rpc/ 这个工作目录里,执行 gradle clean build 的话,$ROOT_DIR 的值并不是它应该有的值,$ROOT_DIR的值应该是 tvm/apps/android_rpc, 也就是这个项目的路径。然而我把这个值打印出来发现, $ROOT_DIR 的值是系统的根目录,在根目录里肯定找不到 LibInfo 啊!

android_rpc/app/src/main/jni 这个工作目录执行的话, ROOT\DIR="$CURR_DIR/../../../../../.." 正好跳到 android_rpc 里

然后我手工执行了这个sh,在 build.gradle 里把这个行为给注释掉了

成功!


## 总结

其实一开始,在 android_rpc 这个目录里执行 gradle clean build 是可以成功编译出文件的,但是在后面签名的时候给我报了个无法找到什么什么类的错误,然后我决定编译 android_deploy 试试,发现成功了,签名也正常,在 Android 10 手机上也可以正常运行,我就觉得肯定是这个项目的问题。

后来我再次尝试编译 android_rpc 的时候,出现了文章中描述的问题,技艺不精,导致这么长时间才解决这个问题,期间也查阅了大量的资料,中途也想过放弃,但是还是坚持下来了。最终把问题分析过程以及思路整理成这篇文章,希望后人遇到相关问题可以通过这篇文章节约大量时间。