程序员人生 网站导航

关于Android import-module 和NDK_MODULE_PATH

栏目:综合技术时间:2016-02-28 11:18:23

===========================

1、将NDK代码模块化

2、导出1个预编译库

===========================




1、将NDK代码模块化

Android module paths (sharing code made easy):


Android模块路径(方便同享代码):

==============================================


Starting from r5, the Android NDK comes with a cool feature that allows you to share and reuse other peoples modules more easily.


从r5开始,Android NDK引入1个很酷的特性,允许你更容易地同享和重用他人的模块。


I. Overview:


1、概述:

------------


The main idea behind this feature are:


这个特性背后的主要思想:


- You can install NDK modules outside of your main project source tree.


- 你可以在你的主工程源码树之外安装NDK模块


- You can easily import them into your project with a one-line command.


- 你可以用1个单行命令简单地“导入”它们到你的工程。


In practice, heres how this works:


实际上,这里介绍它是如何工作的:


1. Your NDK_MODULE_PATH environment variable will contain a list of search paths on your system to lookup for modules.


1. 你的NDK_MODULE_PATH环境变量将包括1个在你的系统上查找模块的搜索路径列表。


It is up to you to set the variable, and to copy other modules to the directories you listed in it.


由你来决定设置变量和复制你在其中列出的目录下的其他模块。


2. To import a module, place a line like the following to, preferably at the *end* of, your Android.mk:


2. 要想导入1个模块,放置以下所示的1行指令,最好放在你的Android.mk文件结束处:


$(call import-module,)


This will look for/Android.mk under any of the directories listed in your NDK_MODULE_PATH.


这将查找在你的NDK_MODULE_PATH中列出的任意目录下的/Android.mk


(The reason why it must be at the end is to avoid messing with the results of the my-dir function. See its description in docs/ANDROID-MK.html for details).


(它必须放在结束处的理由是为了不my-dir函数结果的干扰。详细请参考docs/ANDROID-MK.html中的描写)。


3. Declare that your projects modules depend on the imported one by listing them in either your LOCAL_STATIC_LIBRARIES or LOCAL_SHARED_LIBRARIES. For example:


3. 通过在你的LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES中列出它们,声明你的工程模块依赖于这个导入模块。例如:


LOCAL_STATIC_LIBRARIES +=



4. Rebuild!


4. 重新构建!


Remember that NDK r5 also added the ability for a module to "export" declarations to other modules that depend on it (for example, see the definition of LOCAL_EXPORT_CFLAGS in docs/ANDROID-MK.html).


记住NDK r5还添加模块的能力以“导出”声明到其它依赖于它的模块(例如,参考docs/ANDROID-MK.html中LOCAL_EXPORT_CFLAGS的定义)


A well-written module will correctly export all the things its dependees need, et voila.


1个书写良好的模块将正确地导出它的被依赖者所需要的所有东西,就是这模样(注:et voila是法语)。


Now for the full details:


现在是完全的细节:


I. NDK_MODULE_PATH:


1、NDK_MODULE_PATH:

-------------------


The NDK_MODULE_PATH variable must contain a list of directories.


NDK_MODULE_PATH变量必须包括1个目录列表。


* Due to GNU Make limitations, NDK_MODULE_PATH must not contain any space. The NDK will complain if this is not the case.


* 由于GNU Make的限制,NDK_MODULE_PATH不准包括任何空格。NDK将解释它是不是背背要求。


* Use : as the path separator.


* 使用分号作为路径分隔符。


* On Windows, use / as the directory separator.


* 在Windows上,使用正斜杠作为目录分隔符(注:应当是指把Windows风格的反斜杠改成正斜杠)。


The directories of NDK_MODULE_PATH will be searched in order. The first//Android.mk file that is found during the lookup will be included automatically.


NDK_MODULE_PATH的目录将被顺次搜索。第1个在查找种被找到的//Android.mk文件将自动被包括。


As a convenience, $NDK/sources is appended to your NDK_MODULE_PATH definition by the NDK build system. This allows you to easily import the helper libraries that come with it (see docs/CPU-FEATURES.html for a practical example).


作为约定,$NDK/sources被NDK构建系统尾加到你的NDK_MODULE_PATH定义中。这允许你简单地导入由它生成的辅助库(见docs/CPU-FEATURES.html中的1个实际例子)


II. Writing an import module:


2、书写1个导入模块:

-----------------------------


Writing an import module is trivial and very similar to what you do when writing project modules:


书写1个导入模块是细小而且非常类似于你在书写工程模块时所做的东西:


