Android.mk揭秘系列之初级篇

本文详细介绍了Android.mk文件的作用及其语法,包括如何定义静态库和共享库等模块,以及如何利用NDK构建系统自动处理依赖关系等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android.mk简介
Android.mk文件是编译Module时的描述文件,进一步来说:
-它是会被构建系统解析一次或多次的GNU Makefile的一个小片段
-它的语法是让你把源代码分组为"modules",modules可以是这样的:
    - a static library 静态库
    - a shared library 共享库

虽然可以使用static library来生成共享库,但是只有shared library将被安装/复制到您的应用程序包。


在每个Android.mk文件里面你可以定义一个或多个modules,多个modules可以使用相同的源文件。构建系统也为您处理许多细节。例如,您不需要在Android.mk为将要生成的文件列出头文件或依赖关系。NDK构建系统将为您自动做这些工作。并且当你更新NDK时你无须关注Android.mk。

一个简单的例子
安卓项目"hello JNI"(项目目录为apps/hello-jni/project)
-"src"目录包含"hello JNI"的JAVA的源文件
-"jni"目录包含"hello JNI"的native源文件比如jni/hello-jni.c
  hello-jni.c实现了一个简单的共享库(实现了一个native 方法,这个方法返回一 个字符串给VM应用)
-这个"jni/Android.mk"文件给NDK构建系统描述了这个共享库,文件内容为:
   LOCAL_PATH := $(call my-dir)
   include $(CLEAR_VARS)
   LOCAL_MODULE    := hello-jni
   LOCAL_SRC_FILES := hello-jni.c
   include $(BUILD_SHARED_LIBRARY)

我们现在进行逐行分析
LOCAL_PATH := $(call my-dir)
一个Android.mk文件必须开始先定义LOCAL_PATH 变量。这个变量用于在开发树中查找源文件。在这个例子中,宏函数‘my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。
include $(CLEAR_VARS)
CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多除了LOCAL_PATH的LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...) 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。
LOCAL_MODULE := hello-jni
LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的且不包含空格。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件。为了支持来自安卓平台源代码的Android.mk文件,如果你不命名为"foo"而是
"libfoo"那么最后还是生成"libfoo.so"文件。
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。默认的C++源文件的扩展名是".cpp",你可以通过LOCAL_CPP_EXTENSION自己定义C++源文件的扩展名。
include $(BUILD_SHARED_LIBRARY)
include $(BUILD_SHARED_LIBRARY) 这个BUILD_SHARED_LIBRARY是构建系统提供的一个变量。这个变量指向了一个GNU Makefile 脚本。这个脚本负
责收集你定义在include $(CLEAR_VARS)之后的LOCAL_XXX 变量的全部信息,同时决定要编译什么以及如何精确的编译。

定义变量
这是你应该依赖或在Android.mk中定义的变量的列表。 您可以定义变量,但NDK构建系统保留以下变量名:
 - 以LOCAL_开头的名称(例如LOCAL_MODULE)
 - 以PRIVATE_,NDK_或APP_(内部使用)开头的名称
 - 小写名称(在内部使用,例如“my-dir”)

如果你需要在Android.mk文件中定义自己的变量,我们建议使用MY_前缀,一个小例子:
    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多次,对于其中的一些变量可能每次解析都有不同的含义。

CLEAR_VARS
它指向一个构建脚本,这个脚本定义了几乎所有的LOCAL_XXX变量。这些变量在后面的"Module-description"部分会列出。你需要在定义一个module之前包含它比如:include $(CLEAR_VARS)

BUILD_SHARED_LIBRARY
指向一个构建脚本,这个脚本会收集有关您在LOCAL_XXX变量中提供的所有关于模块的信息,并确定如何根据Android.mk构建目标共享库。请注意,在包含此文件之前,必须至少定义LOCAL_MODULE和LOCAL_SRC_FILES。
用法示例:
  include $(BUILD_SHARED_LIBRARY)
这个会生成一个名字为lib$(LOCAL_MODULE).so的文件


BUILD_STATIC_LIBRARY
BUILD_SHARED_LIBRARY的变体,用于构建目标静态库。 静态库不会复制到您的项目/包中,但可以用于构建共享库(请参阅下面的LOCAL_STATIC_LIBRARIES和LOCAL_WHOLE_STATIC_LIBRARIES)。
 用法示例:
include $(BUILD_STATIC_LIBRARY)
注意这个会生成一个名字为lib$(LOCAL_MODULE).a的文件

PREBUILT_SHARED_LIBRARY
指向用于指定 prebuilt shared library的构建脚本。 与BUILD_SHARED_LIBRARY和BUILD_STATIC_LIBRARY不同,LOCAL_SRC_FILES的值必须是预建共享库(例如foo / libfoo.so)的路径,而不是源文件。你可以使用LOCAL_PREBUILTS这个变量在另一个module引用这个prebuilt library

PREBUILT_STATIC_LIBRARY
这个和PREBUILT_SHARED_LIBRARY相同,但是是一个静态lib文件.详情请看docs/PREBUILTS.html。


NDK提供的函数宏:
以下是GNU Make'function'宏,必须使用'$(call <function>)'来求值。 他们返回文本信息。
my-dir
返回最后一个包含的Makefile的路径,它通常是当前的Android.mk的目录。 这对于在Android.mk开头定义LOCAL_PATH非常有用,例如:


        LOCAL_PATH := $(call my-dir)


重要提醒由于GNU Make的工作方式是依次返回last、included、Makefile,所以不要在including其他文件之后调用call my-dir


        LOCAL_PATH := $(call my-dir)
        ... 声明一个 module
        include $(LOCAL_PATH)/foo/Android.mk
        LOCAL_PATH := $(call my-dir) //这个LOCAL_PATH的值会是$(LOCAL_PATH)/foo/而不是当前Android.mk的上一级目录。
        ... 声明一个另一个 module


