Android.mk文件语法规范

http://www.spridu.cn/article/android-dev/2011/09/05/android-ndk-r5ZhongWenFanYi.shtml

简介: 
-------------

本文档介绍了Android NDK用Android.mk描述你的C/C++源文件.
假设你之前阅读docs/OVERVIEW.html文件,了解了一些其作用和用法.

概述: 
---------

Android.mk文件是用来描述你的源代码如何构建系统.
具体来说:

- 这个文件只是GNU Makefile的一部分,在构建系统时它将被解析多次.
  因此,您应尽量减少声明的变量那里,不要以为不会在解析定义任何东西。

- 文件的语法设计,允许把你的源分类在'modules'.一个模块是下列之一:

     - 静态库
     - 共享库

  只有共享库将被安装/复制到您的应用程序包。
  静态库可用于生成共享库。

  你可以定义一个或多个模块在每个Android.mk文件, 
  你能使用相同的源文件在多个模块中

- 编译系统为您处理了许多细节。例如,你不需要在Android.mk中列出头文件或
  依赖的文件.ndk build会自动帮你搜索。

  意味着,当更新到新版本的NDK,你能尽可能的体会到它的好处,
  你几乎不用修改你的Android.mk文件

注意:这语法是随着Android平台一起开源的.虽然编译系统实现使用他们是不同的,
这是作出一个故意设计的,使开发人员重复使用的外部库的更容易。


一个简单的例子:
---------------

在描述详细的语法之前,让我们思考一个简单 
“你好hello JNI的”的例子,文件在:

    apps/hello-jni/project

在这里,我们可以看到:

   - Android项目的'src'的目录下包含了Java源代码

   - 在'jni的'目录包含的本地源代码, 'jni/hello-jni.c'

    该源文件实现简单的共享库,
    实现了一个本地方法返回一个字符串
    给虚拟机的应用程序.

   - 在'jni/Android.mk'文件中,它描述了NDK是如何构建共享库的.其内容为:

   ---------- cut here ------------------
   LOCAL_PATH := $(call my-dir)

   include $(CLEAR_VARS)

   LOCAL_MODULE    := hello-jni
   LOCAL_SRC_FILES := hello-jni.c

   include $(BUILD_SHARED_LIBRARY)
   ---------- cut here ------------------

现在,让我们解释一下这几行:

 LOCAL_PATH := $(call my-dir)

Android.mk文件必须在开始为LOCAL_PATH变量的定义.
它用于在开发树中查找源代码文件.在这个例子中, 
宏函数'my-dir',由编译系统提供的,用于返回 
当前目录的路径(即目录包含Android.mk文件本身)。

  include $(CLEAR_VARS)

CLEAR_VARS变量是由编译系统提供的,并指向一个特别GNU的make文件,
将清除你很多LOCAL_XXX变量
(例如LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES等..)
LOCAL_PATH例外.这是必要的,
因为所有生成都在单个GNU Make中执行,它要分析控制文件位置所有变量,
这些变量都是全局的,保证唯一.

  LOCAL_SRC_FILES := hello-jni.c

在Android.mk文件中LOCAL_MODULE变量必须明确定义每个模块。
该名称必须是唯一的,不包含任何空格.
请注意,编译系统将自动添加适当的前缀和后缀添加到相应的生成文件.
换句话说,一个共享库模块命名为'foo'将生成'libfoo.so'。

重要注意事项:
如果你给你的模块命名为'libfoo',编译系统不会在添加一个'lib'前缀,
这样会产生libfoo.so,这是为了支持来自Android.mk文件.

  LOCAL_SRC_FILES:=您好,jni.c

LOCAL_SRC_FILES变量必须包含的C/C++源文件列表,这些模块将被加入
一个模块组装.请注意在这里您不用列出包含的头文件,因为生成系统将 
自动为您计算依赖关系,只要列出源文件即可.

请注意,C++源文件的默认扩展名是'.cpp'.这是 
可以通过LOCAL_CPP_EXTENSION变量来定义.
不要忘了那个点(即'.cxx'会工作,但'cpp'将不工作)

  include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY是由编译系统提供的变量,它指向GNU的Makefile脚本,
在负责收集所有的LOCAL_XXX定义的最新信息
'include $(CLEAR_VARS)',并确定如何正确的去编译.
BUILD_STATIC_LIBRARY生成一个静态库。

在示例目录下有复杂的示例,你可以打开Android.mk来看看.

参考: 
----------

