Android.mk 解析

前言

平时总结收集的各种模板,是时候放出来看看了

主题

【常用模板:】

一、编译 Linux 应用程序的模板:
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        #include $(CLEAR_VARS)                                  // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_SRC_FILES:= main.c                                // 这是要编译的源代码文件列表,针对当前目录路径
        LOCAL_MODULE:= test_exe                                 // 这是模块的名字,它必须是唯一的,而且不能包含空格, 模块的名字决定了生成文件的名字
        #LOCAL_C_INCLUDES :=                                    // 可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录
        #LOCAL_STATIC_LIBRARIES :=                              // 表示该模块需要使用哪些静态库
        #LOCAL_SHARED_LIBRARIES :=                              // 表示模块在运行时要依赖的共享库(动态库)
        include $(BUILD_EXECUTABLE)                             // 表示以一个可执行程序的方式进行编译

二、编译 Linux 静态库的模板:
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_SRC_FILES:= /                                     // 这是要编译的源代码文件列表,针对当前目录路径
               helloworld.c
        LOCAL_MODULE:= libtest_static                           // 这是模块的名字,它必须是唯一的,而且不能包含空格, 模块的名字决定了生成文件的名字
        #LOCAL_C_INCLUDES :=                                    // 可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录
        #LOCAL_STATIC_LIBRARIES :=                              // 表示该模块需要使用哪些静态库
        #LOCAL_SHARED_LIBRARIES :=                              // 表示模块在运行时要依赖的共享库(动态库)
        include $(BUILD_STATIC_LIBRARY)                         // 表示编译一个静态库,静态库不会复制到的APK包中,但是能够用于编译共享库

三、编译动态库的模板:
        #Test Shared Lib
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_SRC_FILES:= /                                     // 这是要编译的源代码文件列表,针对当前目录路径
               helloworld.c
        LOCAL_MODULE:= libtest_shared                           // 这是模块的名字,它必须是唯一的,而且不能包含空格, 模块的名字决定了生成文件的名字
        #LOCAL_PRELINK_MODULE  := false                         // Prelink 利用事先链接代替运行时链接的方法来加速共享库的加载,它不仅可以加快起动速度,还可以减少内存开销
        #LOCAL_C_INCLUDES :=                                    // 可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录
        #LOCAL_STATIC_LIBRARIES :=                              // 表示该模块需要使用哪些静态库
        #LOCAL_SHARED_LIBRARIES :=                              // 表示模块在运行时要依赖的共享库(动态库)
        include $(BUILD_SHARED_LIBRARY)                         // 表示编译一个动态库
    
四、编译一个简单的APK 
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_SRC_FILES := $(call all-subdir-java-files)        // Build all java files in the java subdirectory
        LOCAL_PACKAGE_NAME := LocalPackage                      // 要编译的 APK 名称
        include $(BUILD_PACKAGE)                                // 表示编译一个 APK

五、编译一个依赖静态.jar文件的APK 
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_STATIC_JAVA_LIBRARIES := static-library           // APK程序所需要的JAVA库的JAR文件名
        LOCAL_SRC_FILES := $(call all-subdir-java-files)        // Build all java files in the java subdirectory
        LOCAL_PACKAGE_NAME := LocalPackage                      // 要编译的 APK 名称
        include $(BUILD_PACKAGE)                                // 表示编译一个 APK

六、编译一个需要 platform key 签名的 APK 
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_SRC_FILES := $(call all-subdir-java-files)        // Build all java files in the java subdirectory
        LOCAL_MODULE_TAGS := optional                           // 此模块在所有版本下都编译
        LOCAL_PACKAGE_NAME := LocalPackage                      // 要编译的 APK 名称
        LOCAL_CERTIFICATE := platform                           // 签名文件的文件名
        include $(BUILD_PACKAGE)                                // 表示编译一个 APK

七、编译一个需要特殊 vendor key 签名的 APK 
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_SRC_FILES := $(call all-subdir-java-files)        // Build all java files in the java subdirectory
        LOCAL_PACKAGE_NAME := LocalPackage                      // 要编译的 APK 名称
        LOCAL_CERTIFICATE := vendor/example/certs/app           // vendor 签名文件的文件位置
        include $(BUILD_PACKAGE)                                // 表示编译一个 APK

