欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > 内容正文

Android NDK编程浅入深出之--Android.mk,ndk--android.mk

来源: 开发者 投稿于  被查看 47390 次 评论:85

Android NDK编程浅入深出之--Android.mk,ndk--android.mk


    Android.mk  

Android.mk是一个向Android NDK构建系统描述NDK项目的GUN Makefile片段。它是每一个NDK项目的必备组件。构建系统希望它出现在jni子目录中。下面是hello-jni项目中Android.mk文件的内容。

  1. # Copyright (C) 2009 The Android Open Source Project  
  2. #  
  3. # Licensed under the Apache License, Version 2.0 (the "License");  
  4. # you may not use this file except in compliance with the License.  
  5. # You may obtain a copy of the License at  
  6. #  
  7. #       http://www.apache.org/licenses/LICENSE-2.0  
  8. #  
  9. # Unless required by applicable law or agreed to in writing, software  
  10. # distributed under the License is distributed on an "AS IS" BASIS,  
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  12. # See the License for the specific language governing permissions and  
  13. # limitations under the License.  
  14. #  
  15. LOCAL_PATH := $(call my-dir)  
  16.  
  17. include $(CLEAR_VARS)  
  18.  
  19. LOCAL_MODULE :hello-jni  
  20. LOCAL_SRC_FILES :hello-jni.c  
  21.  
  22. include $(BUILD_SHARED_LIBRARY) 

为了更好地理解它的句法,我们逐行分析。因为这个是一个GUN Makefile片段,所以它的句法和其他Makefile是一样的。每行都包含一个单独的指令,以“#”开头的是注释行,GUN Make 工具不处理它们。根据命名规范,变量名要大写。

注释块后的第一条指令是用来定义LOCAL_PATH变量的。根据Android构建系统的要求,Android.mk文档必须以LOCAL_PATH变量的定义开头。

  1. LOCAL_PATH :=$(call my-dir) 

Android构建系统利用LOCAL_PATH来定位源文件。因为将该变量设置为硬编码值并不合适,所以Android构建系统提供了一个名为my-dir的宏功能。通过将该变量设置为my-dir 宏功能的返回值,可以将其放在当前目录下。

Android构建系统将CLEAR_VARS变量设置为clear-vars.mk片段的位置。包含Makefile片段可以清除除了LOCAL_PATH以外的LOCAL_变量,例如LOCAL_MODULE与LOCAL_SRC_FILES等。

  1. Include $(CLEAR_VARS) 

这样做是因为Android构建系统在单次执行中解析多个构建文件和模块定义,而LOCAL_是全局变量。清除它们可以避免冲突,每一个原生组件被称为一个模块。

LOCAL_MODULE变量用来给这些模块设定一个唯一的名称。下面的代码将该模块的名称设为hello-jni:

  1. LOCAL_MODULE  :hello-jni 

因为模块名称也被用于给构建过程所生成的文件命名,所以构建系统给该文件添加了适当的前缀和后缀。本例中,hello-jni模块会生成一个共享库文件且构建系统会将它命名为libhello-jni.so。

用LOCAL_SRC_FILES变量定义用来建立和组装这个模块的源文件列表。

  1. LOCAL_SRC_FILES :hello-jni.c 

这里,hello-jni模块只由一个源文件生成,而LOCAL_SRC_FILES变量可以包含用空格分开的多个源文件名。

至此,Android.mk文件中定义的构建系统变量简单描述了原生项目。编译和生成实际模块的构建系统还需要包含合适的构建系统片段,具体需要包含哪些片段取决于想要生成模块的类型。

1. 构建共享库

为了建立可供主应用程序使用的模块,必须将该模块变成共享库。Android NDK构建系统将BUILD_SHARED_LIBRARY变量设置成build-shared-library.mk文件的保存位置。该Makefile片段包含了将源文件构建和组装成共享库的必要过程:

  1. include  $(BUILD_SHARED_LIBRARY) 

hello-jni是一个简单的模块;然而,除非你的模块需要特殊处理,否则Android.mk文档将会包含一模一样的流程和指令。

2. 构建多个共享库

基于不同的应用程序的体系结构,一个单独的Android.mk文档可能产生多个共享库模块。如程序:

  1. LOCAL_PATH := $(call my-dir)  
  2.  
  3. #  
  4. #模块 1  
  5. #  
  6. include $(CLEAR_VARS)  
  7.  
  8. LOCAL_MODULE :module1 
  9. LOCAL_SRC_FILES :module1.c  
  10. include $(BUILD_SHARED_LIBRARY)  
  11.  
  12. #  
  13. #模块 2  
  14. #  
  15. include $(CLEAR_VARS)  
  16.  
  17. LOCAL_MODULE :module2 
  18. LOCAL_SRC_FILES :module2.c  
  19.  
  20. include $(BUILD_SHARED_LIBRARY) 

