Android.mk 用法

一、Android 中jni有两种编译方案,一种是传统的ndkbuild,一直是当前推荐使用用的cmake

1、编译配置:

  • ndkbuild中,采用Android.mk+Application.mk+src的方式
  • cmake中,采用CMakeList.txt + src的方式

在创建项目时选择了include C++ support 则会创建包含cmake的编译模板

2、编译方式

gradle 对两种编译方式进行了统一;只需要在 module 下的build.gradle 中添加

externalNativeBuild {
    ndkBuild {
        path "src/main/jni/Android.mk"
    }
}

或者

externalNativeBuild {
    cmake {
        path "CMakeLists.txt"
    }
}

即可。其中path指定的是两种编译环境下所需配置文件的地方

此外:

ndkbuild 编译情况下可在android->defaultConfig 中添加

ndk{
    abiFilters "armeabi-v7a"
}

用于设置NDKOption,如abiFilters等;
cmake 编译情况下可在android->defaultConfig 中添加

externalNativeBuild {
    cmake {
        abiFilters "armeabi-v7a"
        cppFlags ""
    }
}

用于设置ExternalNativeNdkBuildOptions,如abiFilters、cppFlags等;

二、ndkbuild 编译模式介绍

ndk-build 是android-ndk中的一个指令,如下图


image.png

使用ndk-build编译时,需指定NDK_PROJECT_PATH项目目录,APP_BUILD_SCRIPT(android.mk)位置,NDK_APPLICATION_MK(Application.mk)位置,以及NDK_LIBS_OUT(so输出位置)和NDK_OUT(输出目录)

ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk NDK_LIBS_OUT=./sample/breakpad/libs NDK_OUT=./sample/breakpad/obj

ndk-build clean 清除编译缓存:

ndk-build clean NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk NDK_LIBS_OUT=./sample/breakpad/libs NDK_OUT=./sample/breakpad/obj

1、 Android.mk 和 Application.mk文件的作用

  • Android.mk 文件是用来配置 jni编译的 源文件输入、编译参数、编译输出产物 等等。
  • Application.mk 文件是用来 指定平台有关的配置信息。比如编译的平台版本、平台架构、使用的标准库 等等

2、Android.mk 文件的一般组织结构,如图所示

image.png
  • 每一个库的源文件放在同一个文件夹下面,比如上面的libusb库的源文件放在libusb子目录下,example库的源文件放在example子目录下。
  • 每一个子目录下(对应每一个库) 都有一个自己的Android.mk 文件,这样每一个Android.mk可以配置该库编译时的源文件输入、编译参数、编译输出产物类型等等。
  • jni目录下有一个总的Android.mk文件和一个Application.mk文件,这个总的Android.mk文件会调用每一个子目录下的Android.mk文件去完成编译工作。

3、Android.mk 文件的一般写法

3.1、 总的Android.mk文件:

    include $(call all-subdir-makefiles) 
    //没错,就只有一句。这句话的意思就是调用每一个子目录下的makefile文件,也就是Android.mk文件

3.2、libusb下的Android.mk文件:

  LOCAL_PATH:= $(call my-dir)  //获取当前目录路径,也就是该Android.mk所在的目录路径,说的准确一点其实是最后一次include的Android.mk的路径,一般把这句话放在最开始。

    include $(CLEAR_VARS)    //清除或者说重置 除了LOCAL_PATH之外的变量的值,比如LOCAL_SRC_FILES变量的值等等

    #$(warning " LOCAL_PATH is $(LOCAL_PATH) ")  //使用warming函数,打印$(LOCAL_PATH)的值,只是用于调试作用,#表示注释

    LOCAL_SRC_FILES := \    //指定源文件,多个源文件使用空格隔开,这里换行(每行最后需要使用 \ 反斜杠 表示衔接作用)只是为了容易阅读

        $(LOCAL_PATH)/core.c \

        $(LOCAL_PATH)/descriptor.c \

        $(LOCAL_PATH)/hotplug.c \

        $(LOCAL_PATH)/io.c \

        $(LOCAL_PATH)/sync.c \

        $(LOCAL_PATH)/strerror.c \

        $(LOCAL_PATH)/os/linux_usbfs.c \

        $(LOCAL_PATH)/os/poll_posix.c \

        $(LOCAL_PATH)/os/threads_posix.c \

        $(LOCAL_PATH)/os/linux_netlink.c

    LOCAL_C_INCLUDES += \    //指定头文件

        $(LOCAL_PATH)/.. \

        $(LOCAL_PATH) \

        $(LOCAL_PATH)/os

    LOCAL_EXPORT_C_INCLUDES := \    //导出头文件,这样其他地方需要就可以直接include进来,比如在example里的某个源文件需要libusb.h头文件,可以直接include <libusb.h> 或者 include "libusb.h"

        $(LOCAL_PATH)

    LOCAL_LDLIBS := -llog    //使用liblog.so动态库,以-l开头,log是库去掉lib前缀和so后缀之后的名称

    LOCAL_MODULE := usb-1.0  //生成so库的名称,最终的名称是libusb-1.0.so(java代码里使用:System.loadLibrary("usb-1.0")),如果以lib开头了系统不再自动追加lib前缀了

    include $(BUILD_SHARED_LIBRARY)  //指定需要生成的是so动态库,如果是 include $(BUILD_STATIC_LIBRARY) 表示需要生成的是.a静态库