1. Create a sub-directory from one of your NDK_MODULE_PATH directories.


1. 在你的NDK_MODULE_PATH目录中的1个目录下创建子目录。


For example, if NDK_MODULE_PATH is defined to /home/user/ndk-modules, then create the directory /home/user/ndk-modules/my-module/


例如,如果NDK_MODULE_PATH被定义为/home/user/ndk-modules,那末创建目录/home/user/ndk-modules/my-module/


2. Place an Android.mk and eventual source code there.


2. 在那里放置1个Android.mk和终究源码。


Just like you would for a project module, where these files normally go to $PROJECT_PATH/Android.mk. In the example above, this would go to /home/user/ndk-modules/my-module/Android.mk


就像你对1个工程模块那样,这些文件通常去到$PROJECT_PATH/Android.mk中。在上面的例子中,它将集中到/home/user/ndk-modules/my-module/Android.mk


NOTE: Any Application.mk file here will be ignored.


注意:这里任何Application.mk文件将被疏忽。


3. Any module that depends on your new module, would import by calling the import-module function. For example:


3. 依赖于你的新模块的任何模块,将通过调用import-module函数进行导入。例如:


$(call import-module,my-first-module)


Import modules *can* import other modules, but circular dependencies are not permitted and will be detected. Dependencies are transitive and the build system will compute all the things that need to be built for you.


导入模块可以导入其他模块,但不允许循环依赖,它会被检测到。依赖是及物的,构建系统将为你计算所有需要被构建的所有东西。


The NDK build system will not place object files or executables in your import module directory (they will all be placed under the projects build directory, e.g. $PROJECT_PATH/obj/).


NDK构建系统将不会在你的导入模块目录中放置对象文件或可履行文件(它们将全部放在工程的构建目录下,例如$PROJECT_PATH/obj/)


You can however distribute prebuilt binaries in your import module with the new PREBUILT_STATIC_LIBRARIES or PREBUILT_SHARED_LIBRARIES feature (see docs/ANDROID-MK.html).


但是你可以通过新的PREBUILT_STATIC_LIBRARIES或PREBUILT_SHARED_LIBRARIES特性,在你的导入模块中分发预构建2进制文件(见docs/ANDROID-MK.html)。


This makes it easy to package and redistribute your import module directory to third-parties.


这将使打包和重新分发你的导入模块目录到第3方变得简单。


III. Naming an import module:


3、命名1个导入模块:

-----------------------------


It is important to understand a few things related to the naming of your import module:


重要是要理解关于你的导入模块命名的1些事情:


- What import-module does is really search for a file named Android.mk using the list provided by NDK_MODULE_PATH, then include while performing very little bit of house-keeping.


- import-module所做的实际上是使用NDK_MODULE_PATH提供的列表搜索名为Android.mk的文件,然后当履行非常小量的内部工作时包括它。


Your imported Android.mk can define any number of modules, with any name. As a consequence, there is no direct relationship betweenin the following line:


你的导入Android.mk可以通过名称定义任意数量的模块。因此,在下面指令行中之间不会有直接的关联:


$(call import-module,/)


And the names of the modules defined under//Android.mk.


和定义在//Android.mk下的模块名称。


IN CASE OF DOUBT, KEEP IT SIMPLE!


如果还是不明白,就让它保持简单!


If you only plan to provide one import module, just name it like the base import directory.


如果你只是计划提供1个导入模块,只要像导入基目录那样命名它就能够了。


On the other hand, you may want to provide a static and a shared version of your module: use distinct names under the same top-level Android.mk. Consider the following build script:


另外一方面,你可能像提供你的模块的静态和动态版本:在相同的顶级Android.mk下使用不同的名称。斟酌以下构建脚本:


$NDK_MODULE_PATH/foo/bar/Android.mk:


LOCAL_PATH := $(call my-dir)


# Static version of the library is named bar_static

# 库的静态版本被命名为bar_static

include $(CLEAR_VARS)

LOCAL_MODULE := bar_static

LOCAL_SRC_FILES := bar.c

# Ensure our dependees can include too

# 确保我们的被依赖者还可以包括

LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)

include $(BUILD_STATIC_LIBRARY)


# Shared version of the library is named bar_shared

# 库的动态版被命名为bar_shared

LOCAL_MODULE := bar_shared

LOCAL_SRC_FILES := bar.c

LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)

include $(BUILD_SHARED_LIBRARY)


Another module would refer to it by doing the following:


另外一个模块将通过以下方法援用它:


1. Import foo/bar, as in:


1. 导入foo/bar,像这样:


$(call import-module,foo/bar)