在处理完这个Android.mk构建文档之后,Android NDK构建系统会产生libmodule1.so和libmodule2.so两个共享库。

3. 构建静态库

Android NDK构建系统也支持静态库。实际的Android应用程序并不直接使用静态库,并且应用程序包中也不包含静态库。静态库可以用来构建共享库。例如,在将第三方代码添加到现有原生项目中时,不用直接将第三方源代码包括在原生项目中,而是将第三方代码编译成静态库然后并入共享库,如程序:

  1. LOCAL_PATH := $(call my-dir)  
  2.  
  3. #  
  4. # 第三方AVI库  
  5. #  
  6. include $(CLEAR_VARS)  
  7.  
  8. LOCAL_MODULE :avilib 
  9. LOCAL_SRC_FILES :avilib.c platform_posix.c  
  10.  
  11. include $(BUILD_STATIC_LIBRARY)  
  12.  
  13. #  
  14. # 原生模块  
  15. #  
  16. include $(CLEAR_VARS)  
  17.  
  18. LOCAL_MODULE :module 
  19. LOCAL_SRC_FILES :module.c  
  20.  
  21. LOCAL_STATIC_LIBRARIES :avilib 
  22.  
  23. include $(BUILD_SHARED_LIBRARY) 

在将第三方代码模块生成静态库之后,共享库就可以通过将它的模块名添加到LOCAL_STATIC_LIBRARIES变量中来使用该模块。

4. 用共享库共享通用模块

静态库可以保证源代码模块化;但是,当静态库与共享库相连时,它就变成了共享库的一部分。在多个共享库的情况下,多个共享库与同一个静态库连接时,需要将通用模块的多个副本与不同共享库重复相连,这样就增加了应用程序的大小。在这种情况下,不用构建静态库,而是将通用模块作为共享库建立起来,而动态连接依赖模块以便消除重复的副本,如程序:

  1. LOCAL_PATH := $(call my-dir)  
  2.  
  3. #  
  4. # 第三方AVI库  
  5. #  
  6. include $(CLEAR_VARS)  
  7.  
  8. LOCAL_MODULE :avilib 
  9. LOCAL_SRC_FILES :avilib.c platform_posix.c  
  10.  
  11. include $(BUILD_SHARED_LIBRARY)  
  12.  
  13. #  
  14. # 原生模块 1  
  15. #  
  16. include $(CLEAR_VARS)  
  17.  
  18. LOCAL_MODULE :module1 
  19. LOCAL_SRC_FILES :module1.c  
  20.  
  21. LOCAL_SHARED_LIBRARIES :avilib 
  22.  
  23. include $(BUILD_SHARED_LIBRARY)  
  24.  
  25. #  
  26. # 原生模块 2  
  27. #  
  28. include $(CLEAR_VARS)  
  29.  
  30. LOCAL_MODULE :module2 
  31. LOCAL_SRC_FILES :module2.c  
  32.  
  33. LOCAL_SHARED_LIBRARIES :avilib 
  34.  
  35. include $(BUILD_SHARED_LIBRARY) 

5. 在多个NDK项目间共享模块

同时使用静态库和共享库时,可以在模块间共享通用模块。但要说明的是,所有这些模块必须属于同一个NDK项目。从R5版本开始,Android NDK也允许在NDK项目间共享和重用模块。考虑前面讲过的示例,可以通过以下步骤在多个NDK项目间共享avilib模块:

首先,将avilib源代码移动到NDK项目以外的位置,例如:C:\android\shared-modules\ avilib。为了避免命名冲突,目录结构也可以包含模块提供者的名字,例如:C:\ android\shared-modules \transcode\avilib。

注意:

在Android NDK构建系统中,共享模块路径不能包含空格。

作为共享模块,avilib需要自己的Android.mk文件,如程序:

  1. LOCAL_PATH := $(call my-dir)  
  2.  
  3. #  
  4. #第三方AVI库  
  5. #  
  6. include $(CLEAR_VARS)  
  7.  
  8. LOCAL_MODULE :avilib 
  9. LOCAL_SRC_FILES :avilib.c platform_posix.c  
  10.  
  11. include $(BUILD_SHARED_LIBRARY) 

