在命令行下用cmake交叉编译可在android中运行的so包

 

工具安装

  1. NDK,(下载地址:http://tools.android-studio.org/)
  2. CMake

交叉编译方式

  • 一是用NDK自带的工具链
  • 二是使用独立工具链

方式一步骤

一、按照JNI的实现方式建一个工程

JNI的实现大概有以下几步:

  1. 编写带有 native 方法的 Java 类
  2. 生成该类扩展名为 .h 的头文件
  3. 创建该头文件的 C/C++ 文件,实现 native 方法
  4. 将该 C/C++ 文件编译成动态链接库
  5. 在Java 程序中加载该动态链接库

最后建好的工程目录如下图所示

在命令行下用cmake交叉编译可在android中运行的so包_第1张图片

MyJni类是一个带native方法的java类

Navive.c是实现native方法的本地类 
内容如下: 

#include 
#include 

#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包就出来了。 
在命令行下用cmake交叉编译可在android中运行的so包_第2张图片

方式二步骤

主要包含以下两个步骤:

  • 编译独立工具链
  • 使用独立工具链编译so包

一、编译独立工具链

编译独立工具链是利用$NDK/tools下的 make-standalone-toolchain.sh 脚本来生成独立的交叉编译工具链,先用 –help 参数来看一下具体用法

在命令行下用cmake交叉编译可在android中运行的so包_第3张图片

参数不多,有几个还是不再使用的,主要的只有以下几个:

  • –toolchain= 指定toolchain,在 $NDK/toolchains 目录下可以看到所有支持的编译链工具,根据目标cpu架构进行选择。
  • –arch= 指定目标cpu架构
  • –platform= 指定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目录看一下结果:

在命令行下用cmake交叉编译可在android中运行的so包_第4张图片

嗯,so包已经出来了,接下来建个工程验证一下,看看这个so包能不能用。
 

你可能感兴趣的:(android,编译工具,Cmake)