NDK官方开发指南翻译之 Android.mk

时间:2021-03-28 05:34:36
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://ikinglai.blog.51cto.com/6220785/1215819

Android.mk 文件语法指南


前言:

---------------------


本文档描述了cc++编写的程序用Android NDK编译时,编译文件Android.mk的语法结构。为了便于理解下面的内容,假设你已经阅读了前面OVERVIEW部分,了解了它们的作用和用法。


概要:

---------


Android.mk是用来描述源文件是如何进行编译的。更具体的:


-Android.mk实际上是一个轻量级的Makefile,它会被编译系统解析一次或多次。因此,你应该尽可能少的声明变量,同时不要假定在解析过程中没有定义任何东西。


-Android.mk是用来允许你将源文件组织在一个‘modeles’中。一个modele是以下两种形式之一:

  - a static library  静态库

             -  a shared library 动态库


只有动态库才会安装或者拷贝到你的应用程序包中,但是静态库可以用来生成动态库。


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


-编译系统为你处理了很多细节。例如,你不需要在Android.mk中列出头文件,也不需要显示的列出文件之间的依赖关系。NDK编译系统将会自动为你计算这些东西。


这同样意味着,当你升级到新的NDK版本时,你可以得到新的交叉工具和平台的支持,而不需要修改你的Android.mk文件。



简单例子:

----------------


在介绍语法细节之前,让我们看一下“hello JNI”这个简单的例子,文件如下:


      apps/hello-jni/project


这里我们可以看到:


-src’目录包含了Android工程的所有java源文件。


    -jni’目录包含了本地源文件。例如,‘jni/hello-jni.c’。


这个源文件实现了一个简单的动态库,而这个动态库实现了一个native方法,这个方法返回一个stringVM应用。


-jni/Android.mk’文件描述了NDK编译系统的动态库。包括:


----------------------分割线----------------------------------

LOCAL_PATH :=$(call my-dir)


include$(CLEAR_VARS)


LOCAL_MODULE   := hello-jni

LOCAL_SRC_FILES  := hello-jni.c


include$(BUILD_SHARED_LIBRARY)

----------------------分割线----------------------------------


现在,我们解释一下:


LOCAL_PATH  :=  $(callmy-dir)


Android.mk文件必须先定义LOCAL_PATH变量,它用来定位开发树中的源文件。在本例中,编译系统提供的宏‘my-dir’,用来返回当前目录(即这个目录包含了Android.mk文件自身)。


include$(CLEAR_VARS)


CLEAR_VARS变量由编译系统提供,它指向一个特殊的GNU Makefile,这个Makefile会为你清除很多LOCAL_XXX这样的变量(如LOCAL_MODULELOCAL_SRC_FIELS, LOCAL_STATIC_LIBARIES, 等等),当然LOCAL_PATH除外。这样做是必须的,因为所有的编译控制文件都是在单一的GNU Make可执行上下文环境中解析的,而在这个上下文环境中所有的变量都是全局的。


LOCAL_MODULE  := hello-jni


LOCAL_MODULE变量用来唯一标示Android.mk文件中的每个module。这个名字必须是唯一的,并且不能包含任何空白字符。编译系统会根据生成的文件自动添加前缀和后缀。换句话说,一个叫‘foo’的动态库module,会生成‘libfoo.so’。


重要提示:

如果你的module命名为‘libfoo’,编译系统将不会另外添加‘lib’前缀,同样会生成libfoo.so。(注:为了养成统一习惯,个人建议不要自行加lib前缀了)


LOCAL_SRC_FILES  := hello-jni.c


LOCAL_SRC_FILES变量必须包含cc++源文件列表,这些源文件会被编译和组装到一个module中。注意这里你不必列出头文件和包含文件,因为编译系统会自动为你计算出它们之间的依赖关系;你只需要列出源文件,这些源文件将直接传递给编译器。


注意,默认的c++源文件的扩展名是‘.cpp’,当然你可以通过定义变量LOCAL_CPP_EXTENSION指定不同的扩展名,但是要记住不能忘记前面的那个点(即‘.cxx’可以工作,但是‘cxx’不行的)。


include $(BUILD_SHARED_LIBRARY)


BUILD_SHARED_LIBRARY是编译系统提供的一个变量,它指向一个GNU Makefile脚本,这个脚本负责收集从最近的‘include $(CLEAR_VARS)’,在LOCAL_XXX变量中定义的所有信息,同时决定编译什么,以及怎么编译。显然,BUILD_STATIC_LIBRARY是用来生成静态库的。