现在,可以将avilib模块从NDK项目的Android.mk文件中移除。为了使用这个共享模块,将以transcode/avilib为参数调用函数宏import-module部分添加在构建文档的末尾。为了避免构建系统的冲突,应该将import-module函数宏调用放在Android.mk文档的末尾。如程序:

  1. #  
  2. # 原生模块  
  3. #  
  4. include $(CLEAR_VARS)  
  5.  
  6. LOCAL_MODULE :module 
  7. LOCAL_SRC_FILES :module.c  
  8. LOCAL_SHARED_LIBRARIES :avilib 
  9.  
  10. include $(BUILD_SHARED_LIBRARY)  
  11.  
  12. $(call import-module,transcode/avilib) 

import-module函数宏需要先定位共享模块,然后再将它导入到NDK项目中。默认情况下,import-module函数宏只搜索<Android NDK>/sources目录。为了搜索c:\android\shared-modules目录,定义一个名为NDK_MODULE_PATH的新环境变量并将它设置成共享模块的根目录,例如:c:\android\shared-modules。

6. 用Prebuilt库

使用共享模块要求有共享模块的源代码,Android NDK构建系统简单地把这些源文件包含在NDK项目中并每次构建它们。自R5版本以后,Android NDK也提供对Prebuilt库的支持。在下面的情况下,Prebuilt库是非常有用的:

想在不发布源代码的情况下将你的模块发布给他人。

想使用共享模块的预建版来加速构建过程。

尽管已经被编译了,但预建模块仍需要一个Android.mk构建文档,如程序:

  1. LOCAL_PATH := $(call my-dir)  
  2.  
  3. #  
  4. # 第三方预构建AVI库  
  5. #  
  6. include $(CLEAR_VARS)  
  7.  
  8. LOCAL_MODULE :avilib 
  9. LOCAL_SRC_FILES :libavilib.so  
  10.  
  11. include $(PREBUILT_SHARED_LIBRARY) 

LOCAL_SRC_FILES变量指向的不是源文件,而是实际Prebuilt库相对于LOCAL_PATH的位置。

注意:

Prebuilt库定义中不包含任何关于该库所构建的实际机器体系结构的信息。开发人员需要确保Prebuilt库是为与NDK项目相同的机器体系结构而构建的。

PREBUILT_SHARED_LIBRARY变量指向prebuilt-shared-library.mk Makefile片段。它什么都没有构建,但是它将Prebuilt库复制到了NDK项目的libs目录下。通过使用PREBUILT_STATIC_LIBRARY变量,静态库可以像共享库一样被用作Prebuilt库,NDK项目可以像普通共享库一样使用Prebuilt库了。

  1. ...  
  2. LOCAL_SHARED_LIBRARIES :=avilib 
  3. … 

7. 构建独立的可执行文件

在Android平台上使用原生组件的推荐和支持的方法是将它们打包成共享库。但是,为了方便测试和进行快速原型设计,Android NDK也支持构建独立的可执行文件。这些独立的可执行文件是不用打包成APK文件就可以复制到Android设备上的常规Linux应用程序,而且它们可以直接执行,而不通过Java应用程序加载。生成独立可执行文件需要在Android.mk构建文档中导入BUILD_EXECUTABLE变量,而不是导入BUILD_SHARED_ LIBRARY变量,如程序:

  1. #  
  2. # 独立的可执行的原生模块  
  3. #  
  4. include $(CLEAR_VARS)  
  5.  
  6. LOCAL_MODULE :module 
  7. LOCAL_SRC_FILES :module.c  
  8.  
  9. LOCAL_STATIC_LIBRARIES :avilib 
  10.  
  11. include $(BUILD_EXECUTABLE) 

BUILD_EXECUTABLE变量指向build-executable.mk Makefile片段,该片段包含了在Android平台上生成独立可执行文件的必要步骤。独立可执行文件以与模块相同的名称被放在libs/<machine architecture>目录下。尽管放在该目录下,但在打包阶段它并没有被包含在APK文件中。

8. 其他构建系统变量

除了在前几节提到的变量之外,Android NDK构建系统还支持其他变量,本节将对这些变量进行简要说明。

构建系统定义的变量有:

TARGET_ARCH:目标CPU体系结构的名称,例如arm

TARGET_PLATFORM:目标Android平台的名称,例如:android-3

TARGET_ARCH_ABI:目标CPU体系结构和ABI的名称,例如:armeabi-v7a

TARGET_ABI:目标平台和ABI的串联,例如:android-3-armeabi-v7a

