ndk-build
是上一代android ndk开发编译工具,尽管现在官方推荐使用CMake
,AS默认的工具也切换成了后者,但是仍有必要对ndk-build
有一定了解,以求:
ndk-build
如何使用;ndk-build
项目切换到CMake
;还是先回顾一下NDK开发的步骤:
javah
命令生成.h头文件;可以看到ndk-build和CMake是NDK开发编码完成后的编译工具,是整个开发环节的最后一环。下面对ndk-build
工具的使用做一个简单的介绍:
Android.mk文件用于指导编译器如何编译程序,文件名后缀为mk表明其是一个Makefile。Android.mk用于配置每个module的C/C++源码,module可以是静态库、共享库或者独立的可执行文件。 一个Android.mk文件可以有一个或多个module,modules之间也可以有依赖关系。来看一个最简单的Android.mk配置文件:
# 获取脚本当前文件路径
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 生成的so文件名
LOCAL_MODULE := hello
# 目标文件
LOCAL_SRC_FILES := hello.c
# 指定生成库为动态链接库,即so文件
include $(BUILD_SHARED_LIBRARY)
NDK提供了宏、变量以及模块描述变量,这些宏、变量以及变量的赋值共同组成了Android.mk文件。
宏:包括my-dir
、all-subdir-makefiles
等,通过$(call )
来调用,返回文本信息。
变量:包括CLEAR_VARS
、BUILD_SHARED_LIBRARY
、TARGET_ARCH
等,由NDK编译系统提供,并且在Android.mk文件被解析前就已经存在。Android.mk文件有可能被多次解析,因此每次解析时这些变量的值都有可能不同。
模块描述变量:Module-description,包括LOCAL_PATH
、LOCAL_MODULE
、LOCAL_SRC_FILES
等LOCAL_前缀变量,这些变量除LOCAL_PATH
外,均填写在语句include $(CLEAR_VARS)
和include $(BUILD_XXX)
之间。
下面介绍一下常用变量:
变量 | 说明 | 可选项 | 示例 |
---|---|---|---|
LOCAL_PATH | 当前目录,为模块描述变量,一个Android.mk必须定义LOCAL_PATH,用于定位源文件,在本例中,使用的是编译系统提供的宏“my-dir”(“my-dir”返回最近一次包括Makefile文件路径,通常为当前Android.mk所在目录),用于返回当前目录。此变量不会被CLEAR_VARS清除,所以每个Android.mk文件只需要定义一次就可以了。 | 调用宏 | - |
CLEAR_VARS | 变量清除,由编译系统提供,作用是清除模块变量(在include $(CLEAR_VARS)和include $(BUILD_XXX)之间的LOCAL_XXX模块变量),当然LOCAL_PATH除外。由于所有的编译控制文件都是单一的GNU Make可执行上下文环境中解析,而这个上下文环境中所有的变量都是全局的,所以编译module前需要清理相应变量。 | 无 | - |
LOCAL_MODULE | module名称,module的唯一标识,这个名字必须是唯一的,且中间不能有空格。在默认情况下,它决定了生成的文件名,如“hello-jni”对应的动态库名称为libhello-jni.so,然而要索引它时,需要“hello-jni”即可,也可以通过变量LOCAL_MODULE_FILENAME 来覆盖这个默认名称。 |
模块名称 | - |
LOCAL_SRC_FILES | 源码文件,包括C/C++源文件列表,这些源文件会被编译到一个module中,不过也不必列出头文件和包括文件,编译系统会自动为你找打所有需要的依赖关系。值得注意的是linux下路径使用顺斜杠(/)。 | C/C++源文件列表 | - |
BUILD_SHARED_LIBRARY | 动态库编译,编译器提供的变量,表示编译成动态库,它指向一个GNU Makefile脚本,这个脚本收集从include $(CLEAR_VARS)后所有的LOCAL_XXX变量中定义的所有信息,决定编译什么以及怎么编译。还有BUILD_STATIC_LIBRARY 表示编译成静态库(.a),静态库不会被拷贝到APK中。 |
无 | - |
PREBUILT_SHARED_LIBRARY | 预编译,指向一个编译脚本,用来指定一个预编译动态库。使用此变量时,不像BUILD_SHARED_LIBRARY 和BUILD_STATIC_LIBRARY 那样,LOCAL_SRC_FILES 的值必须是只能有一个指向预编译动态库的路径,如foo/libfoo.so,而不是源文件。PREBUILD_STATIC_LIBRARY 和PREBUILD_SHARED_LIBRARY 一样,只不过是用于引用静态库。 |
include $ ( C L E A R V A R S ) < b r > L O C A L M O D U L E : = t e s t < b r > L O C A L S R C F I L E S : = l i b / (CLEAR_VARS) <br> LOCAL_MODULE := test <br> LOCAL_SRC_FILES := lib/ (CLEARVARS)<br>LOCALMODULE:=test<br>LOCALSRCFILES:=lib/(TARGET_ARCH_ABI)/libtest.so include $(PREBUILT_SHARED_LIBRARY) |
|
TARGET_ARCH_ABI | 目标ABI名称,若定义了多个ABI,则每次解析Android.mk时值都不一样,主要使用场景为根本不同的ABI定义不同的文件等。 | - | |
LOCAL_LDLIBS | 链接库,用于额外链接选项,所有的库都有“-l”前缀。可同时列出多个库,用空格隔开。Android NDK默认链接了多个库,不需要显式地添加到LOCAL_LDLIBS中,包括 the standard C libraries,the standard C++ libraries,real-time extensions和 pthread库。同时也提供了一些需要显式添加的库。 | Android-3:-llog (Android Log) -lzZlib(Compression Library) -ldl(Dynamic Linker Library) Android-4:-lGLESv1_CM(OpenGL ES 1.x Library) Android-5:-lGLESv2(OpenGL ES 2.0 Library) Android-8:-ljnigraphics(The jnigraphics Library) Android-9:-lEGL(The EGL graphics library) -lOpenSLES(Open ES native audio Library) -landroidNatice (Android API) Android-14:-lOpenMAXAL(OpenMAX AL natice multimedia Library) Android-18:-lGLESv3(OpenGL ES 3.0 Library) Android-21:-lGLESv3(OpenGL ES 3.1 Library) |
LOCAL_LDLIBS := -llog -ldl |
LOCAL_CFLAGS | 编译、链接标志,在编译C/C++时,传递给编译器的标志集合。 | -fexceptions:由于NDK编译从R5开始才支持C++异常控制,为了通用性,异常处理默认是禁用的(-fno-exceptions),因此需要在指定module中添加LOCAL_CPPFLAGS += -fexceptions编译选项方可编译带异常处理的C++代码。也可以直接在Application.mk中配置APP_CPPFLAGS += -fexceptions。 -frtti:从NDK R5开始,NDK也开始支持C++ RTTI了,但为了通用性,所有的C++源文件被构建的时候默认是不支持RTTI的(-fno-rtti),可以通过在Android.mk中添加:LOCAL_CPPFLAGS += -frtti或者在Application.mk添加APP_CPPFLAGS += -frtti来开启RTTI。 -fvisibility=hidden:在NDK开发中,源文件的函数都有一个默认的visibility属性为public,编译生成的so文件中几乎所有的函数名、全局变量名均被导出,其实只需要导出java_com开头的jni函数即可,其他函数不需要暴露出来,在Android.mk中设置LOCAL_CFLAGS += -fvisibility=hidden,就可以隐藏不需要导出的函数,若某个函数需要导出,则添加JNIEXPORT或者__attribute__ ((visibility (“default”)))即可。 -ffunction-sections:不添加此参数时,编译文件.o中代码部分只有.text段,使用此参数,会使每个函数单独有一个段,举个栗子,函数func1()会编译成.text.func1段,虽然段多了,但对链接后代码大小并没有影响。 -fdata-sections:同上,每个data都有一个单独的段。 -Wl --gc-sections:-Wl,选项是告诉编译器,将后面选项传递给连接器,-Wl,–gc-sections的意思是使用连接器ld链接时删除不用的段。若使用LOCAL_CFLAGS += -ffunction-sections -fdata-sections,则代码和数据均被分割成不同的段,若某个函数或数据未被任何函数调用,则ld不会链接未被调用的函数,从而减小so文件体积,达到优化so的目的。 -fPIC:PIC(position independent code)用于编译位置无关代码,生成可用于共享库的位置独立代码。若不添加-fPIC,则加载.so文件的代码段时,代码段引用的数据对象需要重定位,重定位会修改代码段内容,这样就导致没使用这个.so,代码段的进程在内核中就会生成这个文件的拷贝。 -Wall: wring all 意思在编译和链接过程中显示所有警告信息。 |
LOCAL_CPPFLAGS += -fexceptions |
LOCAL_CPPFLAGS | 编译、链接标志,在编译C/C++时,传递给编译器的标志集合,只支持C++。 | 见上 | - |
LOCAL_LDFLAGS | 编译、链接标志,在编译C/C++时传递给连接器一些额外的参数。 | 见上 | - |
Appliction.mk则是用于配置编译生成物相关属性,是轻量级的Makefile,通常位于项目的jni目录下。一个典型的示例如下:
APP_ABI := armeabi arm64-v8a x86_64 x86 armeabi-v7a
NDK_TOOLCHAIN_VERSION := clang3.5
APP_STL := stlport_static
APP_OPTIM:= debug
配置项含义表:
配置项 | 功能 | 可选项 | 示例 |
---|---|---|---|
APP_ABI | 目标平台ABI类型,默认选择armeabi ABI,可通过设置APP_ABI设置一个或者多个ABI。对于ABI的选择需要考虑到效率和APK大小。由于armeabi-v7a指令集兼容armeabi;市面上的x86手机为了兼容性,基本都使用libhoudini模块,兼容arm指令集;64位机型默认支持32位abi的so,因此在对大小要求比较高的情况下,可以只选择市面上设备基本兼容的armeabi ABI,如果对性能有些许要求,可以再添加x86 ABI。 | - armeabi - arm64-v8a - x86_64 - x86 - armeabi-v7a - mips - mips64 - all(全部) |
- |
NDK_TOOLCHAIN_VERSION | 编译器类型、版本。默认采用的是GCC编译器,对于GCC版本的选择与NDK版本有关系,如NDK R12,在64位ABI默认是GCC 4.9,32位ABI默认是GCC 4.8,当然也可以像上面例子中给出的设置一样,设置clang编译器。 | - gcc4.9 -clang3.5 |
- |
APP_STL | 运行库类型。Android NDK 默认使用的是最小支持的C++运行库,如果你需要你的NDK程序中使用STL,则可以设置APP_STL := stlport_static,若APK中有多个SO文件用到STL,建议都使用动态方式链接STL,这样可以减小整个APK文件大小。另外需要注意的是官方提供的NDK运行库除了默认的以外都支持RTTI和异常,然而默认是禁用的,将在下面的Android.mk中说明如何开启。 | system(default)系统默认的C++运行库 stlport_static以静态链接方式使用的sttport版本的STL stlport_shared以动态链接方式使用的sttport版本的STL gnustl_static以静态链接方式使用的gnustl版本的STL gnustl_shared以动态链接方式使用的gnustl版本的STL gabi++_static以静态链接方式使用的gabi++ gabi++_shared以动态链接方式使用的gabi++ c++_static以静态链接方式使用的LLVM libc++ c++_shared以动态链接方式使用的LLVM libc++ |
|
APP_OPTIM | 编译模式。“release”模式为默认的,生成的是优化后的二进制;也可以设置为“debug”模式,“debug”模式生成的是未优化二进制,提供很多BUG信息,便于调试和分析。 | - release - debug |
参考资料:Application.mk官方文档
在AS项目根目录下执行ndk-build
开始生成so文件。
参考资料:ndk-build 脚本
文章浏览阅读488次。1,编写程序,判断给定的某个年份是否是闰年。 闰年的判断规则如下: (1)若某个年份能被4整除但不能被100整除,则是闰年。 (2)若某个年份能被400整除,则也是闰年。package text;import java.util.Scanner;public class Year { public static void ma_从键盘输入年份t如果年份t能被400整除或者能被四整除但不能被100整除则输入7
文章浏览阅读106次。BASE64编码算法不算是真正的加密算法。 MD5、SHA、HMAC这三种加密算法,可谓是非可逆加密,就是不可解密的加密方法,我们称之为单向加密算法。我们通常只把他们作为加密的基础。单纯的以上三种的加密并不可靠。 BASE64 按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The ..._base 64编码 和mad5 和雪花算法
文章浏览阅读1.1k次。IP地址(Internet Protocol Address)是互联网协议地址的简称,是互联网通信的基础,互联网上每一个网络设备的唯一标识符每个在线的设备都需要一个IP地址,这样才能在网络中找到它们并进行数据交换。IP地址有很多种类型,今天跟大家简单分享一下住宅IP、家庭宽带IP以及原生IP的区别。住宅IP通常是指由互联网服务提供商(ISP)分配给家庭的或小型办公室使用的互联网连接IP地址,并可能随着网络连接的变化而变化。此类IP地址主要用于日常网络活动,如浏览网页、发送接收电子邮件、上网冲浪等。
文章浏览阅读2.6w次,点赞14次,收藏30次。如何更改layui form表单位置,宽度,颜色等_layui-form-item 宽度
文章浏览阅读612次。写的非常好_pagraph: scaling gnn training on large graphs via computation-aware caching
文章浏览阅读2.7w次,点赞61次,收藏285次。很炫酷的html代码:<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>star</title><script type="text/javascript">window.onload = function () {C = Math.cos; // cache Math objectsS = Math.si.._炫酷的html
文章浏览阅读2.3k次。题目描述对数字,字符,数字串,字符串,以及数字与字符串组合进行倒序排列。字符范围:由 a 到 z, A 到 Z,数字范围:由 0 到 9符号的定义:“-”作为连接符使用时作为字符串的一部分,例如“20-years”作为一个整体字符串呈现;连续出现 2 个 “-” 及以上时视为字符串间隔符,如“out--standing”中的”–“视为间隔符,是 2 个独立整体字符串”out”和”standing”;除了 1,2 里面定义的字符以外其他的所有字符,都是非法字符,作为字符串的间隔符处理,倒序后
文章浏览阅读5w次,点赞36次,收藏138次。ArrayAdapter数组适配器用于绑定格式单一的数据,数据源可以是集合或者数组列表视图(ListView)以垂直的形式列出需要显示的列表项。实现过程:新建适配器->添加数据源到适配器->视图加载适配器第一种:直接用ListView组件创建列表每一行只有一行文字效果如图:activity_list布局:<?xml version="1.0" e..._arrayadapter
文章浏览阅读43次。近日,水滴直播平台登上了舆论的风口浪尖。有人认为水滴直播涉嫌侵犯隐私,但也有人表示这种互联网新生事物可以有效规避很多风险,值得鼓励,不应一棒子打死。记者采访时发现,很多商家、创业者对于水滴直播纷纷表示支持,并直言水滴直播为他们的经营带来了很大帮助。 邹志泉在北京丰台区经营着一家批发厂家直销男女内衣裤的店铺,平时就打开水滴直播,分享他在店铺的经营画面。面对水滴直播涉及隐私的提问,邹志泉明确表...
文章浏览阅读67次。springboot基于SpringBoot的电影社区网站。springboot基于springboot食品销售网站。ssm基于微信平台的校园汉服租赁系统的设计与实现。ssm基于SSM高校教师个人主页网站的设计与实现。ssm基于SSM框架的在线健康系统设计与实现。ssm基于HTML的武昌理工学院二手交易网站。ssm基于JavaEE的网上图书分享系统。ssm基于Javaee的项目任务跟踪系统。
文章浏览阅读61次。负载均衡是指将客户端的请求分发到多个后端服务器,以平衡服务器的负载。反向代理是指将客户端的请求转发到后端服务器,并将响应返回给客户端。通过配置反向代理,Nginx将转发所有来自客户端的请求到后端服务器,并将响应返回给客户端。通过这样的配置,Nginx将根据请求的URL路径选择是将请求转发到后端服务器还是直接返回静态资源文件。通过配置负载均衡,Nginx将按照指定的策略将客户端的请求分发到后端服务器上,从而实现负载均衡。配置反向代理:编辑Nginx配置文件(通常是nginx.conf),在。_php动静分离
文章浏览阅读9.5k次,点赞3次,收藏18次。(一) 语义标签(二)增强型表单(三)视频和音频(四)Canvas绘图(五)SVG绘图(六)地理定位(七)拖放API(八) WebWorker(九) WebStorage(十)Web..._谈谈html5的一些新特性