背景介绍
- 什么是交叉编译(Cross_Compile)?
所谓"交叉编译",是指编译源代码的开发编译平台和执行源代码编译后程序的目标运行平台是两个不同的平台。
- 为什么要使用交叉编译呢?
1、目的平台上无法实现本地编译(native compile),主要因为目的平台上的资源贫乏(内存小、无显示设备等);
2、有能力实现源代码编译的平台CPU架构或操作系统与目标平台不同。
干货分享:欢迎收藏点赞加关注
windows环境交叉编译
一、MinGW和NDK工具安装和环境配置
讲MinGW和NDK之前,我们先要了解一下如何在linux环境下实现Android平台交叉编译的工具。
linux环境下编译Android平台可执行程序/算法库需要用到gcc编译器和NDK工具。Linux一般自带gcc编译器,不需要额外再下载安装,可以通过gcc –v查看其版本号。NDK (原生开发套件) 是一套工具,使您能够在 Android 应用中使用 C 和 C++ 代码。
下载地址:最新版本android-ndk-r23b-linux.zip
OK,那在windows环境下,需要用到MinGW和NDK工具。
MinGW(Minimalist GNU for Windows)提供了一套简单的再windows环境下基于gcc的开发环境。是将gcc编译器和GNU Binutils移植到windows平台下的产物,包括一系列头文件、库和可执行文件。在windows平台模拟了linux平台gcc的开发环境。
NDK工具实现的功能相同:在 Android 应用中使用 C 和 C++ 代码。
下载地址:最新版本android-ndk-r23b-windows.zip
MinGW和NDK工具安装好之后,需要在系统环境变量中添加PATH :
C:\…\MinGW\bin
C:\…\ndk\android-ndk-r23b
二、编译过程
交叉编译可以选择通过 ndk-build(Android.mk /Application.mk)的方式或者CMake(CMakeLists.txt)的方式。本文重点讲述一下ndk-build方式,CMake是Android Studio 编译原生库的默认构建工具,参考:
1.Android.mk 和Application.mk脚本配置
在刚才安装的NDK目录 C:\…\ndk\android-ndk-r23b\ 下创建一个jni文件夹。并将C/C++代码复制到该路径下,并在该路径下创建Android.mk 和Application.mk文件。
展示一个样例:
Android.mk:
LOCAL_PATH := $(call my-dir) # 指定了当前.mk文件的路径
include $(CLEAR_VARS) # 清空了除了LOCAL_PATH之外的所有LOCAL_xxx变量的值
LOCAL_MODULE_CLASS := STATIC_LIBRARIES # 将用于决定编译时的中间文件存放的位置
LOCAL_MODULE := libtest # 编译生成的目标名
LOCAL_MODULE_TAGS := optional # 该模块在所有版本下都编译
判断目标CPU架构名,如果为arm,则添加配置块,与CPU架构版本无关
ifeq ($(TARGET_ARCH), arm)
LOCAL_ARM_MODE := thumb
LOCAL_CFLAGS += -mthumb
endif
判断当前的cpu/abi的类型,取值包括:
32位:armeabi、armeabi-v7a、x86、mips 64位:arm64-v8a、x86_64、mips64
ifeq ($(TARGET_ARCH_ABI), $(filter arm64-v8a armeabi-v7a, $(TARGET_ARCH_ABI)))
LOCAL_CFLAGS += -D__ARCH_ARM__
endif
判断abi类型
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS += -D__ARMV7__
LOCAL_ARM_MODE := arm
else
LOCAL_ARM_MODE := arm
endif
头文件
INCLUDE_PATH := $(LOCAL_PATH)/src
LOCAL_C_INCLUDES := \ # 额外的C/C++编译头文件路径,用LOCAL_PATH表示本文件所在目录
$(INCLUDE_PATH)/A/
$(INCLUDE_PATH)/B/ \
源文件 wildcard 一句话引入单个目录(不包括子目录)下的所有c/cpp源文件
SRC_PATH := $(LOCAL_PATH)/src
MY_CPP_LIST := $(wildcard $(LOCAL_PATH)/main.c)
MY_CPP_LIST += $(wildcard $(SRC_PATH)/A/.c) #追加到变量MY_CPP_LIST 里
MY_CPP_LIST += $(wildcard $(SRC_PATH)/A/.cpp)
MY_CPP_LIST += $(wildcard $(SRC_PATH)/B/.c)
MY_CPP_LIST += $(wildcard $(SRC_PATH)/B/.cpp)
LOCAL_SRC_FILES := (LOCAL_PATH)/%=%) # 编译该模块需要的源文件
(LOCAL_PATH)/%=%)语法的意思是对MY_CPP_LIST中每一项,应用冒号后面的规则,规则是 (LOCAL_PATH)/开头的项,并截取后面部分
LOCAL_CFLAGS += -DHAVE_CONFIG_H -D__ARM_NEON -DNR_NEON # 宏定义 -DXXX
LOCAL_CFLAGS += -mfloat-abi=softfp -mfpu=neon # 使能neon指令集
LOCAL_CFLAGS += -fPIE -fPIC # 兼容 5.0+
LOCAL_LDFLAGS += -fPIE -pie
LOCAL_CPPFLAGS := -std=c++11 # 支持 c++ 11标准 需要在Application.mk中加入:APP_STL := gnustl_static
#LOCAL_CPPFLAGS += -std=c++1y # 支持 c++ 14标准
include $(BUILD_EXECUTABLE) # 编译可执行文件
#include $(BUILD_STATIC_LIBRARY) # 表示编译成静态库
#include KaTeX parse error: Expected 'EOF', got '#' at position 24: …HARED_LIBRARY) #̲ 表示编译成动态库</code…->#
1、 将可执行程序 push到手机中
adb push <电脑上的文件路径> <设备里的路径>
2、adb shell 进入手机,并cd 到可执行程序的路径下
3、chmod 777 <可执行程序名称>
4、./<可执行程序名称> 运行
5、查看输出结果是否符合预期。
应用场景:
例如:neon优化之后,需要在arm平台进行单元测试/模块测试一致性验证等。