变量您应该定义在Android.mk中.你可以定义你自己使用的其他变量,
但NDK编译系统保留以下变量名:

- 名称以LOCAL_(如 LOCAL_MODULE)开始的
- 名称以PRIVATE_,NDK_或APP_(内部使用)开始的 
- 小写名称(内部使用,例如:'my-dir')

如果你需要定义使自己方便的变量,我们建议使用MY_前缀,一个简单的例子:

   ---------- cut here ------------------
    MY_SOURCES := foo.c
    ifneq ($(MY_CONFIG_BAR),)
      MY_SOURCES += bar.c
    endif

    LOCAL_SRC_FILES += $(MY_SOURCES)
   ---------- cut here ------------------


NDK提供的变量: 
- - - - - - - - - - - -

在你的Android.mk被解析之前,这些变量是被GNU Make定义的.
请注意,在某些情况下,NDK会解析Android.mk多次
解析的NDK可能具有不同的Android.mk几次,这些变量可能都有
不同的定义

CLEAR_VARS 
    指向编译脚本取消几乎所有的LOCAL_XXX变量,
    下面一节列出的“Module-description”的说明.
    在一个新模块中,你必须包含它在开始:

     include $(CLEAR_VARS)

BUILD_SHARED_LIBRARY 
 指向一个编译脚本,收集所有LOCAL_XXX有关的信息,然后
 确定如何去编译.之前必须有LOCAL_MODULE和LOCAL_SRC_FILES定义, 
 示例:

       include $(BUILD_SHARED_LIBRARY)

    请注意,这会产生名为lib$(LOCAL_MODULE).so的文件

BUILD_STATIC_LIBRARY 
    不同于BUILD_SHARED_LIBRARY,用于编译一个静态库.
    静态库不会复制到您的项目/包中,但可以用于构建共享库
    (见LOCAL_STATIC_LIBRARIES和LOCAL_STATIC_WHOLE_LIBRARIES所述)
    示例:

      include $(BUILD_STATIC_LIBRARY)

    请注意,这将生成一个文件名为lib$(LOCAL_MODULE).a

PREBUILT_SHARED_LIBRARY 
    指向一个用于指定建立一个预编译共享库的脚本.
    不像BUILD_SHARED_LIBRARY和BUILD_STATIC_LIBRARY,
    LOCAL_SRC_FILES必须是预编译共享库单一的路径(例如foo/libfoo.so)
    ,而不是源文件。

    你可以在另一个模块中引用该预编译库,
    使用LOCAL_PREBUILTS变量
    (更多的信息见 docs/PREBUILTS.html)

PREBUILT_STATIC_LIBRARY 
    类似于PREBUILT_SHARED_LIBRARY,它是针对静态库。
    更多信息,请参阅文档docs/PREBUILTS.html。

TARGET_ARCH 
    目标CPU架构名,因为它是指定的完整的Android开源版本.
    这是为了在不同CPU架构编译.

TARGET_PLATFORM 
    指定目标Android平台名,当Android.mk被解析。
    例如,'android-3'对应Android 1.5系统映像。
    Android平台名是怎么与版本对应的,
    请阅读docs/STABLE-APIS.html.

TARGET_ARCH_ABI 
    指定在目标CPU+ABI名字,当Android.mk被解析。 
    目前支持两个值:

       armeabi
            For Armv5TE

       armeabi-v7a
       
    注:截至到Android NDK 1.6_r1,这个变量是简单地定义 
          为'arm',现在,这个值已被重新定义,以更好的知道
          在Android内部使用的是什么

    有关架构的ABI及相应的详细资料 
    请阅读文档docs/CPU-ARCH-ABIS.html

    在未来版本的NDK中将有不同的名字。
    请注意,所有ARM-based ABIs 
    有'TARGET_ARCH'定义为'arm',
    但可能有不同'TARGET_ARCH_ABI'

TARGET_ABI 
    Android和ABI连接,它是定义$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI),
    它是有用的针对一个特定的测试目标系统映像的真实设备。

    默认情况下,'android-3-armeabi'

    (截至到Android NDK 1.6_r1,默认使用'android-3-arm')

NDK提供的宏: 
- - - - - - - - - - - - - - -

以下是GNU Make 'function'宏,通过使用'$(call <function>)'。它返回文本信息。

