dylanin1999

导航

统计

Android NDK学习笔记(一)

一、构建系统

(一)Android.mk

LOCAL_PATH: Android.mk文档必须以LOCAL_PATH变量的定义开头

CLEAR_VARS: 设置为clear-vars.mk片段的位置。包含Makefile片段可以清楚除了LOCAL_PATH以外的LOCAL _< NAME>变量,例如 LOCAL_MODULELOCAL_SRC_FILES等; 因为在单次执行构建中,会解析多个构建文件和模块定义,LOCAL_< NAME> 是全局变量,清除他们可以避免冲突。

Eg: Include $(CLEAR_VARS)

LOCAL_MOUDLE : 用来给这些模块设定一个唯一的名字:

Eg:LOCAL_MOUDLE : = hello-jni

模块名液被用于构建过程所生成的文件命名,所以构建系统会给该文件添加适当的前缀和后缀。

Eg:libhello-jni.so

LOCAL_SRC_FILES:用来建立和组装这个模块的源文件列表, 可以包含用空格分开的多个源文件名

Eg: LOCAL_SRC_FILES := hello-jni.c

1、构建共享库

BUILD_SHARED_LIBRARY: 设置成build_shared_library.mk文件的保存位置。该Makefile片段包含了将源文件构建和组装成共享库的必要过程: include $(BUILD_SHARED_LIBRARY)

2、构建多个共享库

基于不同的应用程序的体系结构,一个单独的Android.mk文档可能产生多个共享库模块,为了达到这个目的,需要定义多个模块:

Eg:

LOCAL_PATH := $(call my-dir)

#模块1

include $(CLEAR_VARS)

LOCAL_MOUDLE := module1

LOCAL_SRC_FILES := module1.c

include $(BUILD_SHARED_LIBRARY)

#模块2

LOCAL_MODULE := module2

LOCAL_SRC_FILES := module2.c

include $(BUILD_SHARED_LIBRARY)

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

3、构建静态库

Android应用不适用静态库,并且应用程序包中也不包含静态库,但是可以用于构建共享库。

在Android.mk中使用静态库:

LOCAL_PATH := $(call my-dir)

#第三方AVI库

include $(CLEAR_VARS)

LOCAL_MODULE := avilib

LOCAL_SRC_PATH := avilib.c platform_posix.c

include $(BUILD_STATIC_LIBRARY)

#原生模块

include $(CLEAR_VARS)

LOCAL_MODULE := module

LOCAL_SRC_FILES := module.c

LOCAL_STATIC_LIBRARY := avilib

#在第三方代码模块生产静态库后,共享库就可以通过他的模块名添加LOCAL_STATIC_LIBRARY变量中来使用该模块

include $(BUILD_SHARED_LIBRARY)

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

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

Eg:

LOCAL_PATH := $(call my-dir)

#第三方AVI库

include $(CLEAR_VARS)

LOCAL_MODULE := avilib

LOCAL_SRC_FILES := avilib.c platform_posix.c

#原生模块1

include $(CLEAR_VARS)

LOCAL_MODULE := module1

LOCAL_SRC_FILES := module1.c

LOCAL_SHARED_LIBRARIES := avilib

include $(BUILD_SHARED_LIBRARY)

#原生模块2

include $(CLEAR_VARS)

LOCAL_MODULE := module2

LOCAL_SRC_FILES := module2.c

LOCAL_SHARED_LIBRARIES := avilib

include $(BUILD_SHARED_LIBRARY)

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

同时使用静态库和关系库时,可以通过以下步骤在模块间共享通用模块:

(1)将avilib的源码移动到NDK项目外的位置,设定路径为AVI_Path

(2)作为共享模块,avilib需要自己的Android.mk文件,如下所示:

LOCAL_PATH := $(call my-dir)

#第三方AVI库

include $(CLEAR_VARS)

LOCAL_MODULE := avilib

LOCAL_SRC_FILE := avilib.c platform_posix.c

include $(BUILD_SHARED_LIBRARY)

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

#原生模块

include $(CLEAR_VARS)

LOCAL_MODULE := module

LOCAL_SRC_FILE := module.c

LOCAL_SHARED_LIBRARY := avilib

include $(BUILD_SHARED_LIBRARY)

$(call import-module,transcode/avilib)

(4)import-module函数宏需要先定位共享模块,然后再导入到NDK项目中。默认情况下,import-module函数宏只搜索< Android NDK >/sources目录。

6、使用Prebuilt库

使用共享模块要求有共享模块的源码,Android NDK构建系统简单地把这些源文件包含在NDK项目中并每次构建他们。在以下情况下,Prebuilt库非常有用:

(1)在不想发布源码的情况下把模块发布给别人

(2)在使用共享模块的预建版来加速构建过程

预构建共享模块的Android.mk文件如下:

LOCAL_PATH := $(call my-dir)

#第三方预构建AVI库

include $(CLEAR_VARS)

LOCAL_MODULE := avilib

LOCAL_SRC_FILES := libavilib.so

include $(PREBUILT_SHARED_LIBRARY)

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

