前言:前两天总结了编译、交叉编译,其中交叉编译主要指的是嵌入式中交叉编译,这一篇重点来总结下andriod开发中的交叉编译,方便以后温故知新。
ubuntu:20版本
NDK:r17c和r21b
一、概念
NDK(Native Development Kit缩写)一种基于原生程序接口的软件开发工具包,可以让您在 Android 应用中利用 C 和 C++ 代码的工具。通过此工具开发的程序直接在本地运行,而不是虚拟机。
在Android中,NDK是一系列工具的集合,主要用于扩展Android SDK。NDK提供了一系列的工具可以帮助开发者快速的开发C或C++的动态库,并能自动将so和Java应用一起打包成apk。同时,NDK还集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so文件。
这就是NDK,功能很强大,笔者此篇博客主要记录下NDK交叉编译的功能。
1.1 基础概念
ARM :是嵌入式中的一种架构,全称为Advanced RISC Machine,能够理解为ARM处理器。
ABI(Application Binary Interface):应用程序二进制接口 描述了应用程序和操做系统之间,一个应用和它的库之间,或者应用的组成部分之间的低接口。
ABI和CPU关系:大部分cpu都支持多于一种的ABI。当一个应用安装在设备上,只有该设备支持的CPU架构对应的.so文件会被安装。
CPU架构\ABI | armeabi | armeabi-v7a | arm64-v8a | mips | mips64 | x86 | x86_64 |
ARMV5 | √ | ||||||
ARMV7 | √ | √ | |||||
ARMV8 | √ | √ | √ | ||||
MIPS | √ | ||||||
MIPS64 | √ | √ | |||||
x86 | √ | √ | √ | ||||
x86_64 | √ | √ | √ |
1.2 NDK中交叉编译工具
1.3 版本变迁
从NDK 16 开始,交叉编译器就不再支持GCC了,并会在18版本后移除掉
GCC被移除了,只有Clang了
NDK R19 独立工具链不需要了,意思是,不用自己去通过NDK提供的make_standalone_toolchain.sh脚本来生成我们想要的工具链,因为,你想要(可用)的NDK中都已经给你提供好了,如果没有你想要的,说明,你想的有点多了。
二、NDK交叉编译工具链
首先明确一点,NDK 已经为我们提供了交叉编译工具链(交叉编译工具见1.2小节),用来编译第三方 C/C++ 库到 Android 中使用,比如 FFmpeg、x264、RTMPDump 等等。
如何使用NDK工具,目前笔者查到资料主要有两种
- 下载好NDK后,通过指定工具链(NDK中提供的)路径完成。
- 使用NDK提供的make_standalone_toolchain.py脚本来生成我们想要的工具链。
通过NDK官方的版本变迁可以看到,NDK R19版本,独立工具链不需要了,意思是,不用自己去通过NDK提供的make_standalone_toolchain.sh脚本来生成我们想要的工具链。
2.1 独立工具链
如果还是希望自定义交叉编译工具可以使用NDK r19之前的版本,不建议使用r19之后的版本进行自定义交叉编译工具,除非你准备把编译后的动\静态库用于比较老的cpu架构中,现在比较新的cpu架构下使用ndk交叉编译后的文件还是建议使用较新的ndk版本。
生成独立工具链方法:
NDK 为我们提供了 make_standalone_toolchain.py 脚本来生成编译工具链。它的目录在 build/tools/ 下
使用是比较简单,但是作为小白的我,还是出现了几个问题,并不是命令的问题,而是对于linux的不熟导致的。
第一个问题:
komla@ubuntu:~/NDK$ /android-ndk-r17c/build/tools/make-standalone-toolchain.sh --toolchain=arm-linux-androideabi-4.9 --platform=android-21 --install-dir=my_ndk_toolchain
bash: /android-ndk-r17c/build/tools/make-standalone-toolchain.sh: No such file or directory
看哈,没有这个文件夹,就是路径格式不会写。我在NDK这个文件夹下面打开的命令台,然后/android-ndk-r17c/...,这样是找不到android-ndk-r17c这个文件夹的,需要在最前面加一个"."
"./android-ndk-r17c/...",这样才能找到这个文件夹。
第二个问题:
我是事先创建了一个my_ndk_toolchain文件夹,用于存放生成的交叉编译工具链,
然后执行下面命令
komla@ubuntu:~/NDK$ ./android-ndk-r17c/build/tools/make-standalone-toolchain.sh --toolchain=arm-linux-androideabi-4.9 --platform=android-21 --install-dir=my_ndk_toolchain
输出结果如下,意思就是,这个交叉编译工具链(其实就是这个文件夹,只是我起的名字有误解,应该按照命名规范去起名)已经已经存在了,没法重新安装,除非使用 --force才行。
HOST_OS=linux
HOST_EXE=
HOST_ARCH=x86_64
HOST_TAG=linux-x86_64
HOST_NUM_CPUS=2
BUILD_NUM_CPUS=4
Auto-config: --arch=arm
Refusing to clobber existing install directory: my_ndk_toolchain.
make-standalone-toolchain.sh used to install a new toolchain into an existing
directory. This is not desirable, as it will not clean up any stale files. If
you wish to remove the install directory before creation, pass --force.
接着改,执行成功了,所以,要么事先创建文件夹,要么就在命令最后加上 --force,建议后者,因为可能会修改命令内容重新生成独立交叉编译工具,这样就避免了反复手动创建文件夹了。
komla@ubuntu:~/NDK$ ./android-ndk-r17c/build/tools/make-standalone-toolchain.sh --toolchain=arm-linux-androideabi-4.9 --platform=android-21 --install-dir=my_ndk_toolchain --force
HOST_OS=linux
HOST_EXE=
HOST_ARCH=x86_64
HOST_TAG=linux-x86_64
HOST_NUM_CPUS=2
BUILD_NUM_CPUS=4
Auto-config: --arch=arm
Toolchain installed to my_ndk_toolchain.
可以看到已经为我们生成了 arm-linux-androideabi, 在 sysroot 下包含了系统提供的库以及头文件。在 bin 目录下包含了交叉编译工具,比如 clang、gcc、ar、as、nm、strip 等等。主要做的工作就是将原先在 ndk 目录下的各目录结构归纳到一个目录。
第三个问题:
不知道出现这个问题的原因是我第一个问题中路径没设置好导致的,还是真的因为没有安装python导致的,这个问题其实是最先出现的,所以我就按这篇博客的建议安装了python,然后下面的问题解决后也没出现这个问题了。
说明:
1、网上有很多文章的命令是这样的
$NDK/build/tools/make_standalone_toolchain.py ...
他这里的$NDK 是 NDK 的安装根目录。这应该是把下载的NDK配置到环境中了,所以这里的路径要根据自己解压后的NDK路径进行写。
2、命令简析
./android-ndk-r17c/build/tools/make-standalone-toolchain.sh 执行下载的NDK目录下make-standalone-toolchain.sh脚本;
--toolchain=arm-linux-androideabi-4.9 指独立出来的工具链哪种用途的编译,arm(arm-linux-androideabi-4.8),X86(x86-4.8)或MIPS(mipsel-linux-android-4.8),可cd toolchains中查看并选择适合的类型,我这里使用的是嵌入式;
--platform=android-21 指工具链将使用哪个版本的Android API,可cd android-ndk-r7c/platform中查看,我这里使用的是Android-21;
--install-dir=my_ndk_toolchain 生成的编译工具链安装目录;
--force:强制清空安装目录
其实还有一些命令没用到,使用了默认的值,比如
--arch=arm(默认是arm)
2.2 官方交叉编译工具
在 NDK 19 开始就不需要使用独立工具链了, 在 toolchains/llvm/ 下已经提供好了编译工具, 读者自行去下载进入目录看看,和独立工具链编译出来的结构非常类似,不过它比较全的是针对不同平台版本。
可以看到,llvm和其他工具链位于同一级目录,所以作用是一样的。
基本上能满足开发者使用。
三、使用
3.1 ndk环境配置
环境配置挺简单,但依然配置了小半天,原因还是这个路径问题,哎,有时间得好好整整这个linux的路径问题。
使用命令:
- sudo gedit /etc/profile
- sudo gedit ~/.bashrc
- 上面两个命令都可以,都是通过gedit进行编辑,只是一个编辑的是/etc/profile,另一个是.bashrc,根据自己的习惯选择其中一个就可以
上面命令执行完,不出意外就会跳出来一个可编辑的文档,然后根据网上提供的信息,加上对应信息,点击保存,然后叉掉就可以。
保存,叉掉后回到控制台,然后输入
1、source /etc/profile 你如果打开时候使用sudo gedit /etc/profile 命令就用这个,
2、source ~/.bashrc 你如果打开时候使用sudo gedit ~/.bashrc 命令就用这个,
3、说白了,就是你打开的哪个文件,就在这里soruce 哪个文件
正常,上面配置完就配置好了环境了,下面就验证了,
ndk-build -v
哎,找了好多资料都没找到原因,后来发现,在打开的文档中添加路径时候错了,ndk的路径应该是下面的这个,多一个komla级
/home/komla/NDK/android-ndk-r21b
可是我通过目录看就是不带komla啊
可是通过pwd命令看,确实是,就这个命令,哎有时间好好看看linux命令
既然,问题原因找到了,下面改下
3.2 使用
说明下,按照官网的去敲命令即可,只是要注意几点
- "\"这是个换行符,可有可不有;
- "$NDK",其中"$"是linux系统下的标识符,"NDK"是前面配置的环境变量名称,$和NDK是一起使用的,代表取环境变量中NDK代表的东西
- 因为不同人不同需求,所以在下载ndk的时候有些是下载的window版本的,有些是linux的,有些是mac下的,所以这里官网没有写哪个,而是用HOST_TAG代表了,可根据自己的实际情况改下。
我两种方式都试了下,都可以生成,只是生成的位置,默认是主目录下,然后是一个a.out的二进制文件,并不是我想象中的.so或者.a文件,这里应该是我没有设置成输出.so或.a文件,希望懂得大佬给点建议。
踩坑:
这里有个疑惑,我从bin目录下打开终端,然后执行clang的命令,提示我找不到这个命令,按理说,就是指定clang的路径啊,但是找不到,不知道什么原因,希望懂的大佬指点迷津。
三、引用文献:
1、关于Android arm64-v8a、armeabi-v7a、armeabi、x86等CPU下的so文件兼容问题_晚安08的博客-CSDN博客_arm64-v8a
2、关于Android arm64-v8a、armeabi-v7a、armeabi、x86等CPU下的so文件兼容问题_晚安08的博客-CSDN博客_arm64-v8a
4、交叉编译-如何编译Android平台的可执行程序 - 简书
5、Android 编译 ffmpeg-4.2.2 + libx264 (NDK17以后使用的是Clang)_张雨zy的博客-CSDN博客6、NDK r21编译FFmpeg 4.2.2+x264及使用ffmpeg转换视频文件_来来走走的博客-CSDN博客
7、android交叉编译工具链,NDK 交叉编译工具链使用_神秘墓后煮shi者的博客-CSDN博客
8、独立工具链(已弃用) | Android NDK | Android Developers
11、NDK Clang 编译 FFmpeg 4.4.1 + fdk-aac 2.0.2 + x264 20191217_TYYJ-洪伟的博客-CSDN博客_ndk编译器
12、ubuntu-20.04.4环境下ndk-r21e 编译libiconv_awa2004的博客-CSDN博客_ubuntu 安装libiconv