Android-CMake语法简介(Android.mk和CMakeLists.txt)
前言
Android NDK以前默认使用Android.mk与Application.mk进行构建,但是在Android Studio2.2之后推荐使用CMake进行编译。
CMake是跨平台编译工具,全称为cross platform make,内建c、c++、java自动相依性分析功能。NDK通过工具链支持CMake,工具链文件是用于自定义交叉编译工具链的CMake文件。用于NDK的工具链位于<NDK>/build/cmake/android.toolchain.cmake
,关于CMake更多详情请参考官网:cmake官网。下面对比下Android.mk与CMakeLists.txt的语法。
更详细脚本分析可查看博客:NDK编译脚本分析
一、Android.mk语法
以动态库编译hello模块为例,完整脚本如下:
1 | WORKING_DIR := $(call my-dir) |
1、LOCAL_MODULE
声明模块名称,例如这里编译出来的动态库名称为libhello.so。
2、LOCAL_SRC_FILES
声明源文件列表,文件之间用空格分开,需要换行时使用’’换行符。
3、LOCAL_C_INCLUDES
声明头文件路径,例如$(LOCAL_PATH)/xxx
4、LOCAL_CPP_EXTENSION
指定C++源文件除.cpp以外的文件扩展名,例如:LOCAL_CPP_EXTENSION := .cpp .cxx .cc
5、LOCAL_CPP_FEATURES
指定依赖c++的某些功能,例如RTTI(运行时类型信息):LOCAL_CPP_FEATURES := rtti
使用c++异常检测:LOCAL_CPP_FEATURES := exceptions
6、LOCAL_CFLAGS
在编译c和c++源文件时编译系统要传递的编译器标记,即指定额外的宏定义或编译选项。LOCAL_CFLAGS += -I<path>
7、LOCAL_STATIC_LIBRARIES
共享静态库,作为第三方库被引用LOCAL_STATIC_LIBRARIES := libavcodec libavutil libavformat libavfilter
8、LOCAL_SHARED_LIBRARIES
共享动态库,与共享静态库一样作为第三方库被引用LOCAL_SHARED_LIBRARIES := libffmpeg
9、LOCAL_LDLIBS
额外链接器,一般为系统库,使用-l来引用LOCAL_LDLIBS := -lz -lm
10、 LOCAL_ARM_MODE
ndk默认使用thumb模式来生成目标二进制文件,每条指令为16位宽。也可以指定为ARM模式,来生成32位ARM的目标文件:LOCAL_ARM_MODE := arm
11、LOCAL_ARM_NEON
用于开启NEON指令加速,仅对armeabi-v7a平台有效。为模块开启NEON:LOCAL_ARM_NEON := true
为单独源文件开启NEON:LOCAL_SRC_FILES := hello.c.neon
12、TARGET_ARCH
用于指向CPU架构,包括x86、x86_64、armeabi-v7a、 arm64-v8a
13、TARGET_PLATFORM
目标平台,对应Android API级别号,例如Android5.0系统镜像对应Android API级别21:android-21
14、打印信息
可用warning、debug、info、error级别来打印信息,如果是打印error信息,会终止编译。以warning为例:$(warning 'This is a test')
15、if条件判断
采用ifeq关键字,然后左右变量放在括号体内,用逗号分隔:
1 | ifeq($(TARGET_ABI), arm64-v8a) |
二、Application.mk语法
Android.mk依赖Application.mk文件进行编译,一般Application.mk脚本如下所示:
1 | APP_STL := c++_static |
1、APP_ABI
与Android.mk的TARGET_ABI对应,包括CPU架构有:x86、x86_64、armeabi-v7a、arm64-v8a,支持所有平台这样表示:APP_ABI := all
2、APP_BUILD_SCRIPT
指向编译脚本的路径,一般Android.mk和Application.mk都位于jni目录,默认指向jni/Android.mk路径,如果是其他路径,需要使用此变量来指定绝对路径:APP_BUILD_SCRIPT := /xx/xx/Android.mk
3、APP_OPTIM
编译优化选项,调试模式为debug,发布模式为release。在调试模式下,会保留symbol符号表;在发布模式下,会开启优化,去掉symbol符号表。
4、APP_PLATFORM
指定编译平台,面向于Android API级别,对应gradle声明的minSdkVersion。如果不声明,默认为ndk支持的最低API版本
5、APP_STL
声明使用c++的标准库,默认为system STL。其他选项包括c++_static、c++_shared和none
三、CMakeLists.txt语法
以编译hello模块以及依赖ffmpeg模块为例:
1 | cmake_minimum_required(VERSION 3.4.1) |
1、add_library
传递三个参数,第一个参数是模块名称,第二个参数是SHARED或者STATIC。如果是源文件模块,第三个参数是源文件列表;
如果是第三方库,第三个参数是IMPORTED。
2、set_target## _properties
用于指定第三方库路径,IMPORT_LOCATION一般是指向src/main/cpp目录
3、include_dir## ectories
用于指定头文件路径,头文件路径可以有多个
4、find_libra## ry
用于查找系统库,比如Android系统的log日志库
5、target_link## _libraries
链接目标库,把依赖库都链接到目标库中
6、if条件判断##
与Android.mk稍有差异,CMake采用if…MATCHES形式,例如:
1 | if(${CMAKE_ANDROID_ARCH_ABI} MATCHES "armeabi-v7a") |
7、打印日志
与Android.mk不同的是,CMake采用message函数来打印日志,括号体传入msg内容message("hello, cmake")
8、命令行参数
命令行参数前面统一加上-D,常用的参数:
- -DANRDOID_ABI :android的ABI架构平台
- -DANDROID_NDK :ndk路径
- -DANDROID_ARM_MODE :arm模式/thumb模式
- -DANDROID_ARM_NEON :是否开启arm neon加速,针对armeabi-v7a平台
- -DANDROID_TOOLCHAIN :编译工具链
- -DANDROID_NATIVE_API_LEVEL :与ANDROID_PLATFORM相同,对应minSdkVersion
- -DCMAKE_BUILD_TYPE :编译类型,debug或release
- -DCMAKE_MAKE_PROGRAM :编译程序
- -DCMAKE_TOOLCHAIN_FILE :编译文件
9、命令行编译
以cmake作为关键字,后面带着指定参数,示例如下:
1 | cmake \ |
四、ndk编译配置
1、Android.mk方式配置
在gradle的defaultConfig配置ndk:
1 | defaultConfig { |
然后配置jni源文件路径:
1 | sourceSets { |
另外配置Android.mk文件绝对路径:
1 | externalNativeBuild { |
2、CMake方式配置
前两步与Android.mk方式一样,配置脚本路径稍有差异:
1 | externalNativeBuild { |
另外在defaultConfig设置cppFlags:
1 | externalNativeBuild { |
五、ndk编译过程
1、ndk-build编译
如上图所示,在命令行输入ndk-build后,会根据声明所支持的平台依次编译。首先是armeabi-v7a平台架构,把hello.c源文件编译成hello目标文件,然后链接成libhello.so动态库,最终安装到libs/armeabi-v7a目录下。
2、cmake在Gradle中编译
如上图所示,编译arm64-v8a平台架构的hello模块。首先把hello.c源文件编译成hello.c.o目标文件,然后链接成libhello.so动态库。生成的debug模式动态库在/build/intermediates/cmake/debug/obj/arm64-v8a目录下。
参考链接:https://blog.csdn.net/u011686167/article/details/106458899