Android.mk 中的静态库和共享库

有些类似的问题碰到过很多次,但大脑里总是各种碎片化的记忆,长时间记住这些碎片并不是人类大脑的强项,所以有事没事就要捋捋,知道前因后果才
能记忆深刻。

Android.mk

Android.mk 只是GNU Makefile的一小部分,用来编译module,这个module可以是app,也可以是library。Android.mk可能会被编译系统解析多次,所以
要谨慎定义变量,建议尽量不要在其中定义变量。

静态库与共享库的区别

简单来讲,静态库是在连接阶段直接拷贝到代码中使用的,而共享库是由加载器加载到内存,在运行时使用的。编译出来的静态库(这里指jar包)里每
个java文件对应的class文件都单独存在,可以直接导入Eclipse等IDE使用,而编译出来的共享库(jar包),内部是Android字节码Dex格式的文件,
一般无法导入Eclipse等IDE使用。Android.mk中由BUILD_JAVA_LIBRARY指定生成共享库,BUILD_STATIC_JAVA_LIBRARY指定生成静态库。

编译静态库和共享库

下面是两个生成静态库和动态库的例子。
生成静态库的mk文件:
// 返回Android.mk所在的当前路径
LOCAL_PATH:= $(call my-dir)
// 清理除LOCAL_PATH变量以外的LOCAL_XXX
include $(CLEAR_VARS)

// 生成静态库的name
LOCAL_MODULE := simple_game

// 设置在那个版本下编译,user, eng, tests, optional(全版本编译)
LOCAL_MODULE_TAGS := optional
// 签名类型 testkey, media, platform, shared, 默认为testkey
LOCAL_CERTIFICATE := platform

// 生成静态库使用的源文件
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-Iaidl-files-under, src)

// 设置生成静态库
include $(BUILD_STATIC_JAVA_LIBRARY)
 生成共享库的mk文件:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := simple_game

LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform

LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-Iaidl-files-under, src)

// 安装时需要一起安装的模块
LOCAL_REQUIRED_MODULES      := simple_game.xml

// 设置生成共享库
include $(BUILD_JAVA_LIBRARY)
################################################################
include $(CLEAR_VARS)

LOCAL_MODULE                := simple_game.xml
// 定制LOCAL_MODULE_PATH变量的值
LOCAL_MODULE_CLASS          := ETC
// 设置安装的路径
LOCAL_MODULE_PATH           := $(TARGET_OUT)/etc/permissions
LOCAL_MODULE_TAGS           := optional

LOCAL_SRC_FILES             := simple_game.xml
// 将文件预置进系统
include $(BUILD_PREBUILT)
共享库需要一个xml文件配置安装的信息,LOCAL_REQUIRED_MODULES设置了该文件,当共享库安装时,LOCAL_REQUIRED_MODULES制定的模块也会安装到系
统中。
安装的位置由LOCAL_MODULE_PATH指定,当LOCAL_MODULE_PATH没有设置时,系统将会根据LOCAL_MODULE_CLASS的值来判断安装的位置,
LOCAL_MODULE_CLASS变量将通过/build/core/base_rules.mk文件设置默认的安装目录,常用的值有:

apk文件: APPS
so文件: SHARED_LIBRARIES
bin文件: EXECUTABLES
其他文件: ETC

当LOCAL_MODULE_PATH和LOCAL_MODULE_CLASS均没有设置时,系统会根据编译生成的不同模块(根据include$()判断)来自动设置LOCAL_MODULE_CLASS的值,
但遇到include $(BUILD_PREBUILT)编译选项时,系统不会设置模块的LOCAL_MODULE_CLASS,需要显示设置。
最后针对单一文件进行预编译需要设置BUILD_PREBUILT,对于多文件需要设置BUILD_MULTI_PREBUILT宏。

静态库和共享库的使用

完成了库的编译,接下来看看库的使用方法。
静态库很多情况来自第三方,包括jar包和第三方工程。首先,获得到jar后需要导入项目代码,一般放在libs目录下,接下来需要修改项目的mk,加入
编译静态库的代码,类似一下XML:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

// 依赖静态库的名称,可以随便起名
LOCAL_STATIC_JAVA_LIBRARIES := simple_game
// 预编译静态库,冒号之前名称要和LOCAL_STATIC_JAVA_LIBRARIES一致,冒号后面是静态库路径
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := simple_game:libs/simple_game.jar
include $(BUILD_MULTI_PREBUILT)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-Iaidl-files-under, src)

// 定义生成apk名称
LOCAL_PACKAGE_NAME := game
// 定义app是否要放在/system/priv-app
LOCAL_PRIVILEGED_MODULE := true

LOCAL_CERTIFICATE := platform
// 定义是否需要代码混淆
LOCAL_PROGUARD_ENABLED := disabled

// 编译MODULE为apk
include $(BUILD_PACKAGE)
include $(BUILD_PACKAGE) 会结合LOCAL_PRIVILEGED_MODULE判断生成的apk是最终安装在/system/app下还是/system/priv-app下。
LOCAL_PROGUARD_ENABLED定义了编译apk时是否进行代码混淆,默认为full,将工程代码全部混淆,也可以用LOCAL_PROGUARD_FLAG_FILES配置混淆规则。

静态库的使用比较简单,下面来看看共享库的使用。
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-Iaidl-files-under, src)

LOCAL_PACKAGE_NAME := game
LOCAL_PRIVILEGED_MODULE := true
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
LOCAL_PROGUARD_ENABLED := disabled

// MODULE 依赖的共享库
LOCAL_JAVA_LIBRARIES += simple_game
// 安装时module时,共享库需要一起安装。
LOCAL_REQUIRED_MODULES := simple_game

include $(BUILD_PACKAGE)
上面是一个简单使用共享库的例子,LOCAL_JAVA_LIBRARIES定义了依赖的共享库,全编译时检查到该选项系统会先编译simple_game库,然后检查
LOCAL_REQUIRED_MODULES,决定是否安装该库(即是否在/system/framework下生成该库),注意,单编时mm, mm -B, mmm均不会编译module
使用的依赖文件,需要使用m+module(如: m game)来编译。

app在使用时千万别忘了在AndroidManifest.xml中添加该共享库:
<uses-library android:name="simple_game" android:required="false"/>
有很多同学不注意就忘了,然后查了半天才恍然大悟,切记切记!

最后,类似$(call my-dir)宏函数的定义,可以在/build/core/definitions.mk中找到,其他变量定义可以在/build/core/base_rules.mk中找到。有
兴趣的同学可以去查看。

你可能感兴趣的:(Android)