为什么要使用交叉编译:
在linux系统一般使用c c++编译可执行程序或者so库文件。该程序只能在当前linux系统执行,为了将生成文件可以再android平台运行,必须使用交叉编译。ndk中提供了跟多android平台交叉编译链,所以首先下载ndk工具。
ndk旧版本与新版本的编译链工具有改变,所以新版本与旧版本交叉编译的环境配置不同。
NDK 官网:https://developer.android.google.cn/ndk
编译环境:ubuntu linux系统
一、ndk旧版本交叉编译。以android-ndk-r17c版本为例。
下载旧版本地址(后面改成自己想要下载的版本)
https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip
https://developer.android.google.cn/ndk/downloads/older_releases?hl=zh-cn#ndk-17c-downloads
1、在lunux系统搭建环境
下载android-ndk-r17c-linux-x86_64.zip版本
使用unzip android-ndk-r17c-linux-x86_64.zip 对压缩文件解压。
2、编写程序
1、编写可执行文件
编写一个简单的.c文件testadd.c,对这个文件编译一个可执行文件:
#include
int main() {
int a = 2;
int b = 3;
int sum = a + b;
printf("a + b = %d\n",sum);
return 0;
}
3、编译
命令:gcc testadd.c -o testadd ,编译可执行文件testadd。
gcc :为 linux系统原生的编译环境;
testadd.c: 为待编译的源文件;
-o :表示输出;
testadd: 输出的可执行文件(名字随便取)
4、运行
在linux平台运行程序结果:
将该可执行程序放到android设备/system/app(注意 需要将android设备root处理,否则没有权限),不能运行,报错如下。
使用交叉编译链编译。
二、使用android-ndk-r18b交叉编译链进行编译,生成可执行文件。
1、查看设备信息,选择正确编译链。
我的设备cpu平台为arm64,android10 ,api29。所以使用的编译链为aarch64-linux-android-gcc,路径
…/ndk/android-ndk-r17c/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc
2、编译
// 定义GCC 编译链路径
export GCC_NDK_17=/home/lily/ffmpeg/ndk/android-ndk-r17c/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc
使用GCC_NDK_17编译链进行编译 ${GCC_NDK_17} testadd.c -o ndktestadd 报错,找不到头文件:
// 定义头文件及头文件所在库路径(我的设备是api29,但ndk17版本只有android-28,所以这里先使用android-28平台试一试)
库文件路径:/home/lily/ffmpeg/ndk/android-ndk-r17c/platforms/android-28/arch-arm64
头文件路径:/home/lily/ffmpeg/ndk/android-ndk-r17c/sysroot/usr/include
export FLAG_NDK_17=“–sysroot=/home/lily/ffmpeg/ndk/android-ndk-r17c/platforms/android-28/arch-arm64 -isystem /home/lily/ffmpeg/ndk/android-ndk-r17c/sysroot/usr/include”
再次编译:${GCC_NDK_17} ${FLAG_NDK_17} testadd.c -o ndktestadd 报错:
找不到ASM。
定义ASM路径:export ASM_NDK_17=/home/lily/ffmpeg/ndk/android-ndk-r17c/sysroot/usr/include/aarch64-linux-android
添加到FLAG:export FLAG_NDK_17=“–sysroot=/home/lily/ffmpeg/ndk/android-ndk-r17c/platforms/android-28/arch-arm64 -isystem /home/lily/ffmpeg/ndk/android-ndk-r17c/sysroot/usr/include -isystem ${ASM_NDK_17}”
再次编译:
${GCC_NDK_17} ${FLAG_NDK_17} testadd.c -o ndktestadd 生成可执行文件ndktestadd 。同样push到设备,是否能够执行。
修改编译命令,再次编译:
${GCC_NDK_17} ${FLAG_NDK_17} -pie testadd.c -o ndktestadd 可以生成可执行文件。同样push到设备,是否能够执行。
可以执行。交叉编译成功。
注意:本事例中使用ndk-19,ndk-20版本 没有对应gcc编译链,使用ndk-18版本,使用对应gcc编译链报错。因此,使用ndk-17版本验证。
以上命令使用的均为临时环境变量,下面将环境变量配置为全局环境变量。
打开文件:vi /home/lily/.bashrc(注意.bashrc为虚拟文件)在文件最下面添加一下路径:
#ndk-17
export NDK_17_ROOT="/home/lily/ffmpeg/ndk/android-ndk-r17c"
export NDK_17_HEAD="${NDK_17_ROOT}/sysroot/usr/include"
export NDK_17_ASM="${NDK_17_ROOT}/sysroot/usr/include/aarch64-linux-android"
export NDK_17_GCC_ARM64="${NDK_17_ROOT}/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc"
export NDK_17_SO_ARM64="${NDK_17_ROOT}/platforms/android-28/arch-arm64"
export NDK_17_FLAG_ARM64="--sysroot=${NDK_17_SO_ARM64} -isystem ${NDK_17_HEAD} -isystem ${NDK_17_ASM}"
编译:${NDK_17_GCC_ARM64} ${NDK_17_FLAG_ARM64} -pie testadd.c -o ndktestadd
三、ndk-17 编译动/静态库
// testadd.h
#include
int add();
// testadd.c
#include "testadd.h"
int add() {
int a = 2;
int b = 3;
int sum = a + b;
printf("a + b = %d\n",sum);
return sum;
}
使用交叉编译动态库:
${NDK_17_GCC_ARM64} ${NDK_17_FLAG_ARM64} -fPIC -shared testadd.c -o libadd.so
使用交叉编译静态库
1)生成.o文件
${NDK_17_GCC_ARM64} ${NDK_17_FLAG_ARM64} -fPIC -c testadd.c -o testadd.o
2)生成.a静态库
全局环境添加编译静态库编译链:
export NDK_17_AR_ARM64=“${NDK_17_ROOT}/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar”
编译生成libtestadd.a
$NDK_17_AR_ARM64 rcs -o libtestadd.a testadd.o
以上,使用ndk-17版本交叉编译生成可执行文件、动态库、静态库完成。
首先设置环境变量,vi /home/lily/.bashrc ,如下图
交叉编译生成动态库:
${NDK_25_GCC_ARM64} -fPIC -shared testadd.c -o libadd25arm64.so
交叉编译生成静态库:
${NDK_25_GCC_ARM64} -fPIC -c testadd.c -o libadd25arm64.a