my-dir
    返回最后包含Makefile文件的路径,通常是Android.mk的目录。

        LOCAL_PATH := $(call my-dir)

    重要提示:由于GNU make的工作方式,真正返回的路径是最后一个
    包含Makefile文件的路径。所以,请不要包含另一个文件后。

    例如,考虑下面的例子:

       LOCAL_PATH := $(call my-dir)

        ...声明一个模块

       include $(LOCAL_PATH)/foo/Android.mk

       LOCAL_PATH := $(call my-dir)

        ...另一个模块声明

    这里的问题是,第二次调用'my-dir'将返回$PATH/foo.

    出于这个原因,最好把其他一切包含在最后一个Android.mk,如:

        LOCAL_PATH := $(call my-dir)

        ... 声明一个模块

        LOCAL_PATH := $(call my-dir)

        ... 另一个模块声明

        # 特别的包含在最后一个Android.mk
        include $(LOCAL_PATH)/foo/Android.mk

    如果这是很不方便,保存第一次my-dir的值在一个变量,然后供其他地方调用:

        MY_LOCAL_PATH := $(call my-dir)

        LOCAL_PATH := $(MY_LOCAL_PATH)

        ... 声明一个模块

        include $(LOCAL_PATH)/foo/Android.mk

        LOCAL_PATH := $(MY_LOCAL_PATH)

        ... 另一个模块声明

 

all-subdir-makefiles
    当前'my-dir'路径下列出所有子目录位置.
    例如,考虑以下层次:

        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

this-makefile
    返回当前的Makefile文件的路径

parent-makefile
    返回在Makefile中包含树中的父路径, 
    即包含了当前Makefile的Makefile的路径

grand-parent-makefile
    你猜怎么着...

import-module
    这个功能是通过名字找到包含Android.mk的另一个模块.
    一个典型的例子是:

      $(call import-module,<name>)

    这将列表中查找标签<名称>中的模块

    更多详情请阅读docs/IMPORT-MODULE.html

Module-description variables:
- - - - - - - - - - - - - - -

以下变量是用来描述你的编译系统的模块.
你应该定义它们在'include $(CLEAR_VARS)'和'include $(BUILD_XXXXX)'之间。
以前写的,$(CLEAR_VARS)是一个脚本,将取消定义/清除所有这些变量,除非明确 
注意到在他们的描述.

LOCAL_PATH 
    这个变量是用来指定当前文件的路径。 
    你必须定义它在你Android.mk开始,

      LOCAL_PATH := $(call my-dir)

    这个变量不被$(CLEAR_VARS)清除,所以只需在一个Android.mk定义

LOCAL_MODULE 
    这是你的模块名。它必须是全局唯一的,不得包含任何空间。
    您必须定义它在包括任何$(BUILD_XXXX)脚本之前。

    默认情况下,模块名称决定了生成的文件名称, 
    例如:lib<foo>.so。对于一个共享库命名为<foo>.
    你可以参考其他模块正常生成文件的名称(或Android.mk 
    或Application.mk)

    您可以覆盖默认的LOCAL_MODULE_FILENAME(见下文)

LOCAL_MODULE_FILENAME 
    这个变量是可选的,允许您重新定义生成的文件的名称.
    默认情况下,模块<foo>将生成一个静态库名字为lib<foo>.a
    或者一个共享库lib<foo>.so,这是标准的Unix规定.

    你可以通过覆盖定义LOCAL_MODULE_FILENAME,例如:

        LOCAL_MODULE := foo-version-1
        LOCAL_MODULE_FILENAME := libfoo

    注意:您不应该把一个路径或文件扩展名在LOCAL_MODULE_FILENAME上,
    它们将自动被编译系统处理.

LOCAL_SRC_FILES 
    这里列出要编译源文件.只列出将被传递到编译器的文件,
    编译系统会自动帮你查找依赖关系.

    请注意,所有源文件是相对于LOCAL_PATH,例如:

      LOCAL_SRC_FILES := foo.c \
                         toto/bar.c

    注意:编译文件始终使用Unix-style的正斜杠(/).
          Windows风格的反斜线将不会得到正确处理.

LOCAL_CPP_EXTENSION 
    这个选项用来定义C++源文件扩展名.默认是'.cpp'
    但你可以改变它。例如:

       LOCAL_CPP_EXTENSION := .cxx

LOCAL_C_INCLUDES 
    一个可选列表的路径,相对于NDK根目录, 
    这将被追加到包含搜索路径时编译来源
    (C语言,C++和汇编).例如:

        LOCAL_C_INCLUDES := sources/foo

    或者:

        LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo

    这些放在任何相应LOCAL_CFLAGS / LOCAL_CPPFLAGS的前面
   
    LOCAL_C_INCLUDES路径自动使用ndk-gdb的本地调试。