这样写是也可以的


        LOCAL_PATH := $(call my-dir)
        ... 声明一个 module
        LOCAL_PATH := $(call my-dir)
        ... 声明一个另一个 module
        # extra includes at the end of the Android.mk
        include $(LOCAL_PATH)/foo/Android.mk


但是上面的写法不能保存第一个LOCAL_PATH的值所以你可以按照下面的写法


        MY_LOCAL_PATH := $(call my-dir)
        LOCAL_PATH := $(MY_LOCAL_PATH)
        ... 声明一个 module
        include $(LOCAL_PATH)/foo/Android.mk
        LOCAL_PATH := $(MY_LOCAL_PATH)
        ... 声明一个另一个 module


Module-description 变量:
以下变量用于向构建系统描述module。 你应该在'include (CLEAR_VARS)'和'include $(BUILD_XXXXX)'之间定义这些变量。


LOCAL_PATH
这个变量用于定义当前Android.mk的父目录。你需要在Android.mk的开始定义它。
比如:
LOCAL_PATH := $(call my-dir)
这个变量不会被$(CLEAR_VARS)清除,如果你在Android.mk文件定义了不止一个module那么你只需要一个LOCAL_PATH 变量。


LOCAL_MODULE
这是模块的名称。 它必须在所有模块名称中是唯一的,并且不应包含任何空格。 你必须在包含任何$(BUILD_XXXX)脚本之前定义它。默认情况下,模块名称确定生成的文件的名称,例如lib <foo> .so用于名为<foo>的shared library module。 但是,如果你要在其他Android.mk或Application.mk中的modules引用这个module你应该用<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中放置路径或文件扩展名,这些将由构建系统自动处理。

LOCAL_SRC_FILES
构建module的源文件的列表。
只列出将传递给编译器的文件,不用列出这些文件的依赖,因为构建系统会自动为您计算依赖关系。

请注意,源文件路径是相对于LOCAL_PATH,您可以使用路径组件,
例如: LOCAL_SRC_FILES:= foo.c\toto/bar.c
注意:在构建文件中始终使用Unix样式的正斜杠(/)。 Windows样式的反斜杠将无法正确处理。

LOCAL_STATIC_LIBRARIES
static libraries modules(由BUILD_STATIC_LIBRARY构建)列表应该链接到这个模块。 这只在shared library modules中有意义。


LOCAL_SHARED_LIBRARIES
shared libraries 的所有modules列表会在运行时使用,同时会加在最后生成的文件里面去。


LOCAL_WHOLE_STATIC_LIBRARIES
LOCAL_STATIC_LIBRARIES的变体,用于表示相应的库模块应该用作链接器的"全局"modules。当在几个静态库之间存在循环依赖时,这通常很有用。 注意,当用于构建shared library时,这会强制static libraries的所有对象文件被添加到最终的二进制文件。但不会加在生成的可执行文件里面。


LOCAL_LDLIBS 
这些前缀之类的标记用于构建你的module,比如“-l”前缀的含义是指定特定系统库的名称,以下内容将告诉编译器编译的时候加载/system/lib/libz.so的module:
 LOCAL_LDLIBS:= -lz


LOCAL_MODULE_SUFFIX

定义生成的module的后缀

LOCAL_MODULE_SUFFIX := $(COMMON_JAVA_PACKAGE_SUFFIX)代表module的后缀为.jar

LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)代表module的后缀为.apk


LOCAL_PACKAGE_NAME

编译后生成的APK的名字


编译一个简单的APK
  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  # Build all java files in the java subdirectory
  LOCAL_SRC_FILES := $(call all-subdir-java-files)
  # Name of the APK to build
  LOCAL_PACKAGE_NAME := LocalPackage
  # Tell it to build an APK
  include $(BUILD_PACKAGE)

编译一个依赖静态Jar文件的一个APK
  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  # List of static libraries to include in the package
  LOCAL_STATIC_JAVA_LIBRARIES := static-library
  # Build all java files in the java subdirectory
  LOCAL_SRC_FILES := $(call all-subdir-java-files)
  # Name of the APK to build
  LOCAL_PACKAGE_NAME := LocalPackage
  # Tell it to build an APK
  include $(BUILD_PACKAGE)


编译一个平台签名APK
  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS
  # Build all java files in the java subdirectory
  LOCAL_SRC_FILES := $(call all-subdir-java-files)
  # Name of the APK to build
   LOCAL_PACKAGE_NAME := LocalPackage
   LOCAL_CERTIFICATE := platform
   # Tell it to build an APK
   include $(BUILD_PACKAGE)


编译一个指定厂商的签名的APK
  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  # Build all java files in the java subdirectory
  LOCAL_SRC_FILES := $(call all-subdir-java-files)//返回一个位于当前'my-dir'  路径的子目录中的所有Android.mk的列表。
  # Name of the APK to build
  LOCAL_PACKAGE_NAME := LocalPackage
  LOCAL_CERTIFICATE := platform
  # Tell it to build an APK
  include $(BUILD_PACKAGE)


生成一个prebuiltAPK
  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  # Module name should match apk name to be installed.
  LOCAL_MODULE := LocalModuleName
  LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
  LOCAL_MODULE_CLASS := APPS
  LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
  include $(BUILD_PREBUILT)


生成一个静态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)


Android.mk 变量
LOCAL_  这些变量被设置在每个module。 include $(CLEAR_VARS)会清除它们。
HOST_ and TARGET_ 这些包含特定于主机或目标构建的目录和定义。 在Android.mk中设置变量名不要以HOST_或TARGET_开头。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值