//2. 保存
source /etc/profile
//3. 测试
ndk-build -v
如果出现如下字样,就证明配置成功了。
- 交叉编译在 Linux 上的环境变量配置(做一个参考,采坑之后的环境配置):
export NDK_GCC_x86="/root/android/ndk/android-ndk-r17c/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux-android-gcc"
export NDK_GCC_x64="/root/android/ndk/android-ndk-r17c/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/x86_64-linux-android-
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
gcc"
export NDK_GCC_arm="/root/android/ndk/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc"
export NDK_GCC_arm_64="/root/android/ndk/android-ndk-r17c/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc"
export NDK_CFIG_x86="–sysroot=/root/android/ndk/android-ndk-r17c/platforms/android-21/arch-x86 -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include/i686-linux-android"
export NDK_CFIG_x64="–sysroot=/root/android/ndk/android-ndk-r17c/platforms/android-21/arch-x86_64 -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include/x86_64-linux-android"
export NDK_CFIG_arm="–sysroot=/root/android/ndk/android-ndk-r17c/platforms/android-21/arch-arm -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include/arm-linux-androideabi"
export NDK_CFIG_arm_64="–isysroot=/root/android/ndk/android-ndk-r17c/platforms/android-21/arch-arm64 -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include -isystem -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include/aarch64-linux-android"
export NDK_AR_x86="/root/android/ndk/android-ndk-r17c/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux-android-ar"
export NDK_AR_x64="/root/android/ndk/android-ndk-r17c/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar"
export NDK_AR_arm="/root/android/ndk/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ar"
export NDK_AR_arm_64="/root/android/ndk/android-ndk-r17c/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar"
你可以根据自己的 ndk 路径对应我的环境变量来进行配置。下面我们就用 ndk gcc 来对 test.c 进行交叉编译,步骤如下:
- 首先找到 /root/android/ndk/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc
执行如下命令:
/root/android/ndk/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc -o test test.c
-
这种错误是说在我们编得时候编译器找不到我们引入的 stdio.h 头文件,那怎么告诉编译器 stdio.h 头文件在哪里呢? 下面知识点说明怎么指定这些报错的头文件
-
指定头文件代码
/root/android/ndk/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc --sysroot=/root/android/ndk/android-ndk-r17c/platforms/android-21/arch-arm -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include -pie -o test test.c
上面出现了几个命令符号,不了解了可以看一下如下解释:
–sysroot=?: 使用 ?作为这一次编译的头文件与库文件的查找目录,查找下面的 usr/include 目录。
-isystem ?(主要中间有一个英文空格) : 使用头文件查找目录,覆盖 --sysroot, 查找 ?/usr/include 目录下面的头文件。
-isystem ?(主要中间有一个英文空格): ** 指定头文件的查找路径。
-I?: 头文件的查找目录,I 是大写。
这样编译之后还是会报一个 asm/types.h 文件找不到,我们还要继续修改一下路径,如下
/root/android/ndk/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc --sysroot=/root/android/ndk/android-ndk-r17c/platforms/android-21/arch-arm -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include -isystem /root/android/ndk/android-ndk-r17c/sysroot/usr/include/arm-linux-androideabi -pie -o test test.c
这样就能编译成一个 Android 平台可执行的文件了,这样看起来路径太多不易阅读,大家可以参考我提供的全局变量配置来进行设置,最后一行命令解决,如下:
$NDK_GCC_arm $NDK_CFIG_arm -pie -o test test.c 复制代码
可以看到,我们使用 Android NDK 编译出来的可执行文件已经在 Linux 平台下不可执行了。下面我们将 test 文件导入到 手机 /data/local/tmp 目录。
- 将 NDK 交叉编译出来的 test 可执行文件,导入 Android 手机中并执行 test 文件。
根据上面的录屏,我们知道已经成功的在 Android 设备下执行了 NDK 交叉编译后的 test 文件了。
下面我们利用 NDK 工具交叉编译 test.c 输出静态动态库。
动态库 & 静态库
编译静态库
- 将 test.c 使用 NDK GCC 编译为 .o 文件 ,命令如下:
$NDK_GCC_arm $NDK_CFIG_arm -fpic -c test.c -o test.o
如果出现如下文件,证明已经成功了。
- 使用 NDK arm-linux-androideabi-ar 工具将 test.o 文件生成 test.a 静态库,命令如下:
$NDK_AR_arm r test.a test.o
之后我们把 test.a 文件导入到 AS 中,来对 .a 的使用。
编译动态库
在编译动态库的时候我们需要指定 -fPIC -shared 额外参数给编译器,完整命令如下:
$NDK_GCC_arm $NDK_CFIG_arm -fpic -shared test.c -o libTest.so
动态库与静态库的区别
在平时工作中我们经常把一些常用的函数或者功能封装为一个个库供给别人使用,java开发我们可以封装为 ja r包提供给别人用,安卓平台后来可以打包成 aar 包,同样的,C/C++ 中我们封装的功能或者函数可以通过静态库或者动态库的方式提供给别人使用。
Linux 平台静态库以 .a 结尾,而动态库以 .so 结尾。
那静态库与动态库有什么区别呢?
1. 静态库
与静态库连接时,静态库中所有被使用的函数的机器码在编译的时候都被拷贝到最终的可执行文件中,并且会被添加到和它连接的每个程序中:
优点:运行起来会快一些,不用查找其余文件的函数库了。
缺点:导致最终生成的可执行代码量相对变多,运行时, 都会被加载到内存中. 又多消耗了内存空间。
2. 动态库
与动态库连接的可执行文件只包含需要的函数的引用表,而不是所有的函数代码,只有在程序执行时, 那些需要的函数代码才被拷贝到内存中。
优点:生成可执行文件比较小, 节省磁盘空间,一份动态库驻留在内存中被多个程序使用,也同时节约了内存。
缺点:由于运行时要去链接库会花费一定的时间,执行速度相对会慢一些。
静态库是时间换空间,动态库是空间换时间,二者均有好坏。
如果我们要修改函数库,使用动态库的程序只需要将动态库重新编译就可以了,而使用静态库的程序则需要将静态库重新编译好后,将程序再重新编译一遍。
mk & cmake
上一小节我们通过 NDK 交叉编译了 test.c 为动态静态库,那么该小节我们就基于 makefile 和 cmake 来构建一个 C/C++ 的 Android 程序, 并使用 test .a /libTest.so
mk
Android.mk 是在 Android 平台上构建一个 C 或者 C ++ 语言编写的程序系统的 Makefile 文件,不同的是, Android 提供了一些列内置变量来提供更加方便的构建语法规则。Application.mk 文件实际上是对应用程序本身进行描述的文件,它描述了应用程序要针对哪些 CPU 架构打包动态 so 包、要构建的是 release 包还是 debug 包以及一些编译和链接参数等。
语法基础
1. Android.mk
- LOCAL_PATH :=$(call my-dir)
返回当前文件在系统中路径,Android.mk 文件开始时必须定义该变量。
-
include $(CLEAR_VARS), 表明清楚上一次构建过程的所有全局变量,因为在一个 Makefile 编译脚本中,会使用大量的全局变量,使用这行脚本表明需要清除掉所有的全局变量。
-
LOCAL_SRC_FILES, 要编译的 C 或者 C