可被定义为模块说明部分的变量有:

LOCAL_MODULE_FILENAME:可选变量,用来重新定义生成的输出文件名称。默认情况下,构建系统使用LOCAL_MODULE的值作为生成的输出文件名称,但变量LOCAL_MODULE_ FILENAME可以覆盖LOCAL_MODULE的值。

LOCAL_CPP_EXTENSION:C++源文件的默认扩展名是.cpp。这个变量可以用来为C++源代码指定一个或多个文件扩展名。

  1. …  
  2. LOCAL_CPP_ EXTENSION :=.cpp  .cxx  
  3. … 

LOCAL_CPP_FEATURES:可选变量,用来指明模块所依赖的具体C++特性,如RTTI、exceptions等。

  1. …  
  2. LOCAL_CPP_FEATURES :=rtti 
  3. … 

LOCAL_C_INCLUDES:可选目录列表,NDK安装目录的相对路径,用来搜索头文件。

  1. …  
  2. LOCAL_C_INCLUDES :=sources/shared-module  
  3. LOCAL_C_INCLUDES :=$(LOCAL_PATH)/include  
  4. … 

LOCAL_CFLAGS:一组可选的编译器标志,在编译C和C++源文件的时候会被传送给编译器。

  1. …  
  2. LOCAL_CFLAGS :=-DNDEBUG  -DPORT=1234 
  3. … 

LOCAL_CPP_FLAGS:一组可选的编译标志,在只编译C++源文件时被传送给编译器。

LOCAL_WHOLE_STATIC_LIBRARIES:LOCAL_STATIC_LIBRARIES的变体,用来指明应该被包含在生成的共享库中的所有静态库内容。

(当几个静态库之间有循环依赖时,LOCAL_WHOLE_STATIC_LIBRARIES很有用。)

LOCAL_LDLIBS:链接标志的可选列表,当对目标文件进行链接以生成输出文件时该标志将被传送给链接器。它主要用于传送要进行动态链接的系统库列表。例如:要与Android NDK日志库链接,使用以下代码:

  1. LOCAL_LDFLAGS :=?llog 

LOCAL_ALLOW_UNDEFINED_SYMBOLS:可选参数,它禁止在生成的文件中进行缺失符号检查。若没有定义,链接器会在符号缺失时生成错误信息。

LOCAL_ARM_MODE:可选参数,ARM机器体系结构特有变量,用于指定要生成的ARM二进制类型。默认情况下,构建系统在拇指模式下用16位指令生成,但该变量可以被设置为arm来指定使用32位指令。
 

  1. LOCAL_ARM_MODE :=arm 

该变量改变了整个模块的构建系统行为;可以用.arm扩展名指定只在arm模式下构建特定文件。
 

  1. LOCAL_SRC_FILES :=file1.c  file2.c.arm 

LOCAL_ARM_NEON:可选参数,ARM机器体系结构特有变量,用来指定在源文件中应该使用的ARM高级单指令流多数据流(Single Instruction Multiple Data,SIMD)(a.k.a. NEON)内联函数。

  1. LOCAL_ARM_NEON :=true 

该变量改变了整个模块的构建系统行为;可以用.neon扩展名指定只构建带有NEON内联函数的特定文件。
 

  1. LOCAL_SRC_FILES :=file1.c  file2.c.neon 

LOCAL_DISABLE_NO_EXECUTE:可选变量,用来禁用NX Bit安全特性。NX Bit代表Never Execute(永不执行),它是在CPU中使用的一项技术,用来隔离代码区和存储区。这样可以防止恶意软件通过将它的代码插入应用程序的存储区来控制应用程序。

  1. LOCAL_DISABLE_NO_EXECUTE :=true 

LOCAL_EXPORT_CFLAGS:该变量记录一组编译器标志,这些编译器标志会被添加到通过变量LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES使用本模块的其他模块的LOCAL_CFLAGS定义中。

  1. LOCAL_MODULE :avilib 
  2. ...  
  3. LOCAL_EXPORT_CFLAGS := − DENABLE_AUDIO  
  4. ...  
  5. LOCAL_MODULE :module1 
  6. LOCAL_CFLAGS := − DDEBUG  
  7. ...  
  8. LOCAL_SHARED_LIBRARIES :avilib 

编译器在构建module1时会以-DENABLE_AUDIO  –DDEBUG标志执行。

LOCAL_EXPORT_CPPFLAGS:和LOCAL_EXPORT_CLAGS一样,但是它是C++特定代码编译器标志。

