Rokid交叉编译指引(包含jni编译so库)

Rokid交叉编译指引(包含jni编译so库)

一、添加一个项目

参照 “Rokid系统新增或修改模块(应用)”这篇文章

二、添加一个jni项目

与第一点类似,但是在CMakeLists.txt中指明是生成动态连接库,

1.需要增加两个头文件jni.h jni_md.h

2.需要按照jni的规范,写好提供给java的入口函数,函数名有要求,文件名无要求

实例一

  1. 要求:
    把以下程序编译成rokid设备可以使用的应用

    1
    2
    3
    4
    5
    // haha/haha.c
    #include <stdio.h>
    int main(){
    printf("hello haha\n");
    }
  2. 配置Rokid工程
    1). 在rokid_br_external/package下创建目录haha,创建两个文件Config.in和haha.mk,即:

    > rokid_br_external/package/haha/Config.in
    >
    > rokid_br_external/package/haha/haha.mk
    

    2). 同时在rokid_br_external/package/haha/Config.in文件中增加以下内容

    1
    2
    config BR2_PACKAGE_HAHA
    bool "haha program"

    3). 在rokid_br_external/Config.in下增加一行

    1
    source "$BR2_EXTERNAL_ROKID_PATH/package/haha/Config.in"

    4). 在rokid_br_external/configs/rokid_common_packages.frag中增加一行

    1
    BR2_PACKAGE_HAHA=y

    5). 在robot/services下增加源代码目录haha

    > robot/services/haha
    

    6). 编写rokid_br_external/package/haha/haha.mk下的内容

    1
    2
    3
    4
    5
    6
    7
    8
    HAHA_SITE = $(call qstrip,$(BR2_EXTERNAL_ROKID_PATH)/../robot/services/haha)
    HAHA_SITE_METHOD = local
    define HAHA_INSTALL_TARGET_CMDS
    #暂时不增加安装应用的指令
    endef
    #假定他是一个cmake构建的项目
    $(eval $(cmake-package))

    7). 到robot/services/haha源代码目录下编写相应的代码

    1)). 编写haha.c文件
    2)). 编写CMakeLists.txt文件
    3)). 两个文件的内容如下:
    
        
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //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). 编译:

    > 保证之前已经完整编译过整个系统,之后编译指令如下
    
    
    1
    2
    3
    4
    5
    source rokid_br_external/build/envsetup.sh
    lunch #只能选7
    make haha #只编译haha项目

    9). 结果

    1. 在output/banban_m2_a113/build/haha下会有相应的编译结果,可执行文件为haha
    2. 把haha文件push到rokid系统中,并用chmod更改他的执行权限
    3. 然后运行就可以得到打印“hello haha”的结果
    

实例二

  1. 要求:

    把实例一中的main函数改成普通函数,并提供给java使用

  2. 根据实例一中的第2点配置工程中的i-vii步骤生成haha-jni工程

    • 其中有部分需要修改:
      1). robot/services/haha_jni.c修改一下:main()改为test()

      1
      2
      3
      4
      5
      6
      //haha_jni.c 源代码,
      #include <stdio.h>
      void test(){
      printf("hello haha");
      }

      2). robot/services/CMakeLists.txt修改一下,

      1
      2
      3
      4
      5
      6
      7
      8
      //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_library

      3). 编译及结果

      编译指令同上

      此时在output/banban_m2_a113/build/haha_jni下面生成libhaha_jni.so文件

      4). 此时是普通的so文件,还不能被Java所调用。

  3. 正常情况下jni的头文件是不需要手动生成的,一般是通过java文件自动生成的
    1). jni java侧文件HahaJni.java如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class HahaJni{
    static{
    System.loadLibrary("haha_jni");
    }
    public static native void test();//此方法用于调用jni层的函数
    public static void main(String[] args){
    HahaJni.test();
    }
    }

    2). javah自动生成头文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    //直接用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 __cplusplus
    extern "C" {
    #endif
    /*
    * Class: HahaJni
    * Method: test
    * Signature: ()V
    */
    JNIEXPORT void JNICALL Java_HahaJni_test
    (JNIEnv *, jclass);
    #ifdef __cplusplus
    }
    #endif
    #endif
  4. 根据上述头文件生成对应的源代码文件HahaJni.cpp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    //HahaJni.cpp的内容如下
    #include <HahaJni.h>
    #ifdef __cplusplus
    extern "C" {
    #endif
    void 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
  5. 增加jni相关的头文件,需要在jdk或才jre中拿到这两个文件jni.h和jni_md.h

    • robot/services/jni.h
    • robot/services/jni_md.h
  6. 修改robbot/service/CMakeLists.txt中的编译参数,增加相应的头文件目录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #修改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
  7. 编译

    • 同上
    • HahaJni.java的编译

      1
      2
      #编译生成HahaJni.class
      javac HahaJni.java
  8. 结果

    • 此时在output/banban_m2_a113/build/haha_jni下面生成libhaha_jni.so文件
    • 此文件可以给java调用
  9. 运行

    • 把HahaJni.class和libhaha_jni.so文件放到rokid系统根目录
    • 假设jre放置/data/下,刚运行指令如下

      1
      /data/jre/bin/java -Djava.library.path=. HahaJni
    • 此时结果出现“hello haha”

  • 实例一实现了rokid系统下的普通c/c++程序的编译、运行
  • 实例二实现了rokid系统下普通动态连接库的编译及java使用的动态连接库的编译及相应的运行。