美文网首页Android开发
Android.mk简介(9)

Android.mk简介(9)

作者: xcz1899 | 来源:发表于2018-09-04 08:49 被阅读0次

    简介

    Android.mk文件是GNU Make的一小部分,它用来对Android程序进行编译。
    因为所有的android.mk都在同一个GNU Make执行环境中进行执行,而Android.mk中所有的变量都是全局的。因此,应尽量少声明变量。
    一个Android.mk文件可以编译多个模块,模块类型如下:

    1. APK程序

    一般的Android程序,编译打包生成apk文件

    2. JAVA库

    java类库,编译打包生成jar文件

    3. C\C++应用程序

    可执行的C\C++应用程序

    4. C\C++静态库

    编译生成C\C++静态库,并打包成.a文件

    5. C\C++动态库

    编译生成动态库,并打包成.so文,有且只有动态库才能被安装/复制到您的应用软件(APK)包中。

    注意,NDK的Anroid.mk语法同公开发 布的Android平台开源代码的Anroid.mk语法很接近,然而编译系统实现他们的方式却是不同的,这是故意这样设计的,可以让程序开发人员重用外部库的源代码更容易。

    GNU MAKE系统变量

    GNU Make变量在你的Android.mk文件解析之前,就由编译系统定义好了。

    1. CLEAR_VARS: 必须在开始一个新模块之前包含这个脚本:include$(CLEAR_VARS),用于重置除LOCAL_PATH变量外的所有LOCAL_XXX系列变量。
    2. BUILD_SHARED_LIBRARY: 根据所有的LOCAL_XXX变量把列出的源代码文件编译成一个共享库。
      注意,必须至少在包含这个文件之前定义 LOCAL_MODULE 和 LOCAL_SRC_FILES。
    3. BUILD_STATIC_LIBRARY:用于编译一个静态库。静态库不会复制到的APK包中,但是能够用于编译共享库。示例:include $(BUILD_STATIC_LIBRARY),这将会生成一个名为 lib$(LOCAL_MODULE).a 的文件
    4. TARGET_ARCH: 目标 CPU平台的名字, 和 android 开放源码中指定的那样。如果是
      arm,表示要生成 ARM 兼容的指令,与 CPU架构的修订版无关。
    5. TARGET_PLATFORM: Android.mk 解析的时候,目标 Android 平台的名字。详情可参考/development/ndk/docs/stable- apis.txt.
      android-3 -> Official Android 1.5 system images
      android-4 -> Official Android 1.6 system images
    6. TARGET_ARCH_ABI: 暂时只支持armeabi和armeabi-v7a。在现在的版本中一般把这两个值简单的定义为 arm, 通过android平台内部对它重定义来获得更好的匹配。其他的 ABI 将在以后的 NDK 版本中介绍,它们会有不同的名字。注意虽然所有基于ARM的ABI都会把 'TARGET_ARCH'定义成‘arm’, 但是会有不同的‘TARGET_ARCH_ABI’。
    7. TARGET_ABI: 目标平台和ABI的组合,它事实上被定义成$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI) ,在想要在真实的设备中针对一个特别的目标系统进行测试时,会有用。在默认的情况下,它会是'android-3-arm'。

    模块描述变量

    下面的变量用于向系统描述我们自己的模块,它们应该定义在include $(CLEAR_VARS)include $(BUILD_XXX)之间。

    LOCAL_PATH:当前文件的路径,必须在 Android.mk 的开头定义
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES:编译的源文件
    LOCAL_MODULE:模块名称
    LOCAL_MODULE_CLASS:用于制定LOCAL_MODULE_PATH的路径
    LOCAL_MODULE_PATH:模块的生成地址
    
    LOCAL_PACKAGE_NAME:APK应用的名称
    LOCAL_DEX_PREOPT:是否开启odex优化
    LOCAL_CERTIFICATE:当前应用的证书名称
    LOCAL_MODULE_TAGS:模块的标签,eng,user,debug,development,option
    
    LOCAL_STATIC_JAVA_LIBRARIES: 模块依赖的java静态库,最终会打包到apk里面
    LOCAL_JAVA_LIBRARIES:模块依赖的java动态库,比如framework.ja,只是编译的时候引用
    LOCAL_STATIC_LIBRARIES: 模块依赖的c/c++静态库 .a
    LOCAL_SHARED_LIBRARIES:模块依赖的c/c++动态库 .so
    LOCAL_C_INCLUDES: 表示头文件的搜索路径,默认的头文件的搜索路径是LOCAL_PATH目录
    LOCAL_CPP_EXTENSION: 用来指定C++代码文件的扩展名,默认是'.cpp'
    
    LOCAL_CFLAGS: 提供给c/c++编译器额外的编译参数。指定一个附加的包含路径,宏定义,或者编译选项
    LOCAL_CXXFLAGS: 与 LOCAL_CFLAGS同理,针对 C++源文件
    LOCAL_CPPFLAGS: 与 LOCAL_CFLAGS同理,但是对 C 和 C++ source files都适用
    LOCAL_LDLIBS: 编译模块时要使用的附加的链接器选项
    
    include $(BUILD_XXX)
    

    自定义变量

    可以定义其他变量为自己使用,但是不能使用NDK编译系统保留的变量名:

    1. 以 LOCAL_开头的名字(例如 LOCAL_MODULE)
    2. 以 PRIVATE_, NDK_ 或 APP_开头的名字(内部使用)
    3. 小写名字(内部使用,例如‘my-dir’)

    如果为了方便在 Android.mk 中定义自己的变量,建议使用 MY_前缀,一个小例子:

    MY_SOURCES := foo.c
    LOCAL_SRC_FILES += $(MY_SOURCES)
    

    注意:

    1. = 是最基本的赋值,make会将整个mk文件展开后,再决定变量的值。也就是说,变量的值将会是整个mk文件最后被指定的值
    2. := 表示变量的值决定于它在mk文件中的位置,而不是整个mk展开后的最终值。
    3. ?= 是如果没有被赋值过就赋予等号后面的值
    4. += 是添加等号后面的值

    宏函数

    $(call command) 执行宏函数
    my-dir:返回当前Android.mk文件所在的目录路径
    all-subdir-makefiles:返回一个当前my-dir路径子目录中所有Android.mk列表
    all-subdir-java-files:这个目录下的所有.java文件
    this-makefile:返回当前makefile的路径,即这个函数调用的地方
    parent-makefile:返回调用树中父makefile的路径,即包含当前makefile的makefile的路径

    重点语法详解

    include $(CLEAR_VARS)
    CLEAR_VARS 由编译系统提供(可以在AOSP的build/core/config.mk 文件看到其定义,为 CLEAR_VARS:=$(BUILD_SYSTEM)/clear_vars.mk),其功能是清除除LOCAL_PATH外的其他LOCAL_XXX 变量 ( 如 LOCAL_MODULE , LOCAL_SRC_FILES 等)。因为所有的编译文件都在同一个 GNU Make 执行环境中,所有的变量都是全局的,所以我们需要先清空这些变量(LOCAL_PATH除外)。

    LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT)
    指定最后生成的模块的目标地址。
    TARGET_ROOT_OUT:根文件系统,路径为out/target/product/generic/root
    TARGET_OUT:system文件系统,路径为out/target/product/generic/system
    TARGET_OUT_DATA:data文件系统,路径为out/target/product/generic/data

    LOCAL_MODULE_TAGS :=user
    user: 指该模块只在user版本下才编译
    eng: 指该模块只在eng版本下才编译
    tests: 指该模块只在tests版本下才编译
    optional:指该模块在所有版本下都编译

    include $(BUILD_SHARED_LIBRARY)
    BUILD_SHARED_LIBRARY:位于build\core\shared_library.mk,负责收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息并决定编译为动态库。
    BUILD_STATIC_LIBRARY:编译为静态库。
    BUILD_EXECUTABLE:编译为Native C可执行程序
    BUILD_PREBUILT:该模块预先编译
    BUILD_STATIC_JAVA_LIBRARY:静态jar包,使用.class文件打包,可以运行在任何Java虚拟机平台
    BUILD_JAVA_LIBRARY:动态jar包,在静态jar包基础上使用.dex打包而成的jar文件。
    BUILD_PACKAGE:编译APK

    LOCAL_MODULE_CLASS := $(EXECUTABLES)
    用于制定LOCAL_MODULE_PATH的路径
    在编译为library,exe时,会默认就指定当前的LOCAL_MODULE_CLASS的值,比如EXECUTABLES、SHARED_LIBRARIES等。但当遇到include $(BUILD_PREBUILT)的预编译选项时不会默认指定LOCAL_MODULE_CLASS的值,需要在Android.mk中明确指定值,从而帮助系统确定LOCAL_MODULE_PATH的路径。

    编译文件

    #编译C/C++静态库
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := lib_hello_static #编译后的名称
    LOCAL_SRC_FILES := hellos.c #编译的源文件
    include $(BUILD_STATIC_LIBRARY) #指明要编译成静态库
        
    #编译C/C++动态库
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := lib_hello_shared
    LOCAL_SRC_FILES := hellod.c
    include $(BUILD_SHARED_LIBRARY)
    
    #编译C/C++应用程序
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := exe_hello
    LOCAL_SRC_FILES := hellod.c
    include $(BUILD_EXECUTABLE)    
    
    #编译Java静态库
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES := $(call all-subdir-java-files)
    LOCAL_JAVA_LIBRARIES := android.test.runner #依赖的动态jar
    LOCAL_MODULE := sample
    include $(BUILD_STATIC_JAVA_LIBRARY)
    
    

    Settings中的Android.mk文件,编译APK

    以Settings作为分析对象,来分析一下Android.mk文件的内容:

    
    LOCAL_PATH:= $(call my-dir) #LOCAL_PATH表示当前目录的地址,一般位于include $(CLEAR_VARS)之前
    include $(CLEAR_VARS)#清除除了LOCAL_PATH以外的所有LOCAL_打头的变量
    
    LOCAL_JAVA_LIBRARIES := bouncycastle conscrypt telephony-common ims-common#依赖动态jar  不会打包到APK,使用时从系统获取
    LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v13 jsr305#依赖静态jar  需要打包到APK中
    LOCAL_MODULE_TAGS := optional#模块tag为optional,表示不管是选择了什么模式都会编译该模块
    
    LOCAL_SRC_FILES := \  #本地代码文件
            $(call all-java-files-under, src) \
            src/com/android/settings/EventLogTags.logtags
    
    LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res #本地资源文件
    
    LOCAL_PACKAGE_NAME := Settings#模块名
    
    LOCAL_CERTIFICATE := platform#模块证书签名
    
    LOCAL_PRIVILEGED_MODULE := true#是否是特权文件
    
    LOCAL_PROGUARD_FLAG_FILES := proguard.flags#使用代码混淆
    
    ifneq ($(INCREMENTAL_BUILDS),)#判断是否进行增量编译
        LOCAL_PROGUARD_ENABLED := disabled
        LOCAL_JACK_ENABLED := incremental
    endif
    #include三个makefile文件,进项相关变量赋值
    include frameworks/opt/setupwizard/navigationbar/common.mk
    include frameworks/opt/setupwizard/library/common.mk
    include frameworks/base/packages/SettingsLib/common.mk
    #开始编译Settings模块,对应package.mk文件。感兴趣的可以进一步研究apk是怎么被编译出来的,里面还是很复杂的
    include $(BUILD_PACKAGE)
    # 如果使用的是mm或mmm命令单编Settings模块的话会额外include test目录下的Android.mk,用于编译测试模块。
    # Use the following include to make our test apk.
    ifeq (,$(ONE_SHOT_MAKEFILE))
    include $(call all-makefiles-under,$(LOCAL_PATH))
    endif
    

    相关文章

      网友评论

        本文标题:Android.mk简介(9)

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