gcc -S test.i -o test.s//-S 的作用是编译结束生成汇编文件。
- 汇编阶段
汇编阶段把 .S 文件翻译成二进制机器指令文件 .o ,这个阶段接收.c ,.i ,.s 的文件都没有问题。
下面我们通过以下命令生成二进制机器指令文件 .o 文件:
gcc -c test.s -o test.o
- 链接阶段
链接阶段,链接的是函数库。可以通过以下命令实现:
gcc -C test.o -o test
./test
最后我们通过实际操作,对编译有了一定的了解,当然你也可以直接通过如下命令一步到位:
gcc test.c -o test
到这里我们成功的在 linux 平台生成了可执行文件,试想一下我们可以将这个可执行文件拷贝到安卓手机上执行吗?我们也不猜想了,实际测试下就行,我们把 test 可执行文件 push 到手机 /data/local/tmp 里面, 如下所示:
可以看到 test 在手机 /data/local/tmp 的路径下是有可读可写可执行的权限,但是最后执行不成功,这是为什么呢? 其实 主要原因是两个平台的 CPU 指令集不一样,根本就无法识别指令。那么怎么解决这个问题呢? 下面就要用到今天一个比较重要的知识点了, 利用 Android NDK 工具包来对 C/C++ 代码进行交叉编译 。
交叉编译
简单地来说,交叉编译就是程序的编译环境和实际运行环境不一致,即在一个平台上生成另一个平台上的可执行代码。
在音视频开发中了解交叉编译是很有必要的,因为无论在哪一种移动平台下开发,第三方库都是需要进行交叉编译的。下面我们就以之前的例子来讲解如何在 linux 环境下交叉编译出移动平台上的可执行代码。
了解 NDK
Android 原生开发包 (NDK) 可用于 Android 平台上的 C++ 开发,NDK 不仅仅是一个单一功能的工具,还是一个包含了 API 、交叉编译器、调试器、构建工具等得综合工具集。
下面大致列举了一下经常会用到的组件。
- ARM 交叉编译器
- 构建工具
- Java 原生接口头文件
- C 库
- Math 库
- 最小的 C++ 库
- ZLib 压缩库
- POSIX 线程
- Android 日志库
- Android 原生应用 API
- OpenGL ES 库
- OpenSL ES 库
下面来看一下 Android 所提供的 NDK 跟目录下的结构。
- ndk-build: 该 Shell 脚本是 Android NDK 构建系统的起始点,一般在项目中仅仅执行这一个命令就可以编译出对应的动态链接库了。
- ndk-gdb: 该 Shell 脚本允许用 GUN 调试器调试 Native 代码,并且可以配置到 AS 中,可以做到像调试 Java 代码一样调试 Native 代码。
- ndk-stack: 该 Shell 脚本可以帮组分析 Native 代码崩溃时的堆栈信息。
- build: 该目录包含 NDK 构建系统的所有模块。
- platforms: 该目录包含支持不同 Android 目标版本的头文件和库文件, NDK 构建系统会根据具体的配置来引用指定平台下的头文件和库文件。
- toolchains: 该目录包含目前 NDK 所支持的不同平台下的交叉编译器 - ARM 、X86、MIPS ,目前比较常用的是 ARM 。构建系统会根据具体的配置选择不同的交叉编译器。
下面我们就来为交叉编译的环境变量配置
环境变量配置
- ndk 在 Linux 上的环境变量配置:
//1. vim /etc/profile
#NDK环境变量
export NDK_HOME=/root/android/ndk/android-ndk-r17c
export PATH= P A T H : PATH: PATH:NDK_HOME
//2. 保存