Android NDK开发指南(三)Android build system & Android.mk 规范

1. Android编译系统分析 --- 系统变量解析

       LOCAL_PATH                        - 编译时的目录
       LOCAL_MODULE                   - 编译的目标对象
       LOCAL_SRC_FILES               - 编译的源文件
       LOCAL_C_INCLUDES            - 需要包含的头文件目录
       LOCAL_SHARED_LIBRARIES  - 链接时需要的外部库
       LOCAL_PRELINK_MODULE    - 是否需要prelink处理

 

       BUILD_STATIC_LIBRARY   - 指明要编译成静态库
       BUILD_SHARED_LIBRARY  - 指明要编译成动态库

(1).  LOCAL_PATH - 编译时的目录          

        $(call 目录,目录….) 目录引入操作符:   如该目录下有个文件夹名称 src,则可以这样写 $(call src),那么就会得到 src 目录的完整路径

(2). include $(CLEAR_VARS) -清除之前的一些系统变量
       CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
在 build/core/config.mk 定义 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
通过include 包含自定义的.mk文件(即是自定义编译规则)或是引用系统其他的.mk文件(系统定义的编译规则)。

(3). LOCAL_SRC_FILES - 编译的源文件
       可以是.c, .cpp, .java, .S(汇编文件)或是.aidl等格式, 不同的文件用空格隔开。

       如果编译目录子目录,采用相对路径,如子目录/文件名。

      也可以通过$(call 目录),指明编译某目录下所有.c/.cpp/.java/.S/ .aidl文件.    追加文件 LOCAL_SRC_FILES += 文件