3.3、 example下的Android.mk文件:

LOCAL_PATH := $(call my-dir)    //获取自己本地路径,也就是自己的Android.mk文件所在的路径
    include $(CLEAR_VARS)    //清除 除了LOCAL_PATH之外的变量的值
    LOCAL_C_INCLUDES += $(wildcard $(LOCAL_PATH)/include/*.h)    //指定头文件,使用wildcard通配符函数,这里是一种通用的万能写法
    LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/src/*.c)     //指定源文件,使用wildcard通配符函数,这里是一种通用的万能写法
    #$(warning " LOCAL_SRC_FILES is $(LOCAL_SRC_FILES) ")    //打印$(LOCAL_SRC_FILES),只是调试作用,#表示注释掉了
    LOCAL_SHARED_LIBRARIES := usb-1.0    //依赖libusb-10.so动态库,多个依赖时使用空格隔开,这样就会先去编译生成libusb-10.so动态库,然后再编译生成libexample.so动态库
    LOCAL_MODULE := example    //指定生成so库的名称,最终的名称是libexample.so
    include $(BUILD_SHARED_LIBRARY)    //指定需要生成的是so动态库

      附:wildcard函数有时会和subst函数结合使用,比如SDL库里的LOCAL_SRC_FILES如下所示(省略了一部分):         

        LOCAL_SRC_FILES := \
          $(subst $(LOCAL_PATH)/,, \        //替换操作。替换$(LOCAL_PATH) 的值的空,比如:$(subst OLD, NEW, TEXT),即将字符串TEXT中的子串OLD变为NEW
          $(wildcard $(LOCAL_PATH)/src/*.c) \    //src下的所有.c源文件
          $(wildcard $(LOCAL_PATH)/src/audio/*.c) \    //src下的audio下的所有.c源文件
          $(wildcard $(LOCAL_PATH)/src/audio/android/*.c))    //src下的audio下的android下的所有.c源文件

3.4、 Application.mk 文件的写法

APP_OPTIM := release  //生成release版本的动态库
TARGET_PLATFORM := android-16  //针对android sdk16生成动态库,也是最小sdk版本
APP_STL := stlport_static  //指定标准库。此处使用stlport_static标准库,如果include <string.h>报错找不到string.h头文件,一般是忘记指定标准库,常用的还有 APP_STL := gnustl_static表示使用gnu标准库

APP_ABI := all  //生成哪些架构的so动态库,all表示所有的,包括armeabi、armeabi-v7a、arm64-v8a、mips、mips64、x86、x86_64,也可以指定需要的,比如APP_ABI :=armeabi armeabi-v7a,多个之间空格隔开

# Workaround for MIPS toolchain linker being unable to find liblog dependency
# of shared object in NDK versions at least up to r9.
APP_LDFLAGS := -llog  //提示链接log动态库,注释里的意思是生成MIPS架构时需要显示指定

三、参考文章

Android.mk语法:
https://www.jianshu.com/p/bee78310e420
Android.mk 文件 和Application.mk 文件的具体作用和写法
https://blog.csdn.net/weixin_30808575/article/details/97419067

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 独自徘徊在茫茫人海中 忽感患得患失 内心惶恐不平 害怕黑夜将我侵袭 害怕孤独无处可依...
    木栖235阅读 357评论 1 10
  • 2017年7月,我从研究生院校毕业,正式成为了三门峡市陕州区第一高级中学的一名语文教师,青椒计划也在不久之后出现在...
    陕县053张琳阅读 265评论 0 0
  • 好的字都是练出来的,而练字必须临帖,临帖须用功! 临帖,一定要把握对每一种书法的感觉,要用眼睛去看,认真去...
    夏小麦_ece4阅读 1,865评论 1 1
  • 2016年10月15日 Lee公子 文 于重庆 知识比信息有价值在哪里? 什么样的知识才是有真正高价值的知识? 读...
    Lee公子阅读 640评论 1 0
  • 她经历过年轻美貌 和我不一样的教育 有些少的教育 现在被家庭束缚 换个角度想也许是我束缚了她 被我束缚在这一片小地...
    十八岁的张雪纯阅读 374评论 0 1