2. To use the static library:


2. 要使用静态库:


...

LOCAL_STATIC_LIBRARIES := bar_static


3. Or to use the shared library:


3. 或要使用动态库:


...

LOCAL_SHARED_LIBRARIES := bar_shared



- The module namespace is flat, so try to give your modules names that are likely to not collide with other. Note that your can use LOCAL_MODULE_FILENAME to give the name of your modules binary file, independently from its LOCAL_MODULE (see docs/ANDROID-MK.html for definition and usage). For example:


- 模块的命名空间是平的,所以尝试给你的模块1个不可能和其它模块名称冲突的名字。注意你可使用LOCAL_MODULE_FILENAME设置你的模块的2进制文件的名称,独立于LOCAL_MODULE(见docs/ANDROID-MK.html取得其定义和用法)。例如:


include $(CLEAR_VARS)

LOCAL_MODULE := super_foo

LOCAL_MODULE_FILENAME := foo   # will give libfoo.so # 将给定为libfoo.so

LOCAL_SRC_FILES := foo-src.c

LOCAL_CFLAGS := -DVOLUME=11

include $(BUILD_SHARED_LIBRARY)


include $(CLEAR_VARS)

LOCAL_MODULE := normal_foo

LOCAL_MODULE_FILENAME := foo   # will also give libfoo.so # 还将给定为libfoo.so

LOCAL_SRC_FILES := foo-src.c

include $(BUILD_SHARED_LIBRARY)


Defines two modules named "super_foo" and "normal_foo" which both produce a shared library named libfoo.so


定义两个模块,名为super_foo和normal_foo,它们都将产生1个名为libfoo.so的动态库。


As a consequence, only one of them can be used by your project or a conflict will happen at build time. This allows you to select either the normal or optimized version in your NDK build scripts, while keeping the same simple loading instruction in your Java sources as:


因此,只有它们其中1个可以被你的工程使用或在构建期产生冲突。这允许你用你的NDK构建脚本选择正常或优化版本,保持在你的Java源代码中这模样的相同而且简单的加载指令:


static {

System.loadLibrary("foo");

}



IV. Tips & Recommendations:


4、提示和建议:

---------------------------


* You dont need to import a module before you can reference it!


* 你不需要在你可以援用它前导入模块!


* Use import-module at the *end* of your Android.mk to avoid messing with the result of my-dir. See the description of this function in docs/ANDROID-MK.html to understand why.


* 在你的Android.mk结束处使用import-module以免my-dir结果的干扰。参考docs/ANDROID-MK.html中这个函数的描写以理解为何。


* It is *strongly* suggested to use a subdirectory for your import tags, that describes its origin, as in:


* 强烈建议对你的导入标签使用子目录,以描写它的来源,像这模样:


$(call import-module,gtk/glib)


or something like:


或类似这样:


$(call import-module,com.example/awesomelib)


IMPORTANT: THE android IMPORT DIRECTORY, AND ANY OF ITS SUB-DIRECTORIES IS *RESERVED* FOR NDK USAGE. FEEL FREE TO ORGANIZE YOUR OTHER IMPORT MODULES AS YOU WANT OTHERWISE.


重要:“android”导入目录,和它的任意子目录由于NDK的使用而保存。但是欢迎你依照自己的意愿组织其它导入模块。


2、导出1个预编译库


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.


Android NDK r5引入预构建库(动态和静态)的支持,即在你的利用程序中包括和使用库的预构建版本。


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.


1、你想发布你自己的库给第3方NDK开发者而不分发你的源代码。


2/ You want to use a prebuilt version of your own libraries to speed up your build.


2、你想使用你自己的库的预构建版本以加速你的构建。


This document explains how this support works.


这个文档解释这类支持是如何工作的。


I. Declaring a prebuilt library module:


1、声明1个预构建库模块:

---------------------------------------


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:


每一个预构建库必须向构建系统声明为1个单1独立模块。这里有个小示例,我们假定文件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)


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.


1. 给模块1个名称(这里是foo-prebuilt)。不需要对应预构建库本身的名称。


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.


2. 把你提供的预构建库的路径赋给LOCAL_SRC_FILES。通常路径相对你的LOCAL_PATH


IMPORTANT: You *must* ensure that the prebuilt library corresponds to the target ABI you are using. More on this later.


重要:你必须确保预构建库对应你正在使用的目标ABI(注:利用程序2进制接口,即操作系统开放给利用程序的接口)。更多相干信息见后。


3. Include PREBUILT_SHARED_LIBRARY, instead of BUILD_SHARED_LIBRARY, if you are providing a shared, library. For static ones, use PREBUILT_STATIC_LIBRARY.