八、复制一个普通的第三方 APK
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_MODULE := LocalModuleName                         // Module name should match apk name to be installed.
        LOCAL_SRC_FILES := $(LOCAL_MODULE).apk                  // 要装载的 apk 名称
        LOCAL_MODULE_CLASS := APPS                              // 应该是中间文件存放位置,位于 obj/APPS
        LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) // 表示编译链接后的目标文件的后缀
        LOCAL_CERTIFICATE := platform                           // 签名文件的文件名
        include $(BUILD_PREBUILT)                               // 编译前的预处理,一般用来复制文件到指定目录
        
    可以在 installed-files.txt 中查看是否加入到了对应的 img 文件中。
    纯粹拷贝apk文件:
        目录结构 vendor/BM/APPs/MobileQQ2011.apk
                 vendor/BM/APPs/Renren_Android_3.0.2.apk
                 ...
                 
        通过 android 提供的 PRODUCT_COPY_FILES 这个变量来自动拷贝,
        只需要给此变量赋值。在任何一个确定加入编译的 mk 文件
            PRODUCT_COPY_FILES += /
                vendor/bm/APPS/MobileQQ2011.apk:system/app/MobileQQ2011.apk/
                vendor/bm/APPS/Renren_Android_3.0.2.apk:system/app/Renren_Android_3.0.2.apk

    
九、复制需要 .so(动态库)的第三方apk
        #################################################################
        ####### 复制 apk                        #########################
        #################################################################
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_MODULE := baiduinput_android                      // 模块名称
        LOCAL_SRC_FILES := $(LOCAL_MODULE).apk                  // 要复制的 apk 名
        LOCAL_MODULE_CLASS := APPS                              // 应该是中间文件存放位置,位于 obj/APPS
        LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) // 表示编译链接后的目标文件的后缀
        LOCAL_CERTIFICATE := platform                           // 签名文件的文件名
        include $(BUILD_PREBUILT)                               // 编译前的预处理,一般用来复制文件到指定目录

        #################################################################
        ####### 复制动态库到 /system/lib        #########################
        #################################################################
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_MODULE := libinputcore.so                         // 模块名称
        LOCAL_MODULE_CLASS := SHARED_LIBRARIES                  // 指定文件类型
        LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)     // 指定输出路径
        LOCAL_SRC_FILES := lib/$(LOCAL_MODULE)                  // 源文件位置
        OVERRIDE_BUILD_MODULE_PATH := $(TARGET_OUT_INTERMEDIATE_LIBRARIES)
        include $(BUILD_PREBUILT)                               // 编译前的预处理,一般用来复制文件到指定目录
        
十、第三方 so 库打包到 apk 
    1. 如何判断第三方库文件是32 bit/64 bit? 
        使用Linux 命令: file xxx.so, 可以看到拿到的xxx.so是哪种格式
        
    2. 请把此so 放在apk 目录下,也可以存放在vendor/meidatek/libs/$project/
        #########################################################################
        ### $folder/xxx.so
        ### 采用 prebuilt 的方式,在当前 so 所在目录下写 Android.mk ,内容类似如下: 
        ##########################################################################
        LOCAL_PATH := $(call my-dir)
        include $(CLEAR_VARS)
        LOCAL_MODULE := 此 so 库名(不加 so 后缀)
        LOCAL_SRC_FILES_32 := xxx.so (表示是32 bit 的so)
        LOCAL_SRC_FILES_64 := xxx.so (表示是64 bit的so)
        LOCAL_MULTILIB := 32/64/BOTH(只编译32bit/64bit/both)
        LOCAL_MODULE_CLASS := SHARED_LIBRARIES
        LOCAL_MODULE_SUFFIX := .so
        include $(BUILD_PREBUILT)
        
        #########################################################################
        ## 然后此so 就可以被直接在apk 的Android.mk 使用
        #########################################################################
        ## 在alps\packages\apps\Tester 添加一个apk, Android.mk写法
        #########################################################################
        LOCAL_PATH := $(call my-dir)
        include $(CLEAR_VARS)
        LOCAL_MODULE_TAGS := tests
        LOCAL_SRC_FILES := $(call all-java-files-under, src)
        ######################################
        # 对前面 prebuilt 的动态库的引用
        ######################################
        LOCAL_JNI_SHARED_LIBRARIES +=xxx
        ######################################
        # 此apk 限制为32 bit
        ######################################
        LOCAL_MULTILIB := 32
        include $(BUILD_PACKAGE)

        
