zoukankan      html  css  js  c++  java
  • Android.mk基础

    1、前言

    Android.mk用于向编译系统描述源文件和共享库,它实际上是编译系统解析一次或多次的微小GNU makefile片段。它的语法支持将源文件分组为模块,模块是静态库、共享库或独立的可执行文件。

    2、简单示例

    首先来看一个最简单的Android.mk的例子,如下所示:

    # A simple Android.mk
    
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES := hello.c
    LOCAL_MODULE := helloworld
    include $(BUILD_EXECUTABLE)

    对该Android.mk文件进行解析,如下:

    LOCAL_PATH := $(call my-dir)

    每个Android.mk文件必须以定义LOCAL_PATH为开始,它用于在开发项目文件中查找源文件,而宏my-dir则由编译系统提供,返回包含Android.mk的目录路径。

    include $(CLEAR_VARS)

    CLEAR_VARS变量由编译系统提供,并指向一个特定的GNU Makefile,由它负责清理很多LOCAL_XXX的值,例如:LOCAL_MODULE、LOCAL_SRC_FILES等,但是不清理LOCAL_PATH,这个清理动作是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的,清理后才能避免相互影响。

    LOCAL_SRC_FILES := hello.c

    LOCAL_SRC_FILES变量必须包含将要打包成模块的C/C++源文件,不必列出头文件,编译系统会自动找出依赖的文件,缺省的C++源码的拓展名为.cpp,也可以通过LOCAL_CPP_EXTENSION进行修改。

    LOCAL_MODULE := helloworld

    LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块,名字必须唯一并且不包含空格,Build System会自动添加适当的前缀和后缀。

    include $(BUILD_EXECUTABLE)

    BUILD_EXECUTABLE是编译系统提供的一个变量,指向一个特定的GNU Makefile脚本,表示要编译成一个可执行的文件,如果想编译成动态库则可以用BUILD_SHARED_LIBRARY,如果想编译成静态库则可以用BUILD_STATIC_LIBRARY。

    3、保留的变量

    在编写Android.mk文件时应该使用或者定义的变量,可以视具体情况定义其他的变量,但是NDK编译环境保留以下变量名:

    (1)LOCAL_开头的变量名(例如:LOCAL_MODULE)

    (2)PRIVATE、NDK_以及APP_开头的变量名(内部使用)

    (3)小写命名(内部使用,如my-dir)

    如果要在Android.mk文件中定义自己的变量,建议使用前缀MY_开头,例如:

    MY_SOURCES := foo.c
    ifneq ($(MY_CONFIG_BAR),)
        MY_SOURCES += bar.c
    LOCAL_SRC_FILES += $(MY_SOURCES)

    4、NDK提供的变量

    GNU Make在解析Android.mk文件之前由编译环境定义的一些变量,需要注意的是,在某些条件下,NDK可能会多次解析你的Android.mk文件,每一次都会为某些变量进行不同的定义。

    (1)CLEAR_VARS

    指向一个脚本,取消定义在模块变量下面几乎所有的LOCAL_XXX的定义,必须在一个新的模块下面包含这个脚本,如:

    include $(CLEAR_VARS)

    (2)BUILD_SHARED_LIBRARY

    指向一个脚本,收集你提供的所有LOCAL_XXX变量的信息,决定如何根据你列出的源文件编译对应的共享库,注意,在包含这个脚本之前,你必须至少已经定义了LOCAL_MODULE和LOCAL_SRC_FILES,如:

    include $(BUILD_SHARED_LIBRARY)

    注意:这会生成一个名为lib$(LOCAL_MODULE).so文件。

    (3)BUILD_STATIC_LIBRARY

    该变量类似于BUILD_SHARED_LIBRARY,用来编译生成静态库,静态库不会拷贝到你的工程,但是可以用来生成共享库,如:

    include $(BUILD_STATIC_LIBRARY)

    注意:这会生成一个名为lib$(LOCLA_MODULE).a文件。

    (4)PREBUILT_SHARED_LIBRARY

    指定一个脚本,用来指定一个预置的共享库,和BUILD_SHARED_LIBRARY以及BUILD_SHARED_LIBRARY不同的是,LOCAL_SRC_FILES的值必须是一个预置共享库的路径,而不是一个源文件,如foo/libfoo.so文件,还可以在另一个模块中使用LOCAL_PREBUILTS变量来引用预置库。

    (5)PREBUILT_STATIC_LIBRARY

    和PREBUILT_SHARED_LIBRARY类似,但指定一个静态库。

    (6)TARGET_ARCH

    由AOSP指定的CPU架构名称,arm表示与ARM兼容。

    (7)TARGET_PLATFORM

    解析Android.mk时,目标Android平台的名称。

    (8)TARGET_ARCH_ABI

    解析Android.mk时,目标CPU+ABI的名称,如armeabi-v7a。

    (9)TARGET_ABI

    目标平台和abi的连接,由$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI)定义。

    5、NDK提供的函数宏

    下面是GNU Make的宏方法,必须使用$(call <function>)的形式使用,返回文本信息。

    (1)my-dir

    返回上一个包含Makefile文件的路径,通常是当前Android.mk的目录,在Android.mk文件起始位置定义LOCAL_PATH时很有用,如:

    LOCAL_PATH := $(call my-dir)

    注意:由于GNU Make的工作方式,该方法返回在解析编译脚本时最后一次包含Makefile文件的路径,在包含其他文件之后不要调用my-dir,例如下面的例子:

    # Android.mk
    
    LOCAL_PATH := $(call my-dir)
    # Declare one module
    ...
    include $(LOCAL_PATH)/foo/Android.mk
    # Declare another module
    ...

    这里的问题是,第二次调用my-dir会将LOCAL_PATH定义为$(LOCAL_PATH)/foo/而不是$(LOCAL_PATH)。

    基于上面的这个原因,在一个Android.mk文件中,将额外的包含动作放在所有内容的后面,如下:

    # Android.mk
    
    LOCAL_PATH := $(call my-dir)
    # Declare one module
    ...
    LOCAL_PATH := $(call my-dir)
    # Declare another module
    ...
    # Extra include at the end of Android.mk
    include $(LOCAL_PATH)/foo/Android.mk

    还可以用一个变量保存第一次调用my-dir的值,如下:

    # Android.mk
    MY_LOCAL_PATH := $(call my-dir)
    LOCAL_PATH := $(MY_LOCAL_PATH)
    # Declare one module
    ...
    includ $(LOCAL_PATH)/foo/Android.mk
    LOCAL_PATH := $(MY_LOCAL_PATH)
    # Declare another module
    ...

    (2)all-subdir-makefiles

    返回位于当前my-dir路径下的所有子目录中的Android.mk组成的列表,例如下面的结构:

    sources/foo/Android.mk
    sources/foo/lib1/Android.mk
    sources/foo/lib2/Android.mk

    如果source/foo/Android.mk文件中包含了这句:

    include $(call all-subdir-makefiles)

    那么,source/foo/lib1/Android.mk和source/foo/lib2/Android.mk会自动地被包含进来。

    (3)this-makefile

    返回当前Makefile文件的路径。

    (4)parent-makefile

    返回包含树中父Makefile文件的路径,如包含当前Makefile的Makefile的路径。

    (5)grand-parent-makefile

    与parent-makefile类似。

    (6)import-module

    该方法通过名字查找和包含另一个模块,通常的用法是:

    $(call import-module,<name>)

    该方法会在NDK_MODULE_PATH环境变量中查找标签为<name>的模块,然后自动地将它的Android.mk包含进来。

    6、模块描述变量

    下面的变量用来向编译环境描述模块,应该在include $(CLEAR_VARS)和include $(BUILD_XXX)之间定义这些变量,$(CLEAR_VARS)会取消定义或者清除所有这些变量。

    (1)LOCAL_PATH

    这个变量表示当前文件所在的路径,必须在Android.mk的开始处定义,可以由下面的命令来完成:

    LOCAL_PATH := $(call my-dir)

    $(CLEAR_VARS)不会清除该变量,因此,每个Android.mk只需定义一次即可。

    (2)LOCAL_MODULE

    模块的名字,每一个模块的名字必须唯一并且不含空格,必须在包含$(BUILD_XXX)脚本之前定义这个变量,默认的,这个名字决定了生成文件的名字,如名为<foo>的模块,共享库的名字为lib<foo>.so。

    (3)LOCAL_MODULE_FILENAME

    这个变量是可选的,帮助重新定义生成文件的名字,默认的情况下,<foo>模块会按照Unix的一般标准生成名为lib<foo>.a的静态库或者名为lib<foo>.so的共享库,可以通过LOCAL_MODULE_FILENAME重新定义生成文件的名字,如下:

    # Android.mk
    LOCAL_MODULE := foo-version-1
    LOCAL_MODULE_FILENAME := libfoo

    注意:不要在LOCAL_MODULE_FILENAME中放路径或者拓展名,这些会被编译系统自动处理。

    (4)LOCAL_SRC_FILES

    用来编译的模块的源文件列表,只需要列出需要被传给编译器的文件,编译环境会自动计算依赖关系,所有的源文件名是相对LOCAL_PATH的,也可以使用路径分隔符,如:

    LOCAL_SRC_FILES := foo.c 
                      fun/bar.c

    (5)LOCAL_CPP_EXTENSIONS

    这是一个可选的变量,用来指示C++的源文件的文件拓展名,默认的是.cpp,但是可以改变它,如:

    LOCAL_CPP_EXTENSION := .cxx

    (6)LOCAL_C_INCLUDES

    这是可选的变量,相对NDK根目录的相对路径列表,在编译所有的源文件时会被添加到搜索路径后面,如:

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

    它们需要放置在LOCAL_CFLAGS/LOCAL_CPPFLAGS之前,在使用ndk-gdb进行native调试时将自动使用LOCAL_C_INCLUDES路径。

    (7)LOCAL_CFLAGS

    这是一个可选的变量,编译C/C++源文件时的编译器flags,可以用来指定额外的宏定义和编译选项。

    (8)LOCAL_CXXFLAGS

    LOCAL_CPPFLAGS的别名。

    (9)LOCAL_CPPFLAGS

    可选的变量,编译C++文件时编译器flags,在编译器命令行中,他们出现在LOCAL_CFLAGS之后。

    (10)LOCAL_STATIC_LIBRARIES

    需要链接到这个模块的静态库module(使用BUILD_STATIC_LIBRARY编译的)列表,只在共享库中有用。

    (11)LOCAL_SHARED_LIBRARIES

    该模块在运行时需要依赖的共享库列表,在链接时需要,并在生成文件中嵌入相应的信息。

    (12)LOCAL_LDLIBS

    编译模块时需要的额外链接flags列表,传递指定的以-l为前缀的系统库,例如,下面的指令会告诉链接器生成一个在加载的时候链接到/system/lib/libz.so的模块:

    LOCAL_LDLIBS := -lz

    (13)LOCAL_ALLOW_UNDEFINED_SYMBOLS

    默认情况下,在编译共享数据库时会遇到未定义的引用,导致未定义符号的错误,这对在源码中抓取log的作用很大,但是,如果考虑到某些原因需要关闭这个选项,将变量设置为true即可。

    (14)LOCAL_ARM_MODE

    默认情况下,以thumb模式生成ARM目标二进制,每一个指令都是16比特宽,如果想强制生成arm(32比特指令)模式下的模块,可以定义这个变量为arm,如下:

    LOCAL_ARM_MODE := arm

    也可以通过在源文件名称后面添加后缀.arm的方式编译系统以指定的arm模式编译源文件,如:

    LOCAL_SRC_FILES := foo.c bar.c.arm

    这会告诉编译系统以arm模式编译bar.c,但根据LOCAL_ARM_MODE的值编译foo.c。

    (15)LOCAL_ARM_NENO

    定义这个变量为true允许在C/C++文件中使用ARM Advanced SIMD GCC(也叫NEON)指令,就像在程序集文件中使用NEON指令一样。

    (16)LOCAL_CFLAGS

    定义这个变量来记录一组C/C++编译flags,这些会被添加到使用这个变量的模块的LOCAL_STATIC_LIBRARIES或者LOCAL_SHARED_LIBRARIES的LOCAL_CFLAGS中,例如:

    # Define "foo" module
    include $(CLEAR_VARS)
    LOCAL_MODULE := foo
    LOCAL_SRC_FILES := foo/foo.c
    include $(BUILD_STATIC_LIBRARY)
    
    # Define "bar" module
    include $(CLEAR_VARS)
    LOCAL_MODULE := bar
    LOCAL_SRC_FILES := bar.c
    LOCAL_CFLAGS := -DBAR=2
    LOCAL_STATIC_LIBRARYS := foo
    include $(BUILD_SHARED_LIBRARY)

    在编译bar.c时会将-DFOO=1 –DBAR=2传给编译器,exported flags会被一层一层的传递,如果zoo依赖于bar,而bar依赖于foo,那么foo中的所有flags会被传给zoo,exported flags在当前module编译时不会被使用,在上面,编译foo/foo.c时不会传递-DFOO=1。

    (17)LOCAL_EXPORT_CPPFLAGS

    和LOCAL_EXPORT_CFLAGS一样,但是只对C++文件。

    (18)LOCAL_EXPORT_C_INCLUDES

    和LOCAL_EXPORT_CFLAGS一样,但记录的是C头文件路径。

    (19)LOCAL_EXPORT_LDLIBS

    和LOCAL_EXPORT_CFLAGS一样,记录链接器flags,导入的链接器flags会被添加到模块的LOCAL_LDLIBS中,这由Unix链接器的工作方式决定,当foo是一个静态库并且部分代码依赖系统库,该变量将会很有用,LOCAL_EXPORT_LDLIBS可以被用来导出依赖,如:

    # Define "foo" module
    include $(CLEAR_VARS)
    LOCAL_MODULE := foo
    LOCAL_SRC_FILES := foo/foo.c
    LOCAL_EXPORT_LDLIBS := -llog
    include $(BUILD_STATIC_LIBRARY)
    
    # Define "bar" module
    include $(CLEAR_VARS)
    LOCAL_MODULE := bar
    LOCAL_SRC_FILES := bar.c
    LOCAL_STATIC_LIBRARY := foo
    include $(BUILD_SHARED_LIBRARY)

    这里,libbar.so在链接时编译-llog,表示它依赖于系统日志库,因为它依赖于foo。

    (20)LOCAL_FILTER_ASM

    使用一个shell命令定义这个变量,用来过滤LOCAL_SRC_FILES中的或者由其生成的程序集文件。

  • 相关阅读:
    买房的贷款时间是否是越长越好?https://www.zhihu.com/question/20842791
    asp.net cookie and session
    leelazero and google colab
    download file by python in google colab
    physical processor, core, logical processor
    通过powershell操作eventlog
    openxml in sql server
    get the page name from url
    How to Execute Page_Load() in Page's Base Class?
    Difference between HttpContext.Request and Request
  • 原文地址:https://www.cnblogs.com/Cqlismy/p/11801450.html
Copyright © 2011-2022 走看看