3. 包括PREBUILT_SHARED_LIBRARY,而非BUILD_SHARED_LIBRARY,如果你提供的是1个动态库。对静态库,请使用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/.


1个预构建模块不编译任何东西。但是,你的预构建动态库的副本将被复制到$PROJECT/obj/local,而另外一个副本将被复制并裁剪进$PROJECT/libs/。


II. Referencing the prebuilt library in other modules:


2、援用其它模块的预构建库:

------------------------------------------------------


Simply list your prebuilt modules name in the LOCAL_STATIC_LIBRARIES or LOCAL_SHARED_LIBRARIES declaration in the Android.mk of any module that depends on them.


在依赖于你的构建模块的所有模块的Android.mk的LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES的声明中简单列出这些预构建模块的名称。


For example, a naive example of a module using libfoo.so would be:


例如,1个使用libfoo.so的模块的单纯例子将是:


include $(CLEAR_VARS)

LOCAL_MODULE := foo-user

LOCAL_SRC_FILES := foo-user.c

LOCAL_SHARED_LIBRARY := foo-prebuilt

include $(BUILD_SHARED_LIBRARY)


III. Exporting headers for prebuilt libraries:


3、导出预构建库的头文件:

----------------------------------------------


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").


上面的例子被称为“单纯”是由于,实际上,foo-user.c的代码将依赖于特定的声明,那些声明通常在预构建库分发的头文件中找到(例如,foo.h)


In other words, foo-user.c is going to have a line like:


换句话说,foo-user.c将有类似的1行:


#include


And you need to provide the header and its include path to the compiler when building the foo-user module.


而你需要在构建foo-user模块时提供头文件和它的编译器包括目录。


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:


1个简单处理方法是在预构建模块定义中使用导出。例如,假定1个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)


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 prebuilts include directory, and will thus be able to find headers inside that.


这里LOCAL_EXPORT_C_INCLUDES的定义确保任何依赖于预构建模块的模块将自动具有带预构建库包括目录为前置值的LOCAL_C_INCLUDES,而它将能够找到包括其中的头文件。


IV. Debugging prebuilt binaries:


4、调试预构建2进制文件:

--------------------------------


We recommend you to provide prebuilt shared libraries that contain debug symbols. The version that is installed into $PROJECT/libs// is always stripped by the NDK build system, but the debug version will be used for debugging purposes with ndk-gdb.


我们建议你提供包括调试符号的预构建同享库。安装进$PROJECT/libs//的版本常常是被NDK构建系统裁剪过(注:ndk提供的工具链中包括了strip工具,它应当是用来优化生成文件的大小),但调试版本将可以供ndk-gdb使用以到达调试目的。


V. ABI Selection of prebuilt binaries:


5、预构建2进制文件的ABI选择:

--------------------------------------


As said previously, it is crucial to provide a prebuilt shared library that is compatible with the targetted ABI during the build. To do that, check for the value of TARGET_ARCH_ABI, its value will be:


正如前面所说,关键问题是在构建期间提供1个兼容于目标ABI的预构建动态库(注:开源是好事啊)。为了做到那点,检查TARGET_ARCH_ABI的值,它的值将是:


armeabi     => when targetting ARMv5TE or higher CPUs


armeabi     => 目标为ARMv5TE或更高的CPU


armeabi-v7a => when targetting ARMv7 or higher CPUs


armeabi-v7a => 目标为ARMv7或更高的CPU


x86         => when targetting x86 CPUs


x86         => 目标为x86 CPU。


Note that armeabi-v7a systems can run armeabi binaries just fine.


注意armeabi-v7a系统可以很好地运行armeabi的2进制文件。


Heres an example where we provide two versions of a prebuilt library and select which one to copy based on the target ABI:


这里有1个例子,我们提供两个版本的预构建库并且基于目标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


Android.mk            --> 上面的文件


armeabi/libfoo.so     --> the armeabi prebuilt shared library


armeabi/libfoo.so     --> armeabi预构建动态库


armeabi-v7a/libfoo.so --> the armeabi-v7a prebuilt shared library


armeabi-v7a/libfoo.so --> armeabi-v7a预构建动态库


include/foo.h         --> the exported header file


include/foo.h         --> 导出的头文件


NOTE: Remember that you dont need to provide an armeabi-v7a prebuilt library, since an armeabi one can easily run on the corresponding devices.

注意:记住你不需要提供1个armeabi-v7a预构建库,由于armeabi版本可以更容易地运行在相应的装备上。


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