美文网首页
Android.mk 用法

Android.mk 用法

作者: feifei_fly | 来源:发表于2019-12-18 10:33 被阅读0次

    一、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

    相关文章

      网友评论

          本文标题:Android.mk 用法

          本文链接:https://www.haomeiwen.com/subject/obbynctx.html