samples目录中,还有很多复杂的例子,在Android.mk文件中都有注释,可以自行查看。



参考:

------------


Android.mk中还有一序列的变量,你要么依赖于它,要么要定义它。你可以根据自己的用法,定义其他变量,但是NDK编译系统保留了以下变量名字:


-LOCAL_开头的名称(如,LOCAL_MODULE

-PRIVATE_ , NDK_ , APP_ 开头的名称(内部使用)

-小写的名称(内部使用,如‘my-dir’)


如果你需要在Android.mk中定义自己的变量,推荐用MY_作为前缀,一个简单的例子:


----------------------分割线----------------------------------

MY_SOURCES :=foo.c

Ifneq($(MY_CONFIG_BAR), )

 MY_SOURCES += bar.c

endif


  LOCAL_SRC_FILES += $(MY_SOURCES)

----------------------分割线----------------------------------




NDK提供的变量:

----------------------


Android.mk文件解析之前,编译系统定义了这些GNU Make变量。注意在某些特定的环境下,NDK可能会多次解析Android.mk文件,对于以下这些变量每次可能会使用不同的定义:


CLEAR_VARS

指向一个编译脚本,这个脚本会清除在“Module-descrptionsection下面列出的所有LOCAL_XXX变量。在你开始声明一个新的module之前,你必须包含这个脚本,如:


include $(CLEAR_VARS)


BUILD_SHARED_LIBRARY

指向一个编译脚本,这个脚本会搜集你在module中提供的LOCAL_XXX变量的所有信息,以及决定如何从你列出的源文件中编译目标动态库。注意在包含这个文件之前,你必须至少先定义LOCAL_MODULELOCAL_SRC_FILES。如:


include$(BUILD_SHARED_LIBRARY)


记住,这会生成一个lib$(LOCAL_MODULE).so文件


BUILD_STATIC_LIBRARY

BUILD_STATIC_LIBRARY用来编译目标静态库。静态库不会拷贝到你的工程或者应用包中,但是它可以用来编译动态库(参考下面的LOCAL_STATIC_LIBRARIES LOCAL_WHOLE_STATIC_LIBRARIES)。

使用示例:


 include $(BUILD_STATIC_LIBRARY)


注意,这会生成一个lib$(LOCAL_MODULE).a文件。


PREBUILT_SHARED_LIBRARY

指向一个编译脚本,这个脚本用来指定一个预编译动态库。不像BUILD_SHARED_LIBRARYBUILD_STATIC_LIBRARYLOCAL_SRC_FILES的值必须是一个编译好的动态库的路径(如foo/libfoo.so),而不是源文件。


你可以使用LOCAL_PREBUILTS变量引用另外一个module中编译好的库(请查看PREBUILTS中的相关内容)。


PREBUILT_STATIC_LIBRARY

这个和PREBUILT_SHARED_LIBRARY相同,只是表示一个静态库而已。同样请查看PREBUILTS中的相关内容。


TARGET_ARCH

它是由整个Android开源编译指定的目标CPU架构的名称。这个值为为‘arm’,表示兼容任何ARM的编译,并独立于CPU架构的修订。


TARGET_PLATFORM

Android.mk文件解析的时候,Android目标平台的名称。如,‘android-3’对应Android1.5 系统镜像。如果想要了解平台名称和对应Android系统镜像的完整信息,请查看STABLE-APIS相关内容。


TARGET_ARCH_ABI

Android.mk文件解析的时候,目标CPU+ABI的名称。目前支持两个值:


armabi

       For ARMv5TE


Armabi-v7a


注意:升级到Android NDK1.6_r1,这个变量仅仅用‘arm’来定义。但是,现在这个值已经被重新定义,以便更好的匹配Android的内部使用。


想要了解更多关于ABI架构和相关的兼容性问题,请阅读CPU-ARCH-ABIS相关部分。


在未来的NDK发布版本中,其他目标的ABIs可能会被引入,并且可能会有不同的名字。注意所有基于ARMABIs都会将‘TARGET_ARCH’定义为‘arm’,但是可能会有不同的‘TARGET_ARCH_ABI’。


TARGET_ABI

目标平台和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所在目录。在Android.mk开头用来定义LOCAL_PATH是非常有用的:


   LOCAL_PATH := $(call my-dir)


重要提示:由于GNU Make的工作方式,在解析编译脚本过程中,它实际上返回的是最近一次包含Makefile文件的路径。不要在包含另一个文件后调用my-dir


例如,考虑下面的例子:


   LOCAL_PATH := $(call my-dir)


… 声明一个module


       include$(LOCAL_PATH)/foo/Android.mk  


       LOCAL_PATH := $(callmy-dir)


… 声明另一个module


在第二次调用my-dir的时候,由于在它前面包含了$(LOCAL_PATH)/foo/Android.mk,因此LOCAL_PATH被定义为$PATH/foo,而不是$PATH


因为这样,比较好的做法是,在Android.mk的最后再包含其他文件,例如:


     LOCAL_PATH := $(call my-dir) 

     ... declare one module 

     LOCAL_PATH := $(call my-dir)  

    ... declare another module          
   # extra includes at the end of the Android.mk        
   include $(LOCAL_PATH)/foo/Android.mk


如果这样不方便的话,把第一次调用my-dir的值保存到一个变量中。如:


MY_LOCAL_PATH := $(call my-dir)  

   LOCAL_PATH := $(MY_LOCAL_PATH)  

   ... declare one module 

   include $(LOCAL_PATH)/foo/Android.mk  

   LOCAL_PATH := $(MY_LOCAL_PATH)  

   ... declare another module



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中的文件。



this-makefiles

返回当前Makefile所在路径(即函数被调用的位置)。


parent-makefile

返回目录树结构中parentMakefile的路径。即被当前Makefile包含的那个Makefile文件的路径。


grand-parent-makefile

你猜。。。(汗。。。)


import-module

允许你通过名字来查找和包含另一个module中的Android.mk文件。一个典型的例子是:


$(call import-module, <name>)


它会在NDK_MODULE_PATH环境变量引用的目录列表中,查找所有标记为<name>mudule,并自动为你包含它的Android.mk文件。


请阅读IMPORT-MODULE相关内容,了解更多细节。



Module-description变量:
----------------------------------


下面的这些变量,用来描述编译系统中的module。你必须在'include $(CLEAR_VARS)'  'include $(BUILD_XXXXX)'之间来定义一些变量。根据前面的描述,$(CLEAR_VARS)会清除所有这些变量的定义,除非在它们的描述中显示的指出来。


LOCAL_PATH

这个变量表示当前文件的路径。你必须在Android.mk的开始的时候定义:


       LOCAL_PATH := $(call my-dir)


这个变量不会被$(CLEAR_VARS)清除,因此每一个Android.mk只需要定义一次(即使一个文件里面定义了很多个modules)。


LOCAL_MODULE

这个是module的名称。在所有modules中,它必须是唯一的,不能包含空白字符。你必须在包含$(BUILD_XXXX)脚本之前定义它。


默认情况下,module name决定了生成文件的名称,如module的名称是<foo>,那么共享库的名字是lib<foo>.so。但是,在NDK编译脚本中(Android.mk或者Application.mk),你要引用其他module,只需要通过普通的名称(如<foo>)引用即可。


你可以通过LOCAL_MODULE_FILENAME覆盖这个默认值(see below)。

LOCAL_MODULE_FILENAME
这个变量是可选的,允许你重新定义生成文件的名称。默认,module <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
这个是编译module的源文件列表。只有在这些列表中的源文件才能传递给编译器,编译系统会自动为你计算依赖关系。

注意这些源文件都是相对于LOCAL_PATH,你可以使用path components,如:

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

注意:在编译文件中,总是要用Unix风格的正斜杠(/),而不要使用windows风格的反斜杠。

LOCAL_CPP_EXTCEPTION
这是一个可选的变量,用来定义C++源文件的后缀。必须要以一个点开头,默认的是‘.cpp’,但是你可以修改它。如:

    LOCAL_CPP_EXTCEPTION := .cxx

NDK r7开始,你可以在这个变量中定义一序列的后缀,如:

    LOCAL_CPP_EXTCEPTION :=  .cxx  .cpp  .cc

LOCAL_CPP_FEATURES
这是一个可选的变量,可以让你的代码使用一些c++的特性。为了让你的代码使用RTTI(RunTime Type Information),可以使用:

       LOCAL_CPP_FEATURES := rtti

为了让你的代码支持c++异常,可以使用:

        LOCAL_CPP_FEATURES := exceptions

你可以同时使用它们(顺序不重要)

LOCAL_CPP_FEATURES := rtti features

这个变量的作用是,当从源代码编译module的时候,可以启用正确的compiler/linker标志。对于预编译二进制文件,这同样有助于声明二进制文件所依赖的特性,从而确保最终的链接器能正确工作。

建议你使用这个变量,代替在LOCAL_CPPFLAGS中直接定义-frtti-fexceptions这种用法。

LOCAL_C_INCLUDES
相对于NDK根目录的一个可选路径列表,当编译所有源代码时(cc++或者两者的组合),将会添加到包含搜索路径中。如:

    LOCAL_C_INCLUDES := sources/foo

或者甚至:

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

这些要放在LOCAL_CFLAGS / LOCAL_CPPFLAGS中对应包含的flag的前面。

当用ndk-gdb启动本地调试的时候,LOCAL_C_INCLUDES 同样会自动使用。

LOCAL_CFLAGS
当编译cc++源代码的时候,传递给编译器的可选的标志集合。

对于指定附加宏的定义或者编译选项,是非常有帮助的。

重要:在Android.mk中不要试图改变optimization/debugging的级别,通过在Application.mk中指定合适的信息,系统会帮你自动处理,而且在debug过程中,NDK会生成有用的数据文件。

注意:在android-ndk-1.5_r1中,相应的标志只能应用在c文件上,不能用在c++上。这个问题已经被修正,从而匹配整个Android编译系统的行为。(你可以使用LOCAL_CPPFLAGSc++源文件指定标志)

你可以通过LOCAL_CFLAGS += -I<path>来指定额外的包含路径,但是,对于这个使用LOCAL_C_INCLUDES会更好,因为这些路径可能在用ndk-gdb本地调试的时候会被用到。


LOCAL_CXXFLAGS
LOCAL_CPPFLAGS的别名。注意在后面的版本中,这个标志可能会被移除掉。


LOCAL_CPPFLAGS
当编译c++源文件的时候(只编译c++),传递给编译器的可选的标志集合。它们出现在LOCAL_CFLAGS之后的编译器的命令行上。

注意:在android-ndk-1.5_r1中,相应的flag同时运用于cc++源代码。这些已经得到修正,以匹配整个Android编译系统。(现在你可以使用LOCAL_CFLAGS来指定cc++源代码的标志)。

LOCAL_STATIC_LIBRARIES
应该链接到这个module的静态库modules(用BUILD_STATIC_LIBRARY编译)列表。这在共享库模块才有意义。

LOCAL_SHARED_LIBRARIES
运行时这个module依赖的动态共享库‘modules’列表。这个在链接的时候是有必要的,同时会在生成的文件中嵌入相应的信息。

LOCAL_WHOLE_STATIC_LIBRARIES
它是LOCAL_STATIC_LIBRARIES(用来表达相应library module)的一个变体,对于链接器它应该使用‘whole archives’。可以查看GNU 链接器的文档来了解–whole-archive这个标志。

当很多静态库之间中有环形依赖的时候,这个通常是非常有用的。注意当用它来编译动态库的时候,会强制将你的整个静态库中的所有对象文件添加到最终的二进制文件中。虽然在生成可执行文件的时候是不正确的。

LOCAL_LDLIBS
当编译module时,被使用的附加的链接器标志列表。使用“-l”前缀来传递指定系统库的名称是非常有用的。例如,下面这些将告诉链接器生成一个module,在加载的时候链接到/system/lib/libz.so

    LOCAL_LDLIBS := -lz

查看STABLE-APIS相关内容,了解这个NDK版本能够链接的系统库列表。

LOCAL_ALLOW_UNDEFINED_SYMBOLS
默认情况下,当试图编译动态库时,如果没有定义任何引用,将会导致undefined symbol”的错误。这对在代码中捕捉bug是非常有帮助的。

然而由于某些原因你需要禁用这个检查,设置这个值为‘true’。注意对应的动态库可能在运行时会加载失败。




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

        LOCAL_ARM_MODE := arm

注意你也可以在源文件加上后缀‘.arm’来告诉编译系统,你只想对某个源文件使用arm指令。例如:

       LOCAL_SRC_FILES :=foo.c bar.c.arm


告诉编译系统总是用ARM模式编译‘bar.c’,根据LOCAL_ARM_MODE的值编译foo.c

注意:在Application.mk设置APP_OPTM为‘debug’,同样会强制生成ARM二进制文件。这是因为工具链调试器存在的一个bug,并没有很好的处理thumb代码。


LOCAL_ARM_NEON
定义这个变量为‘true’,允许在cc++代码中使用ARM Advanced SIMD (又名 NEONGCC指令,在组织文件中使用NEON指令。

只有目标为‘armeabi-v7aABI(对应于ARMv7指令集),才应该定义它。注意并不是所有基于ARMv7CPUs都支持NEON指令集扩展,比较安全的做法是在运行时检测是否能够使用这个代码。如果要了解更多细节,请阅读CPU-ARM-NEONCPU-FEATURES相关内容。

你也可以使用‘.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的设备上启用。

想要了解更多信息,请看:

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


LOCAL_DISABLE_RELRO
默认情况下,NDK编译后的代码是只读的进行移动位置并得到GOT保护。这个会指示运行时链接器标记特定的内存区是只读的,在移动位置之后。这样会使得某些安全漏洞(如GOT覆盖)更难执行。

默认它是启用的,但是如果你确实需要,你可以禁用它通过设置变量为‘true’。

注意:这些保护只对新的Android设备有效("JellyBean" 和更高的版本)。代码依然能够运行在旧版本上(尽管没有内存保护)。


想要了解更多信息,请看:

http://isisblogs.poly.edu/2011/06/01/relro-relocation-read-only/        http://www.akkadia.org/drepper/nonselsec.pdf (section 6)



LOCAL_EXPORT_CFLAGS 
定义这个变量是为了记录c/c++编译器flags的集合,这些flags会被添加到任何其他module定义的LOCAL_CFLAGS中,而这个module通过LOCAL_STATIC_LIBRARIES 或者LOCAL_SHARED_LIBRARIES使用它。

例如,考虑modulefoo’下面的定义:

include $(CLEAR_VARS)        

LOCAL_MODULE := foo        

LOCAL_SRC_FILES := foo/foo.c        

LOCAL_EXPORT_CFLAGS := -DFOO=1        

include $(BUILD_STATIC_LIBRARY)


另一个modulebar’,依赖于它:

include $(CLEAR_VARS)        

LOCAL_MODULE := bar        

LOCAL_SRC_FILES := bar.c        

LOCAL_CFLAGS := -DBAR=2        

LOCAL_STATIC_LIBRARIES := foo        

include $(BUILD_SHARED_LIBRARY)


当编译bar.c的时候,标志'-DFOO=1 -DBAR=2'将会传递给编译器。

Exported flags被加在你moduleLOCAL_CFLAGS中,所以你可以简单的覆盖它们。它们也可以传递:如果‘zoo’依赖‘bar’,‘bar’依赖‘foo’,那么‘zoo’将继承‘foo’导出的所有flags

最后,当编译的module导出它们时,exported flags不会被使用。在上面的例子中,当编译foo/foo.c时,-DFOO=1不会传递给编译器。


LOCAL_EXPORT_CPPFLAGS
LOCAL_EXPORT_CFLAGS相同,但是只针对c++标志。

LOCAL_EXPORT_C_INCLUDES
LOCAL_EXPORT_CFLAGS相同,但是它是针对c包含路径的。这是非常有用的,如果‘bar.c’想要包含modulefoo’提供的头文件。

LOCAL_EXPORT_LDLIBS
LOCAL_EXPORT_CFLAGS相同,但是它是针对链接器标志的。注意由于Unix链接器的工作方式,被导入的链接器标志将append到你moduleLOCAL_LDLIBS中。

这是非常有用的,当modulefoo’是一个静态库和它有代码依赖于系统库的时候。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        


这里,libbar.so在链接器命令的尾部会使用-llog进行编译,表明它依赖于系统日志库,因为它依赖于‘foo’。


LOCAL_SHORT_COMMANDS
设置这个变量为‘true’,当你的module有很多的源文件,或者依赖很多的静态或动态库。这会强制编译系统使用一个中间的列表文件,并通过@$(listfile) 语法和library archiver 或者 static linker一起使用。

这在Windows上是非常有用的,因为它的命令行只接收最大8191个字符,这对于复杂的工程来说太小了。

这同样也会影响单个源文件的编译,如果将所有的编译器选项放在列表文件里面。


注意如果设置了‘true’以外的值,都会恢复成默认行为。你也可以在Android.mk文件中定义APP_SHORT_COMMANDS来强制使你的工程中的所有modules使用这项功能。

注意:默认我们不推荐启用这个功能,因为它会使得编译变慢。

LOCAL_FILTER_ASM
shell命令定义这个变量,将会过滤从你的LOCAL_SRC_FILES汇编或生成的文件。

当它被定义时,将发生下面的事情:

- 所有的c或者c++会生成到一个临时汇编文件(而不是编译进对象文件中)。

- 任何临时的、在LOCAL_SRC_FILES列出的汇编文件通过LOCAL_FILTER_ASM命令发送来生成另一个临时的汇编文件。

            - 这些被过滤后的汇编文件被编译到对象文件中。

换句话说,如果你有:

 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