LOCAL_EXPORT_LDFLAGS:和LOCAL_EXPORT_CFLAGS一样,但用作链接器标志。

LOCAL_EXPORT_C_INCLUDES:该变量允许记录路径集,这些路径会被添加到通过变量LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES使用该模块的LOCAL_C_INCLUDES定义中。

LOCAL_SHORT_COMMANDS:对于有大量资源或独立的静态/共享库的模块,该变量应该被设置为true。诸如Windows之类的操作系统只允许命令行最多输入8 191个字符;该变量通过分解构建命令使其长度小于8 191个字符。在较小的模块中不推荐使用该方法,因为使用它会让构建过程变慢。

LOCAL_FILTER_ASM:该变量定义了用于过滤来自LOCAL_SRC_FILES变量的装配文件的应用程序。

9. 其他的构建系统函数宏

本节概括了Android NDK构建系统支持的其他函数宏。

all-subdir-makefiles:返回当前目录的所有子目录下的Android.mk构建文件列表。例如,调用以下命令可以将子目录下的所有Android.mk文件包含在构建过程中:

  1. include $(call all-subdir-makefiles) 

this-makefile:返回当前Android.mk构建文件的路径。

parent-makefile:返回包含当前构建文件的父Android.mk构建文件的路径。

grand-parent-makefile:和parent-makefile一样但用于祖父目录。

10. 定义新变量

开发人员可以定义其他变量来简化他们的构建文件。以LOCAL_和NDK_前缀开头的名称预留给Android NDK构建系统使用。建议开发人员定义的变量以MY_开头,如程序:

  1. ...  
  2. MY_SRC_FILES :avilib.c platform_posix.c  
  3. LOCAL_SRC_FILES := $(addprefix avilib/, $(MY_SRC_FILES))  
  4. ... 

11. 条件操作

Android.mk构建文件也可以包含关于这些变量的条件操作,例如:在每个体系结构中包含一个不同的源文件集,如程序:

  1. ...  
  2. ifeq ($(TARGET_ARCH),arm)  
  3. LOCAL_SRC_FILES + = armonly.c  
  4. else  
  5. LOCAL_SRC_FILES + = generic.c  
  6. endif  
  7. ... 

Application.mk

Application.mk是Android NDK构建系统使用的一个可选构建文件。和Android.mk文件一样,它也被放在jni目录下。Application.mk也是一个GUN Makefile片段。它的目的是描述应用程序需要哪些模块;它也定义所有模块的通用变量。以下是Application.mk构建文件支持的变量:

APP_MODULES:默认情况下,Android NDK构建系统构建Android.mk文件声明的所有模块。该变量可以覆盖上述行为并提供一个用空格分开的、需要被构建的模块列表。

APP_OPTIM:该变量可以被设置为release或debug以改变生成的二进制文件的优化级别。默认情况下使用的是release模式,并且此时生成的二进制文件被高度优化。该变量可以被设置为debug模式以生成更容易调试的未优化二进制文件。

APP_CLAGS:该变量列出了一些编译器标志,在编译任何模块的C和C++源文件时这些标志都会被传给编译器。

APP_CPPFLAGS:该变量列出了一些编译器标志,在编译任何模块的C++源文件时这些标志都会被传给编译器。

APP_BUILD_SCRIPT:默认情况下,Android NDK构建系统在项目的jni子目录下查找Android.mk构建文件。可以用该变量改变上述行为,并使用不同的生成文件。

APP_ABI:默认情况下,Android NDK构建系统为armeabi  ABI生成二进制文件。可以用该变量改变上述行为,并为其他ABI生成二进制文件,例如:

  1. APP_ABI :mips 

另外,可以设置多个ABI

  1. APP_ABI :armeabi mips 

为所有支持的ABI生成二进制文件

  1. APP_ABI :all 

APP_STL:默认情况下,Android NDK构建系统使用最小STL运行库,也被称为system库。可以用该变量选择不同的STL实现。

  1. APP_STL :=stlport_shared 

APP_GNUSTL_FORCE_CPP_FEATURES:与LOCAL_CPP_EXTENSIONS变量相似,该变量表明所有模块都依赖于具体的C++特性,如RTTI、exceptions等。

APP_SHORT_COMMANDS:与LOCAL_SHORT_COMMANDS变量相似,该变量使得构建系统在有大量源文件的情况下可以在项目中使用更短的命令。


        转载声明:http://blog.csdn.net/jmq_0000/article/details/46762683



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关频道:

用户评论