LOCAL_CFLAGS 
    可选编译器标志描述何时编译C/C++源文件.

    这是指定的宏定义编译选项。

    重要事项:尽量不要在你的Android.mk更改优化/调试级别,
    Application.mk可以自动处理您所指定适当的信息,
    让NDK产生有用的调试过程中使用的数据文件。

    注意:在android-ndk-1.5_r1,这个标志只使用于C,不适用于C/++.
    这已得到纠正,以匹配Android编译系统的行为.
    (您现在可以使用LOCAL_CPPFLAGS指定为C++)。

    它可以指定额外的包含路径LOCAL_CFLAGS += -I<path>,
    但是,它是最好使用LOCAL_C_INCLUDES, 
    对于这一点,因为路径将在本机也可使用ndk-gdb调试程序

LOCAL_CXXFLAGS 
    LOCAL_CPPFLAGS的别名.注意,使用此标志是过时的,
    因为在未来的NDK版本它可能会消失.

LOCAL_CPPFLAGS 
    可选的编译器标志设置将要通过时,只编译c++源文件.
    他们将出现在编译器的命令行。

    注意:在android-ndk-1.5_r1,标志适用于 
          C和C++.这已得到纠正.以匹配Android编译系统的行为.
    (您现在可以使用LOCAL_CPPFLAGS指定为C++)。

LOCAL_STATIC_LIBRARIES 
    链接静态库的列表(BUILD_STATIC_LIBRARY)

LOCAL_SHARED_LIBRARIES 
    链接共享库的列表,这个是必要的,因为会嵌入并生成对应的文件

LOCAL_LDLIBS 
    编译你的模块时,额外的链接标志.
    可以通过模块的名字来链接,使用'-l'前缀.
    例如,以下将告诉链接器生成一个模块链接到/system/lib/libz.so

      LOCAL_LDLIBS := -lz

    参见文档:docs/STABLE-APIS.html 哪些你不需要链接
   

LOCAL_ALLOW_UNDEFINED_SYMBOLS 
    默认情况下,你未引用但是却试图建立一个共享库会出现“未定义的符号”错误。
    这是一很大的帮助,去捕捉你的源代码中的错误。

    但是,如果由于某种原因,你需要禁用这一检查,请将此 
    变量为'true'。请注意,相应的共享库可能会在运行时加载失败.

LOCAL_ARM_MODE 
    默认情况下,ARM目标二进制文件将生成'thumb'模式,
    其中每个指令都是16位宽。您可以定义该变量'arm' ,
    如果你想强制模块的目标文件为'arm'(32位指令)模式。例如:

       LOCAL_ARM_MODE := arm

    请注意,您也可以指示编译系统只建立特定在ARM模式源通过追加一个'.arm'它的源文件后缀.
    例如,使用:

       LOCAL_SRC_FILES := foo.c bar.c.arm

    告诉编译系统也编译'bar.c'在ARM模式,并 
    根据LOCAL_ARM_MODE编译foo.c

    注意:在Application.mk中设置APP_OPTIM为'debug'会强制生成ARM二进制模式.
         这种在工具链中的bug不太好用thumb代码处理

LOCAL_ARM_NEON 
    这个变量定义为'true'允许在C/C++源码中使用ARM高级SIMD 
    (a.k.a. NEON),以及NEON指令集文件中.

    你应该只定义'armeabi-v7a' ABI符合ARMv7的设置.
    请注意,并非所有的ARMv7基于CPU支持的NEON指令集扩展,
    而且您应执行运行时的检测,以便能够在运行时使用这个代码安全。
    要了解更多,请阅读docs/CPU-ARM-NEON.html和docs/CPU-FEATURES.html.

    另外,您也可以指定只有特定的源文件 
    可能是编译的NEON支持的,你要使用'.neon',
    如:

        LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon

    在这个例子中,'foo.c'将被编译为thumb+neon模式, 
    'bar.c'将编译为'thumb'模式,'zoo.c'将编译为 
    'arm+neon'模式

    注意.如果同时使用,'.neon'后缀必须出现在'.arm'后缀之后. 
   (即foo.c.arm.neon,但不能为foo.c.neon.arm)

