Android基础总结之七:Android.mk小结

文章出处:http://blog.csdn.net/shift_wwx

前言:了解四大组件之前也有必要熟悉项目的AndroidManifest.xml基础知识,还要熟悉Android.mk基础知识,这两个应该是前提,个人习惯拿到一个没有看过一个应用的程序,首先看的是Manifest和makefile。之前已经写了一篇关于Manifest的文章:《Android基础总结之四:AndroidManifest.xml详解》,这里做一下makefile的小结。

 

一、举例说明

一个Android.mk file用来向编译系统描述你的源代码。具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次。你可以在每一个Android.mk file中定义一个或多个模块,你也可以在几个模块中使用同一个源代码文件。选项参考以下文件:build/core/config.mk,默认的值在以下文件中定义:build/core/base_rules.mk。编译系统为你处理许多细节问题。例如,你不需要在你的Android.mk中列出头文件和依赖文件。NDK编译系统将会为你自动处理这些问题。

首先看个小例子:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-subdir-java-files)

LOCAL_PACKAGE_NAME := AlarmClock

include $(BUILD_PACKAGE)

1. LOCAL_PATH := $(call my-dir) ,一个Android.mk file首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数‘my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。

其中my-dir定义在build/core/definitions.mk中,code如下:

# Figure out where we are.
define my-dir
$(strip \
  $(eval LOCAL_MODULE_MAKEFILE := $$(lastword $$(MAKEFILE_LIST))) \
  $(if $(filter $(CLEAR_VARS),$(LOCAL_MODULE_MAKEFILE)), \
    $(error LOCAL_PATH must be set before including $$(CLEAR_VARS)) \
   , \
    $(patsubst %/,%,$(dir $(LOCAL_MODULE_MAKEFILE))) \
   ) \
 )
endef


2. include $( CLEAR_VARS),CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。
CLEAR_VARS定义在build/core/config.mk中,code如下:

CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk

查看clear_vars.mk就会知道CLEAR_VARS的具体作用了:

LOCAL_MODULE:=
LOCAL_MODULE_PATH:=
LOCAL_MODULE_STEM:=
LOCAL_DONT_CHECK_MODULE:=
LOCAL_CHECKED_MODULE:=
LOCAL_BUILT_MODULE:=
LOCAL_BUILT_MODULE_STEM:=
OVERRIDE_BUILT_MODULE_PATH:=
LOCAL_INSTALLED_MODULE:=
LOCAL_UNINSTALLABLE_MODULE:=
LOCAL_INTERMEDIATE_TARGETS:=
LOCAL_UNSTRIPPED_PATH:=
LOCAL_MODULE_CLASS:=
LOCAL_MODULE_SUFFIX:=
LOCAL_PACKAGE_NAME:=
LOCAL_OVERRIDES_PACKAGES:=
LOCAL_EXPORT_PACKAGE_RESOURCES:=
LOCAL_MANIFEST_PACKAGE_NAME:=
LOCAL_REQUIRED_MODULES:=
LOCAL_ACP_UNAVAILABLE:=
LOCAL_MODULE_TAGS:=

将除LOCAL_PATH之外的所有LOCAL都置空。


3. LOCAL_SRC_FILES :=$(call all-subdir-java-files),LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的JAVA、C或C++源代码文件。

call all-subdir-java-files定义在build/core/definitions.mk中,code如下:

define all-subdir-java-files
$(call all-java-files-under,.)
endef


4. LOCAL_PACKAGE_NAME := AlarmClock,LOCAL_PACKAGE_NAME指的是生成android基本应用程序,apk包。同LOCAL_MODULE

5. include $(BUILD_PACKAGE),BUILD_PACKAGE和CLEAR_VARS一样也是在build/core/config.mk下定义的,code如下:

BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk

最后的include是生成目标的最关键所在,例如,如果要生成apk,那么就要include $(BUILD_PACKAGE);如果要生成java的jar包,那么就要include $(BUILD_STATIC_JAVA_LIBRARY),等等......下面会慢慢介绍。

这些BUILD_***都会在/system/core/config.mk中定义的,如下:

# ###############################################################
# Build system internal files
# ###############################################################

BUILD_COMBOS:= $(BUILD_SYSTEM)/combo

CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.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_PHONY_PACKAGE:= $(BUILD_SYSTEM)/phony_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_NATIVE_TEST := $(BUILD_SYSTEM)/native_test.mk
BUILD_HOST_NATIVE_TEST := $(BUILD_SYSTEM)/host_native_test.mk



二、各种mk小结

一个Android.mk文件可以编译多个模块,每个模块属下列类型之一
1)APK程序
一般的Android程序,编译打包生成apk文件
2)JAVA库
java类库,编译打包生成jar文件
3)C\C++应用程序
可执行的C\C++应用程序
4)C\C++静态库
编译生成C\C++静态库,并打包成.a文件
5)C\C++共享库
编译生成共享库(动态链接库),并打包成.so文, 有且只有共享库才能被安装/复制到您的应用软件(APK)包中。
 