PREBUILT_SHARED_LIBRARY变量指向prebuilt-shared-library.mk Makefile 片段。他将Prebuilt库复制到了NDK项目的libs目录下。通过使用PREBUILT_SHARED_LIBRARY变量,静态库可以像共享库一样被用作Prebuilt库,NDK项目就可以像使用普通共享库一样使用Prebuilt库了。

Eg:LOCAL_SHARED_LIBRARIES := avilib

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

在一般快速测试时,我们一般会选择构建独立的可执行文件,这样程序可以直接执行,而不需要通过Java应用程序加载。

构建独立可执行程序需要在Android.mk文件中导入BUILD_EXECUTABLE变量,而不是导入BUILD_SHARED_LIBRARY变量,实例代码如下所示:

#独立的可执行的原生模块

include $(CLEAR_VARS)

LOCAL_MODULE := module

LOCAL_SRC_FILES := module.c

LOCAL_STATIC_LIBRARIES := avilib

include $(BUILD_EXECUTABLE)

BUILD_EXECUTABLE变量指向build-executable.mk Makefile 片段,该片段包含了在Android平台上生成独立可执行文件的必要步骤。独立可执行文件以与模块系统的名称放在libs/< machine architecture>目录下。

8、其他构件系统变量

(1)构建系统定义的变量有:

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

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

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

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

(2)定义为模块说明部分的变量有:

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

LOCAL_CPP_EXTENSION: C++源文件的默认扩展名是.cpp

Eg: LOCAL_CPP_EXTENSION := .cpp .cxx

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

Eg: LOCAL_CPP_FEATURES := rtti

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

Eg: LOCAL_CFLAGS := -DNDEBUG -DPORT=1234

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

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

LOCAL_LDLIBS: 链接标志的可选列表,当对目标文件进行连接以生成输出文件时,该标志将被传送给链接器。它主要用于传送要进行的行动态链接的系统库列表。

Eg: 要与Android NDK日志库链接 :

LOCAL_LDFKAGS := --llog

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

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

Eg: LOCAL_ARM_MODE := arm

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

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

LOCAL_ARM_NEON: 可选参数,ARM机器体系结构特有变量。用来指定在源文件中应该使用的ARM高级单指令流多数据流内联函数

Eg: LOCAL_SRC_FILES := true

类似的,可以用**.neon**扩展名指定只构建带有NEON内联函数的特定文件

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

LOCAL_DISABLE_NO_EXECUTE: 可选变量,用来禁止NX Bit安全特性。NX Bit代表Never Execute(永不执行),他是在CPU中使用的一项技术,用来隔离代码区和存储区。

Eg: LOCAL_DISABLE_NO_EXECUTE := true

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

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

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

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

LOCAL_SHORT_COMMANDS: 对于有大量资源或独立的静态/共享库,该变量应设为true

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

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

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

Eg: include $(call all-subdir-makefiles)

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

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

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

10、定义新变量

以**LOCAL_NDK_前缀的变量名称预留给Android NDK构建系统使用,建议开发人员可以使用MY_**为前缀定义变量。

Eg: MY_SRC_FILES := avilib.c platform_posix.c

LOCAL_SRC_FILES := $(addprefix avilib/, $(MY_SRC_FILES))

11、条件操作

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

ifeq ($(TARGET_ARCH), arm)

LOCAL_SRC_FILES += armonly.c

else

LOCAL_SRC_FILES += generic.c

endif

(二)Application.mk

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

1、APP_MODULES

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

2、APP_OPTIM

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

3、APP_CLAGS

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

4、APP_CPPFLAGS

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

5、APP_BUILD_SCRIPT

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

6、APP_ABI

​ 默认情况下,Android NDK构建系统为armeabi ABI生成二进制文件。使用该变量,可以为其他ABI生成二进制文件。

Eg: APP_ABI := mips

设置多个ABI:

Eg: APP_ABI := armeabi mips

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

Eg: APP_ABI := all

7、APP_STL

​ 默认情况,Android NDK使用最小STL库,也被称为system库,使用该变量,可以指定不同的STL库。

Eg: APP_STL := stlport_shared

8、APP_GNUSTL_FORCE_CPP_FEATURES

​ 与LOCAL_CPP_EXTNESIONS变量相似,该变量表明所有模块都依赖于具体的C++特性。如RTTI,exception等。

9、APP_SHORT_COMMANDS:

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

二、使用NDK-build脚本

1、ndk-build在一般情况下,应该在主项目目录中执行。-C参数可以用于指定命令行中NDK项目的位置,这样一来ndk-build脚本就可以从任意的位置开始。

ndk-build -C /path/to/the/project

2、如果源文件没有被修改,Android NDK构建系统不会重新构建目标。-B参数可以强制重构建所有代码

ndk-build -B

3、清理生成的二进制文件和目标文件

ndk-build clean

4、加快构建速度

ndk-build -j 4

三、排除构建系统故障

1、启用Android NDK的内部状态日志功能

ndk-build NDK_LOG = 1

2、只显示构建命令

ndk-build V = 1

posted on   DylanYeung  阅读(253)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示