LOCAL_DISABLE_NO_EXECUTE 
    Android NDK r4的增加"NX bit"安全功能的支持。 
    这是默认启用,但是你可以禁用它。
    需要通过设置此变量为'true'。

    注意:此功能不修改ABI,只启用内核对象的ARMv6 + CPU的设备。
    生成的机器码启用此功能在设备上运行不修改运行早期的CPU架构。

    有关详细信息,请参阅:

        http://en.wikipedia.org/wiki/NX_bit
        http://www.gentoo.org/proj/en/hardened/gnu-stack.xml

LOCAL_EXPORT_CFLAGS 
    定义这个变量来记录的C/C++编译器标志.
    将添加到所有LOCAL_CFLAGS定义中使用
    LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES。

    例如,考模块'foo'定义:

        include $(CLEAR_VARS)
        LOCAL_MODULE := foo
        LOCAL_SRC_FILES := foo/foo.c
        LOCAL_EXPORT_CFLAGS := -DFOO=1
        include $(BUILD_STATIC_LIBRARY)

    而另一个模块,名为'bar',依赖于'foo': 
    
        include $(CLEAR_VARS)
        LOCAL_MODULE := bar
        LOCAL_SRC_FILES := bar.c
        LOCAL_CFLAGS := -DBAR=2
        LOCAL_STATIC_LIBRARIES := foo
        include $(BUILD_SHARED_LIBRARY)

    这时,标志'-DFOO=1 -DBAR=2'将被传递给编译器
    编译生成bar.c

    导出标志预置到你的模块的LOCAL_CFLAGS,这样你就可以轻松覆盖它们。
    他们也传递性:如果'zoo'取决于 
     'bar'就依赖于'foo',这下'zoo'也将继承所有标志依赖于'foo'。

    最后,编译模块不使用导出标志。
    在上述例子中,-DFOO=1就不会被传递到编译器,foo/foo.c.

LOCAL_EXPORT_CPPFLAGS 
    类似于LOCAL_EXPORT_CFLAGS,这是对于C++的

LOCAL_EXPORT_C_INCLUDES 
    类似LOCAL_EXPORT_CFLAGS,但是为C的包含路径。 
    这样你能使用有条件选择'bar.c'包含的头文件给'foo'

LOCAL_EXPORT_LDLIBS 
    类似LOCAL_EXPORT_CFLAGS,但链接标记不同。
    请注意链接标志将被追加到你的模块的LOCAL_LDLIBS 
    但是,由Unix链接器完成

    这通常是非常有用的,模块'foo'是一个静态库,并依赖于一个系统库。
    然后可以LOCAL_EXPORT_LDLIBS导出依赖。例如:

        include $(CLEAR_VARS)
        LOCAL_MODULE := foo
        LOCAL_SRC_FILES := foo/foo.c
        LOCAL_EXPORT_LDLIBS := -llog
        include $(BUILD_STATIC_LIBRARY)

        include $(CLEAR_VARS)
        LOCAL_MODULE := bar
        LOCAL_SRC_FILES := bar.c
        LOCAL_STATIC_LIBRARIES := foo
        include $(BUILD_SHARED_LIBRARY)

    libbar.so将编译时,将链接-llog在最后,
    因为它依赖于'foo'。

LOCAL_FILTER_ASM 
    shell命令定义这个变量,用于过滤程序集文件,
    或LOCAL_SRC_FILES

    当它被定义,下列情况:

       - 任何C或C++源文件生成到一个临时文件
       (而不是被编译成目标文件)

       - 任何临时文件,LOCAL_SRC_FILES列出的文件
        通过发送LOCAL_FILTER_ASM命令
        生成_another_临时文件。

       - 这些过滤汇编文件被编译成目标文件。

    换句话说,如果你有:

      LOCAL_SRC_FILES  := foo.c bar.S
      LOCAL_FILTER_ASM := myasmfilter

 foo.c --1--> $OBJS_DIR/foo.S.original --2--> $OBJS_DIR/foo.S --3--> $OBJS_DIR/foo.o
    bar.S                                 --2--> $OBJS_DIR/bar.S --3--> $OBJS_DIR/bar.o

    1 对应的编译器
    2 过滤器
    3 汇编
    
    该过滤器必须是一个独立的shell命令取 
    名称作为它的第一个参数输入文件,输出的名称 
    文件作为第二个,如:

        myasmfilter $OBJS_DIR/foo.S.original $OBJS_DIR/foo.S
        myasmfilter bar.S $OBJS_DIR/bar.S


你可能感兴趣的:(Module,Build,Path,include,library,makefile)