Andriodframework我爱编程

Android.mk语法

2018-04-13  本文已影响0人  记得柒叁贰

翻译自docs/ANDROID-MK.html

Indroduction

本篇文档描述Andrid.mk编译文件的语法。Android.mk文件向Android NDK描述你的CC++文件。为了更好的理解下面的内容,你需要阅读docs/OVERVIEW.html文档,里面介绍了该文件的用途和用法。

Oerview

编写Android.mk是为了向编译系统描述你的源码。具体如下:

只有共享库会被安装或者拷贝到你的应用里面,静态库可以被用来生成共享库。
你可以在一个Android.mk文件中定义一个或多个module,你也可以使用同一套源码生成不同的modules

Simple example

在详细的介绍语法之前,我们先看一个简单的例子,hello JNI,该工程文件放在:

apps/hello-jni/project

这里:

现在,我们详细解释上面每一行内容:

LOCAL_PATH := $(call my-dir)

Android.mk文件必须以变量LOCAL_PATH的定义起始。这个变量用来定位开发树中的源文件的位置。在这个例子中,使用了编译环境中的宏方法my-dir,它可以返回当前目录(包含Android.mk文件的目录)的路径。

include $(CLEAR_VARS)

变量CLEAR_VARS也是编译环境提供的,指向一个特别的GNU Make文件,这个Make文件会帮你清除一些LOCAL_XXX变量(如LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等),但不会清除LOCAL_PATH。这是因为所有的编译控制文件会被GNU Make环境解析为全局变量。

LOCAL_MODULE := hello-jni

变量LOCAL_MODULE必须被定义,用以区分你在Android.mk文件中定义的每一个模块。这个名字必须是唯一的而且能够含有空格。注意编译系统会为生成的文件自动添加正确的前缀和后缀。也就是说,一个名为foo的模块会生成libfoo.so
注意:如果你命名你的模块为libfoo,编译环境不会再添加一个lib前缀,而且也可会生成libfoo.so。这是为了支持源自于AOSPAndroid.mk文件,你也许会用到这些。

LOCAL_SRC_FILES := hello-jni.c

LOCAL_SRC_FILES变量必须包含将要编译到模块中的C和/或C++源文件的列表。注意,你不许要在这里列出头文件,编译环境会自动帮你处理这些依赖,只需要列出被编译器直接编译的源文件即可。
注意,C++源文件的默认扩展名是.cpp。你也可以通过定义变量LOCAL_CPP_EXTENSION来指定一个不同的扩展名。不要忘记..cxx是可以的,但是cxx不行)。

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY变量是由编译环境提供,指向一个GNU Make脚本文件,负责收集自上一个include $(CLEAR_VARS)之后你定义的所有LOCAL_XXX变量,确定编译内容以及如何编译。BUILD_STATIC_LIBRARY用来生成静态库。
sample目录下有更多更复杂的带有注释的Android.mk文件的例子供你参考。

Reference

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

    MY_SOURCES := foo.c
    ifneq ($(MY_CONFIG_BAR),)
      MY_SOURCES += bar.c
    endif
    LOCAL_SRC_FILES += $(MY_SOURCES)  
NDK提供的变量

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

NDK提供的宏方法

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

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

这里的问题是,第二次调用my-dir会将LOCAL_PATH定义为$(LOCAL_PATH)/foo/而不是$(LOCAL_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
    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.mksources/foo/lib2/Android.mk会被自动的包含进来。
这个方法用来向编译环境提供深层嵌套的源目录结构。默认情况下,NDK只查找sources/*/Android.mk中的文件。

模块定义变量

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

    LOCAL_MODULE := foo-version-1
    LOCAL_MODULE_FILENAME := libfoo

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

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

注意:在编译文件中使用Unix中的前向斜杠(/),Windows中的反向斜杠(\)不会被正确的处理。

    LOCAL_CPP_EXTENSION := .cxx
    LOCAL_C_INCLUDES := sources/foo
或
    LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo

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

    LOCAL_LDLIBS := -lz

查阅docs/STABLE-APIS.html获取这个版本的NDK中可用的系统库列表。

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_OPTIMdebug也会强制生成ARM二进制文件,因为thumb代码不能很好的被调试。

LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon

在这里,编译器会使用thumb+neon模式编译foo.c,使用thumb模式编译bar.c,使用arm+neon编译zoo.c。后缀.neon必须放在后缀.arm后面,如果你想同时使用两者的话。

'foo'module的定义:
    include $(CLEAR_VARS)
    LOCAL_MODULE := foo
    LOCAL_SRC_FILES := foo/foo.c
    LOCAL_EXPORT_CFLAGS := -DFOO=1
    include $(BUILD_STATIC_LIBRARY)
'bar'module的定义:
    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会被一层一层的传递,如果zoo依赖于bar,而bar依赖于foo,那么foo中的所有的flags会被传给zoo
exported flags在当前module编译时不会被使用,在上面的例子中,在编译foo/foo.c时不会传递-DFOO=1

    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

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
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
上一篇下一篇

猜你喜欢

热点阅读