??xml version="1.0" encoding="utf-8" standalone="yes"?>
Ҏeoeandroid上的的连载,q行一些更新、修改和加亮?/span>
今天译ANDROID-MK.TXT文gQ英文原文g?/span>/development/Ndk/Docs/android-mk.txtQ?/span>
Android.mk文g语法规范
Introduction:
Android.mk~译文g是用来向Android NDK描述你的C,C++源代码文件的Q?/span> q篇文档描述了它的语法。在阅读下面的内容之前,假定你已l阅Mdocs/OVERVIEW.TXT文gQ了解了它们的脚色和用途?/span>
概述:
一?/span>Android.mk file用来向编译系l描qC的源代码。具体来_-该文件是GNU Makefile的一部分,会被~译pȝ解析一ơ或更多ơ的buildpȝ。因此,您应量减少您声明的变量Q不要认为某些变量在解析q程中不会被定义?/span>-q个文g的语法允许把你的源代码组l成模块Q一个模块属下列cd之一Q?/span>
静态库
׃n?/span>
只有׃n库将被安?/span>/复制到您的应用Y件包。虽焉态库能被用于生成׃n库?/span>
你可以在每一?/span>Android.mk file中定义一个或多个模块Q你也可以在几个模块中用同一个源代码文g?/span>
/*****************************************************************************/
-~译pȝZ处理许多l节问题。例如,你不需要在你的Android.mk中列出头文g和依赖文件?/span>NDK~译pȝ会Z自动处理q些问题。这也意味着Q在升NDK后,你应该得到新?/span>toolchain/platform支持Q而且不需要改变你?/span>Android.mk文g?/span>
注意Q这个语法同公开发布?/span>Androidq_的开源代码很接近Q然而编译系l实C们的方式却是不同的,q是故意q样设计的,可以让程序开发h员重用外部库的源代码更容易?/span>
单的例子:
---------------
在描q语法细节之前,׃来看一个简单的"hello world"的例子,比如Q下面的文gQ?/span>
sources/helloworld/helloworld.c
sources/helloworld/Android.mk
'helloworld.c'是一?/span>JNI׃n库,实现q回"hello world"字符串的原生Ҏ?/span>
相应?/span>Android.mk文g会象下面q样Q?/span>
---------- cut here ------------------
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= helloworld
LOCAL_SRC_FILES := helloworld.c
include $(BUILD_SHARED_LIBRARY)
---------- cut here ------------------
好,我们来解释一下这几行代码Q?/span>
LOCAL_PATH := $(call my-dir)
一?/span>Android.mk file首先必须定义?/span>LOCAL_PATH变量。它用于在开发树中查找源文g?span style="color: blue;">在这个例子中Q宏函数’my-dir’, q译系l提供,用于q回当前路径Q即包含Android.mk file文g的目录)?/span>
include $( CLEAR_VARS)
CLEAR_VARSq译系l提供,指定?/span>GNU MAKEFILEZ清除许多LOCAL_XXX变量Q例?/span> LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, {等...),
?/span>LOCAL_PATH 。这是必要的Q因为所有的~译控制文g都在同一?/span>GNU MAKE执行环境中,所有的变量都是全局的?/span>
LOCAL_MODULE := helloworld
LOCAL_MODULE变量必须定义Q以标识你在Android.mk文g中描q的每个模块。名U必L唯一的,而且不包含Q何空根{注意编译系l会自动产生合适的前缀和后~Q换句话_一个被命名?/span>'foo'的共享库模块Q将会生?/span>'libfoo.so'文g?/span>
重要注意事项
如果你把库命名ؓ‘libhelloworld’Q编译系l将不会dM?/span>lib前缀Q也会生?/span>libhelloworld.soQ这是ؓ了支持来源于Androidq_的源代码?/span>Android.mk文gQ如果你实需要这么做的话?/span>
LOCAL_SRC_FILES := helloworld.c
LOCAL_SRC_FILES变量必须包含要~译打包q模块中?/span>C?/span>C++源代码文件。注意,你不用在q里列出头文件和包含文gQ因为编译系l将会自动ؓ你找Z赖型的文Ӟ仅仅列出直接传递给~译器的源代码文件就好。【注意,默认?/span>C++源码文g的扩展名?#8217;.cpp’. 指定一个不同的扩展名也是可能的Q只要定?/span>LOCAL_DEFAULT_CPP_EXTENSION变量Q不要忘记开始的圆点(也就是定义ؓ‘.cxx’,而不?#8216;cxx’Q(当然q一步我们一般不会去改它Q?/span>
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY是编译系l提供的变量Q指向一?/span>GNU Makefile脚本Q应该就是在build/core目录下的shared_library.mkQ,负责攉自从上次调用'include $(CLEAR_VARS)'以来Q定义在LOCAL_XXX变量中的所有信息,q且军_~译什么,如何正确地去做。ƈҎ其规则生成静态库。同理对于静态库?/span>
/****************************************************************************/
?/span>sources/samples目录下有更复杂一点的例子Q写有注释的Android.mk文gQ你可以看看?/span>
参?/span>:
q是一份你应该?/span>Android.mk中依赖或定义的变量列表,您可以定义其他变量ؓ自己使用Q?/span>
但是NDK~译pȝ保留下列变量名:
-?/span>LOCAL_开头的名字Q例?/span> LOCAL_MODULEQ?/span>
-?/span>PRIVATE_, NDK_ or APP_开头的名字Q内部用)
-写名字Q内部用,例如’my-dir’Q?/span>
如果您ؓ了方便在Android.mk中定义自q变量Q我们徏议?/span>MY_前缀Q一个小例子Q?/span>
---------- cut here ------------------
MY_SOURCES := foo.c
ifneq ($(MY_CONFIG_BAR),)
MY_SOURCES += bar.c
endif
LOCAL_SRC_FILES += $(MY_SOURCES)
---------- cut here ------------------
- - - - - - - - - - -
q些GNU Make 变量在你?/span>Android.mk文g解析之前Q就q译系l定义好了?/span>
注意在某些情况下Q?/span>NDK可能分析Android.mk几次Q每一ơ某些变量的定义会有不同?/span>
CLEAR_VARS
指向一个编译脚本,几乎所有未定义?/span>LOCAL_XXX变量都在"Module-description"节中列出?/span>
你必d开始一个新模块之前包含q个脚本?/span>include $(CLEAR_VARS)
BUILD_SHARED_LIBRARY
指向~译脚本Q收集所有的你在LOCAL_XXX变量中提供的信息Qƈ且决定如何把你列出的源代码文件编译成一个共享库。注意,你必至在包含q个文g之前定义LOCAL_MODULE?/span>LOCAL_SRC_FILESQ用例子:
include $(BUILD_SHARED_LIBRARY)
注意q将生成一个名?/span>lib$(LOCAL_MODULE).so的文件?/span>
BUILD_STATIC_LIBRARY
一?/span>BUILD_SHARED_LIBRARY变量用于~译一个静态库。静态库不会复制C?/span>project/packages中,诞生能够用于~译׃n库,Q看下面描述?/span>LOCAL_STATIC_LIBRARIES and LOCAL_STATIC_WHOLE_LIBRARIESQ?/span>
使用例子Q?/span>
include $(BUILD_STATIC_LIBRARY)
注意Q这会生成一个名?/span>lib$(LOCAL_MODULE).a的文件?/span>
TARGET_ARCH
目标CPUq_的名字,如同?/span>android开放源码中指定的那栗如果是’arm’Q表C生成ARM兼容的指令,?/span>CPU架构的修订版无关?/span>
TARGET_PLATFORM
Android.mk解析的时候,目标Androidq_的名?/span>.详情可参?/span>/development/ndk/docs/stable-apis.txt.
android-3 -> Official Android 1.5 system images
android-4 -> Official Android 1.6 system images
android-5 -> Official Android 2.0 system images
TARGET_ARCH_ABI
暂时只支持两?/span>valueQ?/span>armeabi?/span>armeabi-v7a。在现在的版本中一般把q两个值简单的定义?/span>armQ通过android q_内部对它重定义来获得更好的匹配?/span>
其他的AQテ在以后的NQO版本中介l,它们会有不同的名字。注意所有基于AQԌ的AQテ都会?/span>'TARGET_ARCH'定义?#8216;ar?#8217;Q但是会有不同的‘TARGET_ARCH_ABI’
TARGET_ABI
目标q_?/span>ABI的组合,它事实上被定义成$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI) 在你惌在真实的讑֤中针对一个特别的目标pȝq行试Ӟ会有用。在默认的情况下Q它会是'android-3-arm'?/span>
/*****************************************************************************/
下面?/span>GNU Make ‘功能’宏,必须通过使用'$(call <function>)'来求?/span>Q他们返回文本化的信息?/span>
my-dir
q回当前Android.mk所在的目录路径Q相对于QDQ编译系l的层。这是有用的Q在Android.mk文g的开头如此定义:
LOCAL_PATH := $(call my-dir)
all-subdir-makefiles
q回一个位于当?/span>'my-dir'路径的子目录列表。例如,看下面的目录层次Q?/span>
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
如果sources/foo/Android.mk包含一?/span>Q?/span>
include $(call all-subdir-makefiles)
那么它就会自动包?/span>sources/foo/lib1/Android.mk ?/span>sources/foo/lib2/Android.mk
q项功能用于向编译系l提供深层次嵌套的代码目录层ơ。注意,在默认情况下QNQO会只搜索在sources/*/Android.mk中的文g?/span>
this-makefile
q回当前Makefile的\径(卌个函数调用的地方Q?/span>
parent-makefile
q回调用树中?/span>Makefile路径。即包含当前Makefile?/span>Makefile路径?/span>
grand-parent-makefile
猜猜?/span>...
/*****************************************************************************/
模块描述变量:
下面的变量用于向~译pȝ描述你的模块。你应该定义?/span>'include $(CLEAR_VARS)'?/span>'include $(BUILD_XXXXX)'之间定义?/span>正如前面描写的那P$(CLEAR_VARS是一个脚本,清除所有这些变量,除非在描qC昑ּ注明?/span>
LOCAL_PATH
q个变量用于l出当前文g的\径。你必须?/span>Android.mk的开头定义,可以q样使用Q?/span>
LOCAL_PATH := $(call my-dir)
q个变量不会?/span>$(CLEAR_VARS)清除Q因此每?/span>Android.mk只需要定义一ơ(即你在一个文件中定义了几个模块的情况下)?/span>
LOCAL_MODULE
q是你模块的名字Q它必须是唯一的,而且不能包含I格。你必须在包含Q一?/span>$(BUILD_XXXX)脚本之前定义?/span>。模块的名字军_了生成文件的名字Q例如,如果一个一个共享库模块的名字是<foo>Q那么生成文件的名字是lib<foo>.so。但是,在你?/span>NDK生成文g中(或?/span>Android.mk或?/span>Application.mkQ,你应该只涉及(引用)有正常名字的其他模块?/span>
LOCAL_SRC_FILES
q是要编译的源代码文件列表。只要列传递给~译器的文gQ因为编译系l自动ؓ你计依赖?/span>
注意源代码文件名U都是相对于LOCAL_PATH的,你可以用\径部分,例如Q?/span>
LOCAL_SRC_FILES := foo.c \
toto/bar.c
注意Q在生成文g中都要?/span>UNIX风格的斜?/span>(/).windows风格的反斜杠不会被正的处理?/span>
LOCAL_CPP_EXTENSION
q是一个可选变量,用来指定C++代码文g的扩展名Q默认是'.cpp',但是你可以改变它Q比如:
LOCAL_CPP_EXTENSION := .cxx
LOCAL_C_INCLUDES
路径的可选配|,是从根目录开始的Q?/span>
all sources (C, C++ and Assembly). For example:
LOCAL_C_INCLUDES := sources/foo
Or even:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
需要在M包含LOCAL_CFLAGS / LOCAL_CPPFLAGS标志之前?/span>
LOCAL_CFLAGS
可选的~译器选项Q在~译C代码文g的时候用?/span>
q可能是有用的,指定一个附加的包含路径Q相对于NDK的顶层目录)Q宏定义Q或者编译选项?/span>
重要信息Q不要在Android.mk中改?/span>optimization/debuggingU别Q只要在Application.mk中指定合适的信息Q就会自动地Z处理q个问题Q在调试期间Q会让NQO自动生成有用的数据文件?/span>
LOCAL_CXXFLAGS
Same as LOCAL_CFLAGS for C++ source files
LOCAL_CPPFLAGS
?/span>LOCAL_CFLAGS相同Q但是对C 和 C++ source files都适用?/span>
LOCAL_STATIC_LIBRARIES
应该链接到这个模块的静态库列表Q?/span>BUILD_STATIC_LIBRARY生成Q,q仅仅对׃n库模块才有意义?/span>
LOCAL_SHARED_LIBRARIES
q个模块在运行时要依赖的׃n库模块列表,在链接时需要,在生成文件时嵌入的相应的信息。注意:q不会附加列出的模块到编译图Q也是Q你仍然需要在Application.mk中把它们d到程序要求的模块中?/span>
LOCAL_LDLIBS
~译你的模块要用的附加的链接器选项。这对于使用”-l”前缀传递指定库的名字是有用的。例如,下面告诉链接器生成的模块要在加载时刻链接到/system/lib/libz.so
LOCAL_LDLIBS := -lz
?/span>docs/STABLE-APIS.TXT获取你?/span>NDK发行版能链接到的开攄pȝ库列表?/span>
LOCAL_ALLOW_UNDEFINED_SYMBOLS
默认情况下,在试囄译一个共享库ӞM未定义的引用导致一?#8220;未定义的W号”错误。这对于在你的源代码文g中捕捉错误会有很大的帮助?/span>
然而,如果你因为某些原因,需要不启动q项查,把这个变量设?#8216;true’。注意相应的׃n库可能在q行时加载失败。(q个一般尽量不要去设ؓtrueQ?/span>
LOCAL_ARM_MODE
默认情况下,arm目标二进制会?/span>thumb的Ş式生成(16位)Q你可以通过讄q个变量?/span>arm如果你希望你?/span>module是以32位指令的形式?/span>
'arm' (32-bit instructions) mode. E.g.:
LOCAL_ARM_MODE := arm
注意你同样可以在~译的时候告诉系l编译特定的cdQ?/span>比如
LOCAL_SRC_FILES := foo.c bar.c.arm
q样告诉系lL?/span>bar.c?/span>arm的模式编译,
Android.mk使用模板
在一?/span>Android.mk中可以生成多个可执行E序、动态库和静态库?/span>
1Q编译应用程序的模板Q?/span>
#Test Exe
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)
Q菜鸟别解释::=是赋值的意思,$是引用某变量的|LOCAL_SRC_FILES中加入源文g路径Q?/span>LOCAL_C_INCLUDES 中加入所需要包含的头文件\径,LOCAL_STATIC_LIBRARIES加入所需要链接的静态库Q?/span>*.aQ的名称Q?/span>LOCAL_SHARED_LIBRARIES中加入所需要链接的动态库Q?/span>*.soQ的名称Q?/span>LOCAL_MODULE表示模块最l的名称Q?/span>BUILD_EXECUTABLE表示以一个可执行E序的方式进行编译?/span>
2Q编译静态库的模板:
#Test Static Lib
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表示~译一个静态库?/span>
3Q编译动态库的模板:
#Test Shared Lib
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表示~译一个共享库?/span>
以上三者的生成l果分别在如下,generic依具?/span>target会变Q?/span>
out/target/product/generic/obj/EXECUTABLE
out/target/product/generic/obj/STATIC_LIBRARY
out/target/product/generic/obj/SHARED_LIBRARY
每个模块的目标文件夹分别为:
可执行程序:XXX_intermediates
静态库Q?/span> XXX_static_intermediates
动态库Q?/span> XXX_shared_intermediates
另外Q在Android.mk文g中,q可以指定最后的目标安装路径Q用LOCAL_MODULE_PATH?/span>LOCAL_UNSTRIPPED_PATH来指定。不同的文gpȝ路径用以下的宏进行选择Q?/span>
TARGET_ROOT_OUTQ表C根文gpȝ?/span>
TARGET_OUTQ表C?/span>system文gpȝ?/span>
TARGET_OUT_DATAQ表C?/span>data文gpȝ?/span>
用法如:
LOCAL_MODULE_PATH:=$(TARGET_ROOT_OUT)
void android_main(struct android_app* state) {
// Make sure glue isn't stripped.
app_dummy();
// loop waiting for stuff to do.
while (1) {
// Read all pending events.
int ident;
int events;
struct android_poll_source* source;
// Read events and draw a frame of animation.
if ((ident = ALooper_pollAll(0, NULL, &events,
(void**)&source)) >= 0) {
// Process this event.
if (source != NULL) {
source->process(state, source);
}
}
// draw a frame of animation
bringTheAwesome();
}
}
------------------------------------------------------------------------------------