cmake使用独立工具链交叉编译可在android中运行的so包
在在命令行下用CMake交叉编译可在android中运行的so包一文中说了一下使用NDK自带的工具链来编译so包,当时讲到还有另一种方法来编译so包,即使用独立工具链来编译,现在就来讲一讲这种方式。主要包含以下两个步骤:
- 编译独立工具链
- 使用独立工具链编译so包
一、编译独立工具链
编译独立工具链是利用$NDK/tools下的 make-standalone-toolchain.sh 脚本来生成独立的交叉编译工具链,先用 –help 参数来看一下具体用法,我的ndk位置放在/home/hm/android_ndk_r15c
参数不多,有几个还是不再使用的,主要的只有以下几个:
- –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
然后运行这个脚本,稍等片刻就能看到如下的结果:
接下来我们根据输出的提示进入/tmp/ndk-hm目录下看看有些什么东西
嗯,只有一个压缩包和一个tmp目录,显然tmp目录是个临时目录,可以删除它,然后解压arm-linux-androideabi.tar.bz2,解压出来是这样子的:
这样独立工具链就编译好了,接下来看看怎么使用它。
二、编译so包
新建一个jni工程,目录如下:
内容都非常简单,其中JTest.java文件的内容如下,就一个带native修饰的方法:
package com.jni;
public class JTest{
public native String getStringFromC();
}
CTest.c文件的内容如下,它是根据JTest.java文件的头文件来编写的,实现了JTest.java中的native方法,打印了一句日志,返回了一个字符串:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <android/log.h>
/* Header for class com_jni_JTest */
#ifndef _Included_com_jni_JTest
#define _Included_com_jni_JTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_jni_JTest
* Method: getStringFromC
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_jni_JTest_getStringFromC
(JNIEnv * env, jobject obj){
__android_log_print(ANDROID_LOG_DEBUG,"CTest.c","Hello World C!\n");
return (*env)->NewStringUTF(env, "I am from CTest.c");
}
#ifdef __cplusplus
}
#endif
#endif
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包能不能用。
三、验证
跟之前一样,建个测试工程,将编译好的so包及JTest.java文件拷到工程中,具体步骤就不多说了,很简单,最后建好的工程目录如下:
在MainActivity.java中调用native方法:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String str = new JTest().getStringFromC();
System.out.println(str);
((TextView)findViewById(R.id.tvHello)).setText(str);
}
}
跑一下工程,看看有没有输出日志:
没问题,返回值没错,在CTest.c中输出的日志也打出来了,说明这个so包是可用的。
最后,上源码:
demo源码:https://github.com/MingHuang1024/CrossCompileForAndroid
测试工程的源码就不上了,需要的可以联系我。
由于水平有限,如果文中存在错误之处,请大家批评指正,欢迎大家一起来分享、探讨!
博客:http://blog.csdn.net/MingHuang2017
GitHub:https://github.com/MingHuang1024
Email:MingHuang1024@foxmail.com
微信:724360018