Android 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:androidshared-modules avilib。

为了避免命名冲突,文件夹结构也能够包括模块提供者的名字,比如:C: androidshared-modules ranscodeavilib。

注意:

在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:androidshared-modules文件夹,定义一个名为NDK_MODULE_PATH的新环境变量并将它设置成共享模块的根文件夹。比如:c:androidshared-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模式以生成更easy调试的未优化二进制文件。

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



原文地址:https://www.cnblogs.com/wzjhoutai/p/7168261.html