Android NDK r5引入预构建库(动态和静态)的支持,即在你的应用程序中包含和使用库的预构建版本。
这个特性可能在两方面有用:
1、你想发布你自己的库给第三方NDK开发者而不分发你的源代码。
2、你想使用你自己的库的预构建版本以加速你的构建。
这个文档解释这种支持是如何工作的。
一、声明一个预构建库模块:
每个预构建库必须向构建系统声明为一个单一独立模块。这里有个小示例,我们假设文件libfoo.so位于以下Android.mk相同的目录中。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
注意,要声明这个模块,你实际上只需要以下东西:
1. 给模块一个名称(这里是foo-prebuilt)。不需要对应预构建库本身的名称。
2. 把你提供的预构建库的路径赋给LOCAL_SRC_FILES。通常路径相对于你的LOCAL_PATH
重要:你必须确保预构建库对应你正在使用的目标ABI(注:应用程序二进制接口,即操作系统开放给应用程序的接口)。更多相关信息见后。
3. 包含PREBUILT_SHARED_LIBRARY,而非BUILD_SHARED_LIBRARY,如果你提供的是一个动态库。对于静态库,请使用PREBUILT_STATIC_LIBRARY
一个预构建模块不编译任何东西。然而,你的预构建动态库的副本将被复制到$PROJECT/obj/local,而另一个副本将被复制并裁剪进$PROJECT/libs/<abi>。
二、引用其它模块的预构建库:
在依赖于你的构建模块的所有模块的Android.mk的LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES的声明中简单列出这些预构建模块的名称。
例如,一个使用libfoo.so的模块的单纯例子将是:
include $(CLEAR_VARS)
LOCAL_MODULE := foo-user
LOCAL_SRC_FILES := foo-user.c
LOCAL_SHARED_LIBRARY := foo-prebuilt
include $(BUILD_SHARED_LIBRARY)
三、导出预构建库的头文件:
上面的例子被称为“单纯”是因为,实际上,foo-user.c的代码将依赖于特定的声明,那些声明通常在预构建库分发的头文件中找到(例如,foo.h)
换句话说,foo-user.c将有类似的一行:
#include <foo.h>
而你需要在构建foo-user模块时提供头文件和它的编译器包含目录。
一个简单处理方法是在预构建模块定义中使用导出。例如,假设一个foo.h文件位于相对于预构建模块的include目录下,我们可以这样写:
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := libfoo.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
这里LOCAL_EXPORT_C_INCLUDES的定义确保任何依赖于预构建模块的模块将自动拥有带预构建库包含目录为前置值的LOCAL_C_INCLUDES,而它将能够找到包含其中的头文件。
四、调试预构建二进制文件:
我们建议你提供包含调试符号的预构建共享库。安装进$PROJECT/libs/<abi>/的版本常常是被NDK构建系统裁剪过(注:ndk提供的工具链中包含了strip工具,它应该是用来优化生成文件的大小),但调试版本将可以供ndk-gdb使用以达到调试目的。
五、预构建二进制文件的ABI选择:
正如前面所说,关键问题是在构建期间提供一个兼容于目标ABI的预构建动态库(注:开源是好事啊)。为了做到那点,检查TARGET_ARCH_ABI的值,它的值将是:
armeabi => when targetting ARMv5TE or higher CPUs
armeabi => 目标为ARMv5TE或更高的CPU
armeabi-v7a => 目标为ARMv7或更高的CPU
x86 => 目标为x86 CPU。
注意armeabi-v7a系统可以很好地运行armeabi的二进制文件。
这里有一个例子,我们提供两个版本的预构建库并且基于目标ABI选择哪一个版本去复制。
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libfoo.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
这里。我们假设要复制的预构建库位于以下目录层次:
Android.mk --> 上面的文件
armeabi/libfoo.so --> armeabi预构建动态库
armeabi-v7a/libfoo.so --> armeabi-v7a预构建动态库
include/foo.h --> 导出的头文件
注意:记住你不需要提供一个armeabi-v7a预构建库,因为armeabi版本可以更容易地运行在相应的设备上。