十一、编译一个静态java库 
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_SRC_FILES := $(call all-subdir-java-files)        // Build all java files in the java subdirectory
        LOCAL_JAVA_LIBRARIES := android.test.runner             // Any libraries that this library depends on
        LOCAL_MODULE := sample                                  // 模块名
        include $(BUILD_STATIC_JAVA_LIBRARY)                    // 表示生成 static jar文件

十二、复制一个 so 库到系统中 
    #方法一:预置so等资源文件
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_MODULE := wanghai.so                              // 要复制成的库名
        LOCAL_SRC_FILES := wanghai.so                           // 要复制的库文件
        LOCAL_MODULE_TAGS := optional                           // 此模块在所有版本下都编译
        LOCAL_MODULE_CLASS := SHARED_LIBRARIES                  // 文件类型为动态库
        LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/                 // 指定输出目录
        include $(BUILD_PREBUILT)                               // 编译前的预处理,一般用来复制文件到指定目录

    #方法二:预置so等资源文件
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_MODULE_TAGS := optional                           // 此模块在所有版本下都编译
        LOCAL_PREBUILT_LIBS := sdfapk.so sdffff.so              // 已经编译好的第三方库
        include $(BUILD_MULTI_PREBUILT)                         // 编译前的预处理,用于处理多个文件

    #方法三:
        预置so等资源文件,在 Android.mk 里 添加 这样一句,注意:这样的方式 如果路径不存在,这条指令 执行 失败,但 不会 报错!
             $(shell cp -rf $(LOCAL_PATH)/libs/*.so $(TARGET_OUT)/lib)
             
十三、复制一个静态库:
        LOCAL_PATH := $(call my-dir)  
        include $(CLEAR_VARS)  
        LOCAL_PREBUILT_LIBS := libA.a    /  
                            libB.a   
        LOCAL_STATIC_LIBRARIES := libA    /  
                                libB  
        include $(BUILD_MULTI_PREBUILT)  

十四、复制一个可执行程序
    第一种方法:
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_SRC_FILES := hellovprc.elf                        // 要复制的成源文件名
        LOCAL_MODULE := hellovprc.elf                           // 模块名称
        LOCAL_MODULE_CLASS := EXECUTABLES                       // 要复制的文件类型
        LOCAL_MODULE_TAGS := debug                              // 只在 debug 模式下执行
        include $(BUILD_PREBUILT)                               // 编译前的预处理,一般用来复制文件到指定目录
        
    第二种方法:
        LOCAL_PATH := $(call my-dir)                            // 给出当前文件的路径
        include $(CLEAR_VARS)                                   // 重置除 LOCAL_PATH 外的所有 LOCAL_XXX 系统变量
        LOCAL_PREBUILT_EXECUTABLES := i2cdetect i2cdump         // 需要添加的文件名,其模块名称默认也为 i2cdetect
        include $(BUILD_MULTI_PREBUILT)
        
        
十五、 APK 签名 
        ####################################################
        ## 需要将一下内容写入Android.mk
        ####################################################
        LOCAL_PATH := $(call my-dir)
        include $(CLEAR_VARS)
        LOCAL_MODULE := 模块名称
        LOCAL_MODULE_TAGS := optional
        LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
        LOCAL_MODULE_CLASS := APPS
        LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
        LOCAL_CERTIFICATE := platform
        include $(BUILD_PREBUILT)

【输出目录:】

以上生成结果分别在如下,generic 依具体 target 会变:
    out/target/product/generic/obj/EXECUTABLE
    out/target/product/generic/obj/STATIC_LIBRARY
    out/target/product/generic/obj/SHARED_LIBRARY
    out/target/product/generic/obj/APPS
    out/target/product/generic/obj/JAVA_LIBRARIES

每个模块的目标文件夹分别为:
    可执行程序:    XXX_intermediates
    静态库:        XXX_static_intermediates
    动态库:        XXX_shared_intermediates
    APK程序:       XXX_intermediates
    JAVA库程序:    XXX_intermediates

另外,在Android.mk文件中,还可以指定最后的目标安装路径,用 LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH 来指定。不同的文件系
统路径用以下的宏进行选择:
    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。
    OUT_DIR:          代码工程编译时的out生成目录
    PRODUCT_OUT:      映象生成目录
用法如下:
     CAL_MODULE_PATH:=$(TARGET_ROOT_OUT)

Android.mk 解析】

一个Android.mk file用来向编译系统描述你的源代码。具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一
次或多次。你可以在每一个Android.mk file中定义一个或多个模块,你也可以在几个模块中使用同一个源代码文件。每个模
块属下列类型之一:
  1)APK程序,一般的Android程序,编译打包生成apk文件
  2)JAVA库,java类库,编译打包生成jar文件
  3) C\C++应用程序,可执行的C\C++应用程序
  4)C\C++静态库,编译生成C\C++静态库,并打包成.a文件
  5)C\C++共享库, 编译生成共享库(动态链接库),并打包成.so, 有且只有共享库才能被安装/复制到您的应用软件(APK)包中。

一、GNU Make系统变量

这些 GNU Make变量在你的 Android.mk 文件解析之前,就由编译系统定义好了。注意在某些情况下,NDK可能分析 Android.mk 
几次,每一次某些变量的定义会有不同。
	(1)CLEAR_VARS:  指向一个编译脚本,几乎所有未定义的 LOCAL_XXX 变量都在"Module-description"节中列出。必须在
        开始一个新模块之前包含这个脚本:include$(CLEAR_VARS),用于重置除LOCAL_PATH 变量外的,所有 LOCAL_XXX 系列变量。
        android有自己的一套代码编译规则跟编译选项等变量的定义,此变量会引入,实际是android/build/core下的clear_vas.mk
	(2)BUILD_SHARED_LIBRARY:  指向编译脚本,根据所有的在 LOCAL_XXX 变量把列出的源代码文件编译成一个共享库。
		注意,必须至少在包含这个文件之前定义 LOCAL_MODULE 和 LOCAL_SRC_FILES。
	(3)BUILD_STATIC_LIBRARY: 一个 BUILD_SHARED_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.
	(6)TARGET_ARCH_ABI:  暂时只支持两个 value: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_XXXXX)'之间。正如前面描写
  的那样,$(CLEAR_VARS)是一个脚本,清除所有这些变量。
  (1) LOCAL_PATH:  这个变量用于给出当前文件的路径。必须在 Android.mk 的开头定义,可以这样使用:LOCAL_PATH := $(call my-dir) 
        这个变量不会被$(CLEAR_VARS)清除,因此每个 Android.mk 只需要定义一次(即使在一个文件中定义了几个模块的情况下)。
  (2)LOCAL_MODULE: 这是模块的名字,它必须是唯一的,而且不能包含空格。必须在包含任一的$(BUILD_XXXX)脚本之前定义它。模块的
        名字决定了生成文件的名字。例如,如果一个一个共享库模块的名字是,那么生成文件的名字
		就是lib.so。但是,在的 NDK 生成文件中(或者 Android.mk 或者 Application.mk),应该只涉及(引用)有正常名字的其他模块。
  (3)LOCAL_SRC_FILES:  这是要编译的源代码文件列表。只要列出要传递给编译器的文件,因为编译系统自动计算依赖。注意源代码文
        件名称都是相对于 LOCAL_PATH 的,你可以使用路径部分,
		例如:
			LOCAL_SRC_FILES := foo.c toto/bar.c\
			Hello.c
		文件之间可以用空格或Tab键进行分割,换行请用"\".如果是追加源代码文件的话,请用 LOCAL_SRC_FILES +=
		注意:在生成文件中都要使用UNIX风格的斜杠(/).windows风格的反斜杠不会被正确的处理。
		注意:可以 LOCAL_SRC_FILES := $(call all-subdir-java-files) 这种形式来包含 local_path 目录下的所有 java 文件。
  (4) LOCAL_CPP_EXTENSION:  这是一个可选变量, 用来指定C++代码文件的扩展名,默认是'.cpp',但是可以改变它,
		比如:
			LOCAL_CPP_EXTENSION := .cxx
  (5) LOCAL_C_INCLUDES:  可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录。
		示例:
			LOCAL_C_INCLUDES := sources/foo或LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
		LOCAL_C_INCLUDES需要在任何包含LOCAL_CFLAGS/LOCAL_CPPFLAGS标志之前进行设置。
  (6)LOCAL_CFLAGS:  可选的编译器选项,在编译 C 代码文件的时候使用。这可能是有用的,指定一个附加的包含路径(相对于NDK的顶
        层目录),宏定义,或者编译选项。
		注意:不要在 Android.mk 中改变 optimization/debugging 级别,只要在 Application.mk 中指定合适的信息,就会自动地为
        你处理这个问题,在调试期间,会让 NDK自动生成有用的数据文件。
  (7)LOCAL_CXXFLAGS:  与 LOCAL_CFLAGS同理,针对 C++源文件。
  (8)LOCAL_CPPFLAGS:  与 LOCAL_CFLAGS同理,但是对 C 和 C++ source files都适用。
  (9)LOCAL_STATIC_LIBRARIES: 表示该模块需要使用哪些静态库,以便在编译时进行链接。
  (10)LOCAL_SHARED_LIBRARIES:  表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息。
        注意:它不会附加列出的模块到编译图,也就是仍然需要在Application.mk 中把它们添加到程序要求的模块中。
  (11)LOCAL_LDLIBS:  编译模块时要使用的附加的链接器选项。这对于使用‘-l’前缀传递指定库的名字是有用的。
		例如,
			LOCAL_LDLIBS := -lz
		表示告诉链接器生成的模块要在加载时刻链接到/system/lib/libz.so
		可查看 docs/STABLE-APIS.TXT 获取使用 NDK发行版能链接到的开放的系统库列表。
  (12) LOCAL_ALLOW_UNDEFINED_SYMBOLS:  
		默认情况下, 在试图编译一个共享库时,任何未定义的引用将导致一个“未定义的符号”错误。这对于在源代码文件中捕捉错误会有
        很大的帮助。然而,如果因为某些原因,需要不启动这项检查,可把这个变量设为‘true’。
		注意相应的共享库可能在运行时加载失败。(这个一般尽量不要去设为 true)。
  (13) LOCAL_ARM_MODE: 默认情况下, arm目标二进制会以 thumb 的形式生成(16 位),你可以通过设置这个变量为 arm如果你希望你的
         module 是以 32 位指令的形式。
		'arm' (32-bit instructions) mode. E.g.:
			LOCAL_ARM_MODE := arm
		注意:可以在编译的时候告诉系统针对某个源码文件进行特定的类型的编译
		比如,LOCAL_SRC_FILES := foo.c bar.c.arm  这样就告诉系统总是将 bar.c 以arm的模式编译。
	(14)LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH
		在 Android.mk 文件中, 还可以用 LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH 指定最后的目标安装路径.
        不同的文件系统路径用以下的宏进行选择:
           TARGET_ROOT_OUT: 表示根文件系统。
           TARGET_OUT:      表示 system文件系统。
           TARGET_OUT_DATA: 表示 data文件系统。
        用法如:LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT) 
        至于 LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH 的区别,暂时还不清楚,strip 是一个编译完成后去除程序调试信息的工具。
    (15) LOCAL_MODULE_CLASS 将用于决定编译时的中间文件存放的位置,之后放在最后的obj目录下的对应目录中。
        LOCAL_MODULE_CLASS用于制定 LOCAL_MODULE_PATH 的路径所在, 如果在Android.mk没有直接明确LOCAL_MODULE_PATH 的话,需要通过
        以下规则来自动生成 base_rules.mk:
            LOCAL_MODULE_PATH := $(strip $(LOCAL_MODULE_PATH))
            ifeq ($(LOCAL_MODULE_PATH),)
                    #LOCAL_MODULE_CLASS :=
              LOCAL_MODULE_PATH := $($(my_prefix)OUT$(partition_tag)_$(LOCAL_MODULE_CLASS))
              $(info *******//////////$(LOCAL_MODULE_PATH))
            ifeq ($(strip $(LOCAL_MODULE_PATH)),)
                $(error $(LOCAL_PATH): unhandled LOCAL_MODULE_CLASS "$(LOCAL_MODULE_CLASS)")
              endif
            endif

            在不同的 Android.mk 文件中,对于模块 include()不同的编译类型选项,比如对于 Library 或者 app,execut 等在调用对应的处理 mk 文件时,
        会默认就指定当前的LOCAL_MODULE_CLASS的值,比如 EXECUTABLES 、SHARED_LIBRARIES等。所以在自己编写的Android.mk可不显示的指
        定LOCAL_MODULE_CLASS的值.
            但当遇到include $(BUILD_PREBUILT)的预编译选项时不会指定模块模块编译输出的类型CLASS,需要在自己编写的Android.mk中明确指
        定LOCAL_MODULE_CLASS的值如ETC/APP等,使其值为非空,从而帮助系统确定LOCAL_MODULE_PATH的路径,比如最终编译输出 
            LOCAL_MODULE_PATH  := $(TARGRT_OUT_ETC)。
        一般根据文件类型来指定位置: 
            指定文件类型,apk 文件用APPS,动态库 so 文件用 SHARED_LIBRARIES ,bin文件用 EXECUTABLES,其他文件用 ETC
        LOCAL_MODULE_CLASS 选项有:
            LOCAL_MODULE_CLASS := ETC
            LOCAL_MODULE_CLASS := STATIC_LIBRARIES
            LOCAL_MODULE_CLASS := EXECUTABLES
            LOCAL_MODULE_CLASS := FAKE
            LOCAL_MODULE_CLASS := JAVA_LIBRARIES
            LOCAL_MODULE_CLASS := SHARED_LIBRARIES
            LOCAL_MODULE_CLASS := APPS
        对应 Cyanogenmod/target/product/m7ul/obj 的目录 
        比如说若 
            LOCAL_MODULE_CLASS := ETC 
        那么该模块编译的中间文件将存放于
            Cyanogenmod/target/product/m7ul/obj/ETC
    (16) LOCAL_MODULE_SUFFIX 表示编译链接后的目标文件的后缀
    (17) LOCAL_MODULE_TAG:标识在什么情况下去编译起模块,有几个选项
            user        模块只在user下编译
            eng         模块在eng模式下编译
            tests       test状态下编译
            optional    此模块在所有版本下都编译 
        即 TARGET_BUILD_VARIANT=eng 编译TAGS为 eng 和 optional 的模块

    (18) LOCAL_CERTIFICATE : 指定签名,可以用 platform 说明用平台签名,或者直接指定第三方签名文件, PRESIGNED 表示已经签过名了,系统
        不需要再次签名 

    (19) BUILD_PREBUILT/BUILD_MULTI_PREBUILT: Android 提供了 Prebuilt 编译方法,两个文件 prebuilt.mk 和 multi_prebuilt.mk,对应的
        方法宏是 BUILD_PREBUILT 和 BUILD_MULTI_PREBUILT, prebuilt.mk 就是 prebuilt 的具体实现,它是针对独立一个文件的操作,
        multi_prebuilt.mk 可以针对多个文件的,它对多个文件进行判断,然后调用 prebuilt 对独立一个文件进行处理。

    (20) LOCAL_OVERRIDES_PACKAGES: 此变量可以使其他的模块不加入编译,如源码中 DeskClock 的 android.mk 有
            LOCAL_OVERRIDES_PACKAGES := AlarmClock
        使 AlarmClock 不会加入到编译系统中,不会生成 AlarmClock.apk。
            
            原先我是死活不明白会什么有两个闹钟 AlarmClock和 DeskClock ,源码几乎相同,原先只在 AlarmClock 中的文件中修改,就是没有效
        果,测试说没有修改,原来发布的版本中只有 DeckClock.apk,我却在本地 make AlarmClock 编译出了AlarmClock.apk,>_<!!
            试了一下在 DeskClock 的 android.mk 中加入 LOCAL_OVERRIDES_PACKAGES := Calendar,删掉 Calendar.apk, 然后全部make一下,在
        system/app下calendar.apk 竟然没再生成了????!!!
        
        # Some packages may override others using LOCAL_OVERRIDES_PACKAGES.
        # Filter out (do not install) any overridden packages.
        overridden_packages := $(call get-package-overrides,$(modules_to_install))
        ifdef overridden_packages
        #  old_modules_to_install := $(modules_to_install)
          modules_to_install := /
              $(filter-out $(foreach p,$(overridden_packages),$(p) %/$(p).apk), /
                  $(modules_to_install))
        endif

Android.mk 中常用的重要变量解析:

        LOCAL_PATH: 用来确定源码所在目录
        CLEAR_VARS: 清空了很多 LOCAL_ 开头的变量,LOCAL_PATH 除外
        LOCAL_MODULE: 模块名
        LOCAL_MODULE_PATH: 模块的输出路径
        LOCAL_SRC_FILES: 模块编译过程所涉及的源文件
        LOCAL_CC: 用于指定 C 编译器
        LOCAL_CXX: 用于指定 C++ 编译器
        LOCAL_CPP_EXTENSION: 用于指定特殊的 C++ 文件后缀名
        LOCAL_CFLAGS: C 语言编译时的额外选项
        LOCAL_CXXFLAGS: C++ 语言编译时的额外选项
        LOCAL_C_INCLUDES: 编译 C 和 C++ 程序所需的额外头文件
        LOCAL_STATIC_LIBRARIES: 编译所需的静态库列表
        LOCAL_SHARED_LIBRARIES: 编译所需的共享库列表
        LOCAL_JAVA_LIBRARIES: 编译时所需的 JAVA 类库
        LOCAL_LDLIBS: 编译时所需的链接选项
        LOCAL_COPY_HEADERS: 安装应用时所需复制的头文件列表
        LOCAL_COPY_HEADERS_TO: 上述头文件复制目的地
        LOCAL_MODULE_TAGS: 用于指定该项目的标签值, optiional/tests/eng 
        
        LOCAL_PACKAGE_NAME: 用于描述 APK 项目的名称
        LOCAL_MODULE_NAME: 用于描述 C 项目的名称
        LOCAL_SDK_VERSION: 用于指定该 APK 项目所需的 SDK 版本,current 代表了当前 Android 源码的版本 
        
        LOCAL_CERTIFICATE: 用于指定该 APK 项目将使用何种签名文件签名最后生成的 apk 文件
                    系统一共有四种签名:
                        platform: Framework 源码最后将生成一个 jar 包,该 jar 包默认就使用该类型签名 
                        shared: 一些系统应用程序使用该类型签名 
                        user: 一些私有项目使用该签名 
                        tests: 调试过程中一般使用的签名
                    一般当需要和特定的程序共享数据库资源时,两个项目必须拥有相同的签名
        
    各种类型的编译模板:
        BUILD_HOST_STATIC_LIBRARY           // 主机上的二进制静态库
        BUILD_HOST_SHARED_LIBRARY           // 主机上的二进制动态库
        BUILD_STATIC_LIBRARY                // 目标设备上的二进制静态库
        BUILD_RAW_STATIC_LIBRARY
        BUILD_SHARED_LIBRARY                // 目标设备上的二进制动态库
        BUILD_EXECUTABLE                    // 目标设备上的二进制可执行文件
        BUILD_RAW_EXECUTABLE
        BUILD_HOST_EXECUTABLE               // 主机上的可执行文件
        BUILD_PACKAGE                       // APK 程序 
        BUILD_HOST_PREBUILT                 
        BUILD_PREBUILT
        BUILD_MULTI_PREBUILT
        BUILD_JAVA_LIBRARY                  // 目标设备上的共享 Java 库 
        BUILD_STATIC_JAVA_LIBRARY           // 目标设备上的静态 Java 库 
        BUILD_HOST_JAVA_LIBRARY             // 主机上的 Java 共享库 
        BUILD_DROIDDOC
        BUILD_COPY_HEADERS
        BUILD_KEY_CHAR_MAP

三、GNU Make‘功能’宏

GNU Make‘功能’宏,必须通过使用'$(call  )'来调用,调用他们将返回文本化的信息。
(1)my-dir:返回当前 Android.mk 所在的目录的路径,相对于 NDK 编译系统的顶层。这是有用的,在 Android.mk 文件的开头如此定义:
		LOCAL_PATH := $(call my-dir)
(2)all-subdir-makefiles: 返回一个位于当前'my-dir'路径的子目录中的所有Android.mk的列表。
	例如,看下面的目录层次:
		sources/foo/Android.mk
		sources/foo/lib1/Android.mk
		sources/foo/lib2/Android.mk
	如果 sources/foo/Android.mk 包含一行:
		include $(call all-subdir-makefiles)
	那么它就会自动包含 sources/foo/lib1/Android.mk 和 sources/foo/lib2/Android.mk。
	这项功能用于向编译系统提供深层次嵌套的代码目录层次。
	注意,在默认情况下,NDK 将会只搜索在 sources/*/Android.mk 中的文件。
(3)this-makefile:  返回当前Makefile 的路径(即这个函数调用的地方)
(4)parent-makefile:  返回调用树中父 Makefile 路径。即包含当前Makefile的Makefile 路径。
(5)grand-parent-makefile:返回调用树中父Makefile的父Makefile的路径
(6)all-subdir-c-files: 子目录下所有 .c 文件 
(7)all-subdir-java-files: 子目录下所有 java 源文件 

##【一个例子详解】

先看一个简单的例子:一个简单的"hello world",比如下面的文件:
	sources/helloworld/helloworld.c 
	sources/helloworld/Android.mk
相应的Android.mk文件会象下面这样:
	---------- cut here ------------------
	LOCAL_PATH := $(call my-dir)
	include $(CLEAR_VARS)
	LOCAL_MODULE	:= helloworld
	LOCAL_SRC_FILES := helloworld.c
	include $(BUILD_SHARED_LIBRARY)
	---------- cut here ------------------
我们来解释一下这几行代码:

1.LOCAL_PATH := $(call my-dir) 
	一个Android.mk file首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’, 由编译
    系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。
	
2.include $( CLEAR_VARS)
	CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, 
    LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所
    有的变量都是全局的。
	
3.LOCAL_MODULE := helloworld
	LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。注意编译
    系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件。
	
4.LOCAL_SRC_FILES := helloworld.c 
	LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编
    译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。

此处虽没用到其他常用的还有:

5,LOCAL_C_INCLUDES:可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录。示例:
    LOCAL_C_INCLUDES := sources/foo 或 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo

6,TARGET_ARCH:目标 CPU平台的名字;TARGET_PLATFORM:Android.mk 解析的时候,目标 Android 平台的名字;TARGET_ARCH_ABI:
    暂时只支持两个 value,armeabi 和 armeabi-v7a

7,LOCAL_STATIC_LIBRARIES: 表示该模块需要使用哪些静态库(*.a)的名称,以便在编译时进行链接。

8,LOCAL_SHARED_LIBRARIES:  表示模块在运行时要依赖的共享库(动态库)(*.so)的名称,在链接时就需要,以便在生成文件时嵌
    入其相应的信息。

9,LOCAL_LDLIBS:  编译模块时要使用的附加的链接器选项。

10,LOCAL_ARM_MODE: 默认情况下, arm目标二进制会以 thumb 的形式生成(16 位),你可以通过设置这个变量为 arm如果你希望你的
     module 是以 32 位指令的形式

11,LOCAL_CFLAGS:  可选的编译器选项,在编译 C 代码文件的时候使用

12,include $(call all-subdir-makefiles):返回一个位于当前'my-dir'路径的子目录中的所有Android.mk的列表。

13. LOCAL_MODULE_TAGS := optional
	# According to your requirement to set the tags
	# set it as ‘user’ if library/file is required in final SW product
	# set it as ‘eng’/’tests’/’debug’ etc. if a development/debug used lib/file
	# set it as ‘optional’ if installed to system image by other module’s dependency
	# setting(ex. LOCAL_XXX_LIBRARIES) trigger(NOT installed directly)

在Android中增加本地程序或者库,这些程序和库与其所载路径没有任何关系,只和它们的Android.mk文件有关系。Android.mk和普
通的Makefile有所不同,它具有统一的写法,主要包含一些系统公共的宏。在一个Android.mk中可以生成多个可执行程序、动态库和静态库。

猜你喜欢

转载自blog.csdn.net/wangjun7121/article/details/88133598