cmake使用独立工具链交叉编译可在android中运行的so包

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

评论 4 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

MingHuang1024

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值