Rokid交叉编译指引(包含jni编译so库)
一、添加一个项目
参照 “Rokid系统新增或修改模块(应用)”这篇文章
二、添加一个jni项目
与第一点类似,但是在CMakeLists.txt中指明是生成动态连接库,
1.需要增加两个头文件jni.h jni_md.h
2.需要按照jni的规范,写好提供给java的入口函数,函数名有要求,文件名无要求
实例一
要求:
把以下程序编译成rokid设备可以使用的应用12345// haha/haha.c#include <stdio.h>int main(){printf("hello haha\n");}配置Rokid工程
1). 在rokid_br_external/package下创建目录haha,创建两个文件Config.in和haha.mk,即:> rokid_br_external/package/haha/Config.in > > rokid_br_external/package/haha/haha.mk2). 同时在rokid_br_external/package/haha/Config.in文件中增加以下内容
12config BR2_PACKAGE_HAHAbool "haha program"3). 在rokid_br_external/Config.in下增加一行
1source "$BR2_EXTERNAL_ROKID_PATH/package/haha/Config.in"4). 在rokid_br_external/configs/rokid_common_packages.frag中增加一行
1BR2_PACKAGE_HAHA=y5). 在robot/services下增加源代码目录haha
> robot/services/haha6). 编写rokid_br_external/package/haha/haha.mk下的内容
12345678HAHA_SITE = $(call qstrip,$(BR2_EXTERNAL_ROKID_PATH)/../robot/services/haha)HAHA_SITE_METHOD = localdefine HAHA_INSTALL_TARGET_CMDS#暂时不增加安装应用的指令endef#假定他是一个cmake构建的项目$(eval $(cmake-package))7). 到robot/services/haha源代码目录下编写相应的代码
1)). 编写haha.c文件 2)). 编写CMakeLists.txt文件 3)). 两个文件的内容如下:123456789101112131415//haha.c 源代码#include <stdio.h>int main(){printf("hello haha");}//CMakeLists.txt文件 构建信息如下cmake_minimum_required(VERSION 2.8)project(haha)set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")aux_source_directory(. DIR_SRCS)add_executable(haha ${DIR_SRCS})8). 编译:
> 保证之前已经完整编译过整个系统,之后编译指令如下12345source rokid_br_external/build/envsetup.shlunch #只能选7make haha #只编译haha项目9). 结果
1. 在output/banban_m2_a113/build/haha下会有相应的编译结果,可执行文件为haha 2. 把haha文件push到rokid系统中,并用chmod更改他的执行权限 3. 然后运行就可以得到打印“hello haha”的结果
实例二
- 要求:
把实例一中的main函数改成普通函数,并提供给java使用
根据实例一中的第2点配置工程中的i-vii步骤生成haha-jni工程
其中有部分需要修改:
1). robot/services/haha_jni.c修改一下:main()改为test()123456//haha_jni.c 源代码,#include <stdio.h>void test(){printf("hello haha");}2). robot/services/CMakeLists.txt修改一下,
12345678//CMakeLists.txt文件 构建信息如下cmake_minimum_required(VERSION 2.8)project(haha)set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")aux_source_directory(. DIR_SRCS)add_library(haha_jni ${DIR_SRCS})#动态连接库应该使用add_library3). 编译及结果
编译指令同上
此时在output/banban_m2_a113/build/haha_jni下面生成libhaha_jni.so文件
4). 此时是普通的so文件,还不能被Java所调用。
正常情况下jni的头文件是不需要手动生成的,一般是通过java文件自动生成的
1). jni java侧文件HahaJni.java如下1234567891011class HahaJni{static{System.loadLibrary("haha_jni");}public static native void test();//此方法用于调用jni层的函数public static void main(String[] args){HahaJni.test();}}2). javah自动生成头文件:
123456789101112131415161718192021222324252627//直接用java提供的javah工具就可以生成对应的头文件HahaJni.h//下面的HahaJni为全限定名,如果放在包里请加上对应的包包名javah -d . -jni HahaJni//HahaJni.h的内容如下/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HahaJni */#ifndef _Included_HahaJni#define _Included_HahaJni#ifdef __cplusplusextern "C" {#endif/** Class: HahaJni* Method: test* Signature: ()V*/JNIEXPORT void JNICALL Java_HahaJni_test(JNIEnv *, jclass);#ifdef __cplusplus}#endif#endif根据上述头文件生成对应的源代码文件HahaJni.cpp
1234567891011121314151617181920212223//HahaJni.cpp的内容如下#include <HahaJni.h>#ifdef __cplusplusextern "C" {#endifvoid test();//增加外部函数的声明/** Class: HahaJni* Method: test* Signature: ()V*/JNIEXPORT void JNICALL Java_HahaJni_test(JNIEnv *env, jclass clazz){//调用haha_jni.c的test函数test();}#ifdef __cplusplus}#endif增加jni相关的头文件,需要在jdk或才jre中拿到这两个文件jni.h和jni_md.h
- robot/services/jni.h
- robot/services/jni_md.h
修改robbot/service/CMakeLists.txt中的编译参数,增加相应的头文件目录
123456789101112#修改robbot/service/CMakeLists.txt文件:cmake_minimum_required(VERSION 2.8)project(haha_jni)#增加头文件目录的编译参数set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I.")set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I.")set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")aux_source_directory(. DIR_SRCS)add_library(haha_jni ${DIR_SRCS})#动态连接库应该使用add_library编译
- 同上
HahaJni.java的编译
12#编译生成HahaJni.classjavac HahaJni.java
结果
- 此时在output/banban_m2_a113/build/haha_jni下面生成libhaha_jni.so文件
- 此文件可以给java调用
运行
- 把HahaJni.class和libhaha_jni.so文件放到rokid系统根目录
假设jre放置/data/下,刚运行指令如下
1/data/jre/bin/java -Djava.library.path=. HahaJni此时结果出现“hello haha”
完
- 实例一实现了rokid系统下的普通c/c++程序的编译、运行
- 实例二实现了rokid系统下普通动态连接库的编译及java使用的动态连接库的编译及相应的运行。