首页 > 代码库 > NDK使用二进制库方法(翻译)
NDK使用二进制库方法(翻译)
NDK Prebuilt library support:
NDK使用二进制库方法:
Android NDK r5 introduced support for prebuilt libraries (shared and static), i.e. the ability to include and use, in your applications, prebuilt version of libraries. This feature can be useful for two things: 1/ You want to distribute your own libraries to third-party NDK developers without distributing your sources. 2/ You want to use a prebuilt version of your own libraries to speed up your build. This document explains how this support works.
Android NDK r5版本引入了引用二进制库(提前编译好的共享和静态库)的能力,可以在应用中包含和使用提前编译好的库。这个功能使以下两件事有帮助:
1/ 你需要分发你自己的库给第三方的NDK开发者,但是不想分发源码。
2/你需要引入自己的库文件,加快构建速度。
这篇文档将解释上面的两种情况是如何实现的。
I. Declaring a prebuilt library module:
I. 定义一个预先编译好的二进制库模块:
Each prebuilt library must be declared as a *single* independent module to the build system. Here is a trivial example where we assume that the file "libfoo.so" is located in the same directory than the Android.mk below:
每个预先编译好的库在构建系统中必须定义成一个单独的独立模块。这里是一个简单的例子,我们假定文件“libfoo.so”和Android.mk位于同一个路径,Android.mk内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
Notice that, to declare such a module, you really only need the following: 1. Give the module a name (here ‘foo-prebuilt‘). This does not need to correspond to the name of the prebuilt library itself. 2. Assign to LOCAL_SRC_FILES the path to the prebuilt library you are providing. As usual, the path is relative to your LOCAL_PATH. IMPORTANT: You *must* ensure that the prebuilt library corresponds to the target ABI you are using. More on this later. 3. Include PREBUILT_SHARED_LIBRARY, instead of BUILD_SHARED_LIBRARY, if you are providing a shared, library. For static ones, use PREBUILT_STATIC_LIBRARY. A prebuilt module does not build anything. However, a copy of your prebuilt shared library will be copied into $PROJECT/obj/local, and another will be copied and stripped into $PROJECT/libs/<abi>.
注意,为了定义这样一个模块,你只需要做以下事情:
1. 给这个模块命名(这里是“foo-prebuild”),这不需要和库文件名字本身一样
2.给 LOCAL_SRC_FILES 赋值,指向你的预编译好的库所在的路径。像其他一样,提供和LOCAL_PATH对于的相对路径。注意,必须保证预编译库的版本和目标ABI移植。
3.如果包含的是共享库,应写成PREBUILT_SHARED_LIBRARY,而不是BUILD_SHARED_LIBRARY。如果是静态库,就是PREBUILT_STATIC_LIBRARY。预编译的模块不会出发构建过程。只是把预编译的共享库拷贝到$PROJECT/obj/local路径,静态库则是拷贝到$PROJECT/libs/<abi>并进行裁剪。
II. Referencing the prebuilt library in other modules:
Simply list your prebuilt module‘s name in the LOCAL_STATIC_LIBRARIES or LOCAL_SHARED_LIBRARIES declaration in the Android.mk of any module that depends on them. For example, a naive example of a module using libfoo.so would be: include $(CLEAR_VARS) LOCAL_MODULE := foo-user LOCAL_SRC_FILES := foo-user.c LOCAL_SHARED_LIBRARIES := foo-prebuilt include $(BUILD_SHARED_LIBRARY)
II.在其他模块中引用预编译的库:
简单的在依赖库的应用的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_LIBRARIES := foo-prebuilt
include $(BUILD_SHARED_LIBRARY)
III. Exporting headers for prebuilt libraries:
III. 导出预编译库的头文件:
The example above was called ‘naive‘ because, in practice, the code in foo-user.c is going to depend on specific declarations that are normally found in a header file distributed with the prebuilt library (e.g. "foo.h"). In other words, foo-user.c is going to have a line like: #include <foo.h>
And you need to provide the header and its include path to the compiler when building the foo-user module. A simple way to deal with that is to use exports in the prebuilt module definition. For example, assuming that a file "foo.h" is located under the ‘include‘ directory relative to the prebuilt module, we can write: include $(CLEAR_VARS) LOCAL_MODULE := foo-prebuilt LOCAL_SRC_FILES := libfoo.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_SHARED_LIBRARY)
The LOCAL_EXPORT_C_INCLUDES definition here ensures that any module that depends on the prebuilt one will have its LOCAL_C_INCLUDES automatically prepended with the path to the prebuilt‘s include directory, and will thus be able to find headers inside that.
上面的例子之所以说“简单”,是因为实际上foo-user.c里面的代码会依赖预编译库配套的头文件(如“foo.h”)中的定义。换句话说,foo-user.c需要有一行类似于下面的代码 #include <foo.h> ,而且你在构建时应该提供他引用的头文件并放置在编译器能访问的路径下。一个简单的处理方法是在预编译的库的定义中中使用exports。例如,假设"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)
IV. Debugging prebuilt binaries:
IV. 调试预编译的库
We recommend you to provide prebuilt shared libraries that contain debug symbols. The version that is installed into $PROJECT/libs/<abi>/ is always stripped by the NDK build system, but the debug version will be used for debugging purposes with ndk-gdb.
我们建议你提供包含调试信息的共享库,拷贝到$PROJECT/libs/<abi>/目录的版本会被NDK构建系统剥离调试信息,而调试版本可以供ndk-gdb用于调试目的。
V. ABI Selection of prebuilt binaries:
V. 预编译库的ABI适配
As said previously, it is crucial to provide a prebuilt shared library that is compatible with the targeted ABI during the build. To do that, check for the value of TARGET_ARCH_ABI, its value will be: armeabi => when targeting ARMv5TE or higher CPUs armeabi-v7a => when targeting ARMv7 or higher CPUs x86 => when targeting x86 CPUs mips => when targeting MIPS CPUs
Note that armeabi-v7a systems can run armeabi binaries just fine. Here‘s an example where we provide two versions of a prebuilt library and select which one to copy based on the target 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)
Here. we assume that the prebuilt libraries to copy are under the following directory hierarchy: Android.mk --> the file above armeabi/libfoo.so --> the armeabi prebuilt shared library armeabi-v7a/libfoo.so --> the armeabi-v7a prebuilt shared library include/foo.h --> the exported header file
NOTE: Remember that you don‘t need to provide an armeabi-v7a prebuilt library, since an armeabi one can easily run on the corresponding devices.
就像前面说的,提供一个与目标ABI版本匹配的预编译的库非常重要。检查TARGET_ARCH_ABI的值,如果目标版本为ARMv5TE或更高,值应该是 armeabi 。目标是ARMv7或更高,值应该是armeabi-v7a。目标是x86时值为x86;目标是MIPS系列CPU时,值为mips。注意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 --> 上面的make文件
armeabi/libfoo.so--> armeabi 版本库
armeabi-v7a/libfoo.so --> armeabi-v7a 版本库
include/foo.h --> 导出头文件
注意:记住你不是必须要提供一个armeabi-v7a版本的预编译库,因为armeabi版本就可以在相关设备商跑的很好。