工具安装
- NDK,(下载地址:http://tools.android-studio.org/)
- CMake
交叉编译方式
- 一是用NDK自带的工具链
- 二是使用独立工具链
方式一步骤
一、按照JNI的实现方式建一个工程
JNI的实现大概有以下几步:
- 编写带有 native 方法的 Java 类
- 生成该类扩展名为 .h 的头文件
- 创建该头文件的 C/C++ 文件,实现 native 方法
- 将该 C/C++ 文件编译成动态链接库
- 在Java 程序中加载该动态链接库
最后建好的工程目录如下图所示
MyJni类是一个带native方法的java类
Navive.c是实现native方法的本地类
内容如下:
#include <jni.h>
#include <android/log.h>
#ifndef _Included_com_jni_MyJni
#define _Included_com_jni_MyJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_jni_MyJni
* Method: callNative
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_jni_MyJni_callNative
(JNIEnv * env, jobject obj){
__android_log_print(ANDROID_LOG_DEBUG,"Native.c","Hello! I am in native.\n");
int i = 9;
return (jint)i;
}
#ifdef __cplusplus
}
#endif
#endif
仅打印了一句日志。
CMakeLists.txt的内容如下:
cmake_minimum_required(VERSION 3.4.1)
add_library(myso SHARED Native.c)
set_target_properties(myso
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}/lib")
include_directories(/usr/lib/jvm/java-8-oracle/include /usr/lib/jvm/java-8-oracle/include/linux)
target_link_libraries(myso
log)
添加了一个myso的动态库,输出到c目录下的lib目录中(实际输出的名字叫:libmyso.so)
至此,如果不需要交叉编译的话进入build目录下执行下面两条命令就可以生成so包了(目前build只是个空目录)
$ cmake ..
$ make
不过这个so包只能在当前pc上使用,不能用在手机上(实际上这个例子按上面的方法执行是会报错的,因为用到了android的日志,会找不到头文件的,这里只是说明一下本地编译与交叉编译的区别)。如果要交叉编译就要配置交叉编译环境,这就是今天的重头戏。
二、配置交叉编译环境
写一个脚本来记录这些参数,在build目录下新建configuer.sh文件,内容如下:
/home/wxyz/Android/Sdk/cmake/3.10.2.4988404/bin/cmake \
-DANDROID_ABI=armeabi-v7a \
-DANDROID_PLATFORM=android-15 \
-DCMAKE_BUILD_TYPE=Debug \
-DANDROID_NDK=/home/wxyz/Android/Sdk/ndk-bundle \
-DCMAKE_TOOLCHAIN_FILE=/home/wxyz/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake \
-DANDROID_TOOLCHAIN=clang ..
这里对各个参数作个解释:
ANDROID_ABI 是cpu架构
ANDROID_PLATFORM是支持的最低android平台
ANDROID_NDK是ndk的根目录
CMAKE_TOOLCHAIN _FILE是工具链文件,这个参数非常重要,这里面还配置了很多其它参数。
ANDROID_TOOLCHAIN是C/C++编译器,可选Clang和gcc,官网推荐clang
最后还有两个点,代表上一级目录,即CMakeLists.txt所在的目录
在build目录下执行这个脚本,再执行make命令,可用于android的so包就出来了。
方式二步骤
主要包含以下两个步骤:
- 编译独立工具链
- 使用独立工具链编译so包
一、编译独立工具链
编译独立工具链是利用$NDK/tools下的 make-standalone-toolchain.sh 脚本来生成独立的交叉编译工具链,先用 –help 参数来看一下具体用法
参数不多,有几个还是不再使用的,主要的只有以下几个:
- –toolchain=<name> 指定toolchain,在 $NDK/toolchains 目录下可以看到所有支持的编译链工具,根据目标cpu架构进行选择。
- –arch=<name> 指定目标cpu架构
- –platform=<name> 指定android平台,默认是[android-14]
好,现在来指定一下这几个参数,
- –toolchain=arm-linux-androideabi-4.9
- –arch=arm
- –platform=android-15
然后运行这个脚本,稍等片刻就能看到如下的结果:
二、编译so包
新建一个jni工程,目录如下方式一
CMakeLists.txt中的内容就是重点了,这里面指定了刚刚编译好的独立工具链,内容如下:
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
# Android 5.0 以上需要在此处设置 PIE
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie")
# 配置使用 NDK Standalone Toolchain 编译
set(NDK_STANDALONE_TOOLCHAIN /tmp/ndk-hm/arm-linux-androideabi)
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 21)
set(CMAKE_C_COMPILER ${NDK_STANDALONE_TOOLCHAIN}/bin/clang)
set(CMAKE_CXX_COMPILER ${NDK_STANDALONE_TOOLCHAIN}/bin/clang++)
set(CMAKE_FIND_ROOT_PATH ${NDK_STANDALONE_TOOLCHAIN})
# 使用 NDK 提供的头文件
add_definitions("--sysroot=${NDK_STANDALONE_TOOLCHAIN}/sysroot")
add_library(myso SHARED CTest.c)
set_target_properties(myso
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}/lib")
include_directories(/home/hm/JDK/jdk1.8.0_151/include /home/hm/JDK/jdk1.8.0_151/include/linux)
target_link_libraries(myso
log)
进入build目录,执行一下:
~/cmake_sample/cross_for_android/build$ cmake ../c/
~/cmake_sample/cross_for_android/build$ make
进入c/lib目录看一下结果:
嗯,so包已经出来了,接下来建个工程验证一下,看看这个so包能不能用。