Created: September 2, 2021
作者: 秋水君
前言
怎么编写能在Android系统中运行的C/C++可执行程序,一般有一下两种方法:
1. 通过谷歌提供的JNI机制
2. 交叉编译(本文选用方式)
安卓一般搭载在ARM架构下,其文件格式与常规X86架构的电脑端有所不同,电脑端可运行的可执行文件无法在安卓端直接运行,这就需要进行交叉编译,将代码编译为ARM环境下能够运行的程序。交叉编译有更大的自由度,可以使用NDK里提供的交叉编译工具,例如 android-ndk-r13b中就有交叉编译器 arm-linux-androideabi-gcc。
注:作者编程环境为 X86-64架构下的Ubuntu系统
xml库
可选的库有libxml2等,我这里选用 mxml 。原因在于1.纯C语言开发,更小巧便捷 2. 其依赖的库更少,之后交叉编译更容易。具体过程如下:
1. 从[GitHub](https://github.com/michaelrsweet/mxml/releases)获取压缩包 mxml-3.2.tar.gz
注意mxml也要经过交叉编译,正常gcc编译的mxml库在主程序交叉编译时无法直接链接到主程序。
1. 下载后解压,运行 /.configure ,设定编译器选项 CC=arm-linux-androideabi-gcc 及 编译输出路径 —–prefix=XXX
2. 运行命令 ./configure 得到Makefile。修改Makefile将 LIBS = -lpthread 改为 LIBS += -pthread (原因见下文常见问题)
3. 运行 make。
运行后可能报错,依据报错对应再次修改Makefile(与testsml相关的部分不会影响最终生成的lib,可以删除或者手动建立空白文件)
4. 在指定路径得到交叉编译的libmxml和mxml.h头文件
交叉编译主程序
我们用gcc编译程序时,可能会用到“-I”(大写i),“-L”(大写l),“-l”(小写l)等参数,下面做个记录:
举例:gcc -o example1 example1.c -I /usr/local/include/freetype2 -L/usr/local/lib -lfreetype -lm
上面这句话在编译example1.c 时,-I /usr/local/include/freetype2 将/usr/local/include/freetype2作为第一个寻找**头文件的目录,**参数-L是对应链接库地址。-lfreetype ,l (小写的l)参数就是用来指定程序要链接的库,l参数紧接着就是库名。指定程序链接的库名是freetype.
本文的编译示例:
arm-linux-androideabi-gcc test.c -I/home/exchange/android-ndk-r13b/my-toolchain/mxml/include -L/home/exchange/android-ndk-r13b/my-toolchain/mxml/lib -static -lmxml -o testand
注:使用C++的主程序将gcc部分换为g++即可
常见问题
1. 安卓环境下 lpthread 已经集成到核心库,libc,bionic提供了对pthreads的内置支持。所以对**交叉编译找不到 lpthread 库**的情况,将Makefile对应位置链接库对应位置改为 += -pthread
2. 交叉编译链接阶段经常找不到特定的头文件或者链接库,通过以下命令可以查看交叉编译器默认的头文件地址和链接库地址
echo 'main(){}' | /home/exchange/android-ndk-r13b/my-toolchain/bin/arm-linux-androideabi-gcc -E -v -