在一个 Android.mk 中可以生成多个APK应用程序,JAVA库,C\C++可执行程序,C\C++动态库和C\C++静态库。
1)编译APK应用程序模板。
关于编译APK应用程序,前面已经介绍过。
(2)编译JAVA库模板
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Any libraries that this library depends on
LOCAL_JAVA_LIBRARIES := android.test.runner
# The name of the jar file to create
LOCAL_MODULE := sample
# Build a static jar file.
include $(BUILD_STATIC_JAVA_LIBRARY)
:LOCAL_JAVA_LIBRARIES := android.test.runner表示用到的JAVA库的jar文件名
 
(3)编译C/C++应用程序模板如下
LOCAL_PATH := $(call my-dir)
#include $(CLEAR_VARS)
LOCAL_SRC_FILES := main.c
LOCAL_MODULE := test_exe
#LOCAL_C_INCLUDES :=
#LOCAL_STATIC_LIBRARIES :=
#LOCAL_SHARED_LIBRARIES :=
include $(BUILD_EXECUTABLE)
:‘:=’是赋值的意思,'+='是追加的意思,‘$’表示引用某变量的值
LOCAL_SRC_FILES中加入源文件路径,LOCAL_C_INCLUDES中加入需要的头文件搜索路径
LOCAL_STATIC_LIBRARIES 加入所需要链接的 静态库(*.a) 的名称,
LOCAL_SHARED_LIBRARIES 中加入所需要链接的 动态库(*.so) 的名称,
LOCAL_MODULE 表示模块最终的名称, BUILD_EXECUTABLE 表示以一个可执行程序的方式进行编译。
(4)编译C\C++静态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
    helloworld.c
LOCAL_MODULE:= libtest_static
#LOCAL_C_INCLUDES :=
#LOCAL_STATIC_LIBRARIES :=
#LOCAL_SHARED_LIBRARIES :=
include $(BUILD_STATIC_LIBRARY)
和上面相似,BUILD_STATIC_LIBRARY 表示编译一个静态库。
(5)编译C\C++动态库的模板
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := helloworld.c
LOCAL_MODULE := libtest_shared
TARGET_PRELINK_MODULES := false
#LOCAL_C_INCLUDES :=
#LOCAL_STATIC_LIBRARIES :=
#LOCAL_SHARED_LIBRARIES :=
include $(BUILD_SHARED_LIBRARY)
和上面相似,BUILD_SHARED_LIBRARY 表示编译一个共享库。
以上三者的生成结果分别在如下目录中,generic 依具体 target 会变
out/target/product/generic/obj/APPS
out/target/product/generic/obj/JAVA_LIBRARIES
out/target/product/generic/obj/EXECUTABLE
out/target/product/generic/obj/STATIC_LIBRARY
out/target/product/generic/obj/SHARED_LIBRARY
每个模块的目标文件夹分别为
1) APK程序 :XXX_intermediates
2) JAVA库程序 :XXX_intermediates
这里的XXX
3) C\C++可执行程序 :XXX_intermediates
4) C\C++静态库 : XXX_static_intermediates
5) C\C++动态库 : XXX_shared_intermediates

 

三、常用变量小结

(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的区别,暂时还不清楚。
(15)LOCAL_MODULE_TAGS:= user eng tests optional

user: 指该模块只在user版本下才编译

eng: 指该模块只在eng版本下才编译

tests: 指该模块只在tests版本下才编译

optional:指该模块在所有版本下都编译


四、编译流程小结

我们知道,在编译android系统的时候,会用到make命令,那么必须用到对应的Makefile文件。

我们可以在根目录中找到这样的Makefile文件,打开一看:

### DO NOT EDIT THIS FILE ###
include build/core/main.mk
### DO NOT EDIT THIS FILE ###
了解makefile的知道所有的定义、执行都应该在main.mk中。

很简单就能找到config.mk,这个是个很关键的makefile,其中不但包含了product的相关变量定义,和所有mk变量的定义,也包含了具体的执行mk。

因为mk文件很多,有的人会问,一般这些都是系统的makefile,device或者vendor下面的mk是什么时候调用到的呢?是最后还是最开始?

这些都可以在config.mk中找到结果。

在config.mk中很快就能找到produc_config.mk,对的,这就是关于product的所有配置、定义、链接。其中最关键的就是AndroidProduct.mk,这里会寻找除了build下的AndroidProduct.mk,还会到device或者vendor下面找,会找到所有定义PRODUCT_MAKEFILES的地方,并且执行。这个时候就进入了product的mk中了。



这里写的只是一些小结,如果想要详细了解,还是需要多看看资料、书籍。





 

你可能感兴趣的:(android,makefile,android.mk)