(4). LOCAL_C_INCLUDES - 需要包含的头文件目录
       可以是系统定义路径,也可以是相对路径. 如该编译目录下有个include目录,写法是include/*.h

(5). LOCAL_MODULE - 编译的目标对象
       module 是指系统的 native code,通常针对c,c++代码
              ./system/core/sh/Android.mk:32:LOCAL_MODULE:= sh
              ./system/core/libcutils/Android.mk:71:LOCAL_MODULE := libcutils
              ./system/core/cpio/Android.mk:9:LOCAL_MODULE := mkbootfs
              ./system/core/mkbootimg/Android.mk:8:LOCAL_MODULE := mkbootimg
              ./system/core/toolbox/Android.mk:61:LOCAL_MODULE:= toolbox
              ./system/core/logcat/Android.mk:10:LOCAL_MODULE:= logcat
              ./system/core/adb/Android.mk:65:LOCAL_MODULE := adb
              ./system/core/adb/Android.mk:125:LOCAL_MODULE := adbd
              ./system/core/init/Android.mk:20:LOCAL_MODULE:= init
              ./system/core/vold/Android.mk:24:LOCAL_MODULE:= vold
              ./system/core/mountd/Android.mk:13:LOCAL_MODULE:= mountd

(6). LOCAL_PACKAGE_NAME 
       Java 应用程序的名字用该变量定义
              ./packages/apps/Music/Android.mk:9:LOCAL_PACKAGE_NAME := Music
              ./packages/apps/Browser/Android.mk:14:LOCAL_PACKAGE_NAME := Browser
              ./packages/apps/Settings/Android.mk:8:LOCAL_PACKAGE_NAME := Settings
              ./packages/apps/Stk/Android.mk:10:LOCAL_PACKAGE_NAME := Stk
              ./packages/apps/Contacts/Android.mk:10:LOCAL_PACKAGE_NAME := Contacts
              ./packages/apps/Mms/Android.mk:8:LOCAL_PACKAGE_NAME := Mms
              ./packages/apps/Camera/Android.mk:8:LOCAL_PACKAGE_NAME := Camera
              ./packages/apps/Phone/Android.mk:11:LOCAL_PACKAGE_NAME := Phone
              ./packages/apps/VoiceDialer/Android.mk:8:LOCAL_PACKAGE_NAME := VoiceDialer

(7).  依赖库
         LOCAL_SHARED_LIBRARIES - 链接时需要的外部共享库
         LOCAL_STATIC_LIBRARIES - 链接时需要的外部外部静态
         LOCAL_JAVA_LIBRARIES 加入jar包


(8). BUILD_SHARED_LIBRARY - 指明要编译成动态库。编译的目标,用include 操作符
       BUILD_STATIC_LIBRARY  --- 来指明要编译成静态库。
       如果是java文件的话,用 BUILD_PACKAGE 来指明。会用到系统的编译脚本host_java_library.mk,

-------------------
include $(BUILD_STATIC_LIBRARY)
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
-------------------
include $(BUILD_SHARED_LIBRARY)
./build/core/config.mk:50:BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
-------------------
include $(BUILD_HOST_SHARED_LIBRARY)
BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk
-------------------
include $(BUILD_EXECUTABLE)
build/core/config.mk:51:BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
-------------------
include $(BUILD_HOST_EXECUTABLE)
./build/core/config.mk:53:BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
-------------------
BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
-------------------
BUILD_JAVA_LIBRARY
./build/core/config.mk:58:BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
------------------
BUILD_STATIC_JAVA_LIBRARY 编译静态JAVA库
./build/core/config.mk:59:BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
------------------
BUILD_HOST_JAVA_LIBRARY 编译本机用的JAVA库
./build/core/config.mk:60:BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
------------------
BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk
BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk
BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk
BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk
BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk
BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk
BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk

 

2. NDK提供的宏功能 及 Anroid.mk 规范
以下是使用GNU make的宏功能,必须通过使用"$(call <function>)",返回一个文本信息。

my-dir

返回最后包含的makefile的路径,这通常是当前Android.mk所在目录的路径,在Android.mk开始之前定义
LOCAL——PATH是很有用的。

在Android.mk文件的开始位置定义
LOCAL_PATH :=$(call my-dir)

...声明一个模块
include $(LOCAL_PATH)/foo/Android.mk

LOCAL_PATH :=($call my-dir)

...声明另一个模块
这里的问题是第二次调用"my-dir"定义LOCAL_PATH替换$PATH为$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
返回一个Android.mk文件所在位置的列表,以及当前的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包含进来。

此功能可以用于提供深层嵌套的源代码目录build system的层次结构。请注意,默认情况下,NDK只会寻找
sources/*Android.mk

this-makefile
返回当前makefile的路径(也就是那个功能被调用了)

parent-makefile
返回makefile的包含树,也就是包含Makefile当前的文件

grand-parent-makefile
你猜?

import-module
一个允许你通过名字找到并包含另一个模块的的Android.mk的功能,例如

$(call import-module,<name>)

这将会找到通过NDK_MODULE_PATH环境变量引用的模块<name>的目录列表,并且将其自动包含到
Android.mk中

详细信息请参阅:docs/IMPORT-MODULE.html

模块变量描述:
----------------------------------
下面的这些变量是用来描述怎样用你的模块来编译系统的。你可以定义它们中的一些比如
"include $(CLEAR_VARS)"和"include $(BUILD_XXX)",正如前面所写的,$(CLEAR_VARS)是一个可以取消定义/清楚所有变量的脚本。

LOCAL_PATH
这个变量是用来给出当前文件的路径。您比系再您的Android.mk开始位置定义:
LOCAL_PATH :=$(call my-dir)
注意,这个变量是不被$(CLEAR_VARS)清除的,其他的都要被清除(我们可以定义几个模块到一个文件中)

LOCAL_MODULE
这个是你模块的名称,它在你的所有模块中名称必须是唯一的,并且不能包含空格。你必须在包含任何
$(BUILD-XXX)脚本之前定义它。

默认情况下,模块的名称决定了生成的文件的名称,例如lib<foo>.so,它是foo模块的名字。

你可以用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里,这些将有build system自动处理。

LOCAL_SRC_FILES
这是你模块中将要编译的源文件列表。只列出将被传递到编译器的文件,因为build system自动为您计算了它们的依赖。

注意:源文件的名称都是相对LOCAL_PATH的,您可以使用路径组件,例如
LOCAL_SRC_FILES :=foo.c\
toto/bar.c

注意:在build system时请务必使用UNIX风格的斜杠(/),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

当用用ndk-gdb启动本机调试时,LOCAL_C_INCLUDES也会自动被使用到

LOCAL_CFLAGS

当编译C/C++源文件时传递一个可选的编译器标志。
这对于指定额外的宏定义或编译选项很有用

重要提示:尽量不要改变Android.mk中的优化/调试级别,这个可以通过在Application.mk中设置相应的信息来自动为你处理,并且会会让NDK生成在调试过程中使用的有用的数据文件。

注意:在Android-ndk-1.5_r1中,只使用于C源文件,而不适用于C++源文件。在匹配所有Android build system的行为已经得到了纠正。(现在你可以为C++源文件使用LOCAL_CPPFLAGS来指定标志)

它可以用LOCAL_CFLAGS += -I<path>来指定额外的包含路径,然而,如果使用LOCAL_C_INCLUDES会更好,因为用ndk-gdk进行本地调试的时候,那些路径依然是需要使用的

LOCAL_CXXFLAGS
LOCAL_CPPFLAGS的别名。请注意,这个标志在NDK的未来的版本中将会消失

LOCAL_CPPFLAGS
当只编译C++源代码的时候,将传递一个可选的编译器标志。它们将会出现再LOCAL_CFLAGS之后。

注意:在Android NDK-1.5_r1版本中,相应的标志可以应用于C或C++源文件上。在配合完整的Android build system的时候,这已经得到了纠正。(你可以使用LOCAL_CFLAGS去指定C或C++源文件)

LOCAL_STATIC_LIBRARIES

静态库模块的列表(通过BUILD_STATIC_LIBRARY创建)应与此模块链接。这仅仅是为了使动态库敏感。

LOCAL_SHARED_LIBRARY
共享库的列表“模块”,这个模块依赖于运行时.这在链接的时候和在生成的文件中嵌入相应的信息是非常必要的

LOCAL_WHOLE_STATIC_LIBRARIES

LOCAL_WHOLE_STATIC_LIBRARIES是一个用于表示相应的库模块被用作为“整个档案”到链接程序的变量。

当几个静态库之间有循环依赖关系的时候,通常是很有益的。注意,当用来编译一个动态库的时候,这将迫使你将所有的静态库中的对象文件添加到最终的二进制文件中。但生成可执行程序时,这是不确定的。

LOCAL_LDLIBS
当额外的链接标志列表被用于在编译你的模块时,通过用"-l"前缀的特定系统库传递名字是很有用的。例如,下面的旧爱哪个告诉你生成一个在加载时链接到/system/lib/libz.so的模块。

LOCAL_LDLIBS :=-lz

LOCAL_ALLOW_UNDEFINED_SYMBOLS
默认情况下,当试图编译一个共享库的时候遇到任何未定义的引用都可能导致"未定义符号"(undefined symbol)的错误。这在你的源代码中捕获bug会很有用。

然而,但是由于某些原因,你需要禁用此检查的话,设置变量为"true"即可。需要注意的是,相应的共享库在运行时可能加载失败。

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

LOCAL_ARM_MODE := arm

注意,你需要执行编译系统为在ARM模式下通过文件的名字增加后缀的方式编译指定的源文件。比如:

LOCAL_SRC_FILES :=foo.c bar.c.arm

这会告诉编译系统一直以ARM模式编译"bar.c",并且通过LOCAL_ARM_MODE的值编译foo.c。

注意:在Application.mk文件中设置APP_OPTIM为"debug"也会强制ARM二进制文件的生成。这是因为工具链调试其中的bug不会处理thumb代码。

LOCAL_ARM_NEON

定义这个变量为"true"会允许在你的C或C++源文件的GCC的内部函数中使用ARM高级SIMD(又名NEON),以及在聚合文件中的NEON指令。

当针对"armeabi-v7a"ABI对应的ARMv7指令集时你应该定义它。注意,并不是所有的ARMv7都是基于NEON指令集扩展的CPU,你应该执行运行时来检测在运行时中这段代码的安全。

另外,你也可以指定特定的源文件,比如用支持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位"安全功能特性。它是默认启用的,如果你需要的话,可以通过设置变量为“true”来禁用它。

注意:此功能不修改ABI,并且只在ARMv6及以上的CPU设备的内核上被启用。

更多信息,可以参见:
 http://en.wikipedia.org/wiki/NX_bit
 http://www.gentoo.org/proj/en/hardened/gnu-stack.xml

LOCAL_EXPORT_CFLAGS

定义这个变量用来记录C/C++编译器标志集合,并且会被添加到其他任何以LOCAL_STATIC_LIBRARIES和LOCAL_SHARED_LIBRARIES的模块的LOCAL_CFLAGS定义中。

例如:这样定义"foo"模块
include $(CLEAR_VARS)
LOCAL_MODULE :=foo
LOCAL_SRC_FILES :=foo/foo.c
LOCAL_EXPORT_CFLAGS :=-DFOO=1
include $(BUILD_STATIC_LIBRARY)

另一个模块,叫做"bar",并且依赖于上面的模块
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"将被传递到编译器。

输出的标志被添加到模块的LOCAL_CFLAGS上,所以你可以很容易复写它们。它们也有传递性:如果"zoo"依赖"bar",“bar”依赖"foo",那么"zoo"也将继承"foo"输出的所有标志。

最后,当编译模块输出标志的时候,这些标志并不会被使用。在上面的例子中,当编译foo/foo.c时,
-DFOO=1将不会被传递给编译器。


LOCAL_EXPORT_CPPFLAGS

类似LOCAL_EXPORT_CFLAGS,但适用于C++标志。

LOCAL_EXPORT_C_INCLUDES

类似LOCAL_EXPORT_C_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。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值