10. OpenWrt根文件系统的构建

10.1. OpenWrt简介

openwrtlogo

OpenWrt/LEDE是一个为嵌入式设备(通常是无线路由器)开发的高扩展度的GNU/Linux发行版。 与许多其他路由器的发行版不同,OpenWrt是一个完全为嵌入式设备构建的功能全面、 易于修改的由现代Linux内核驱动的操作系统。 在实践中,这意味着您可以得到您需要的所有功能,却仍能避免臃肿。

OpenWrt不是一个单一且不可更改的固件,而是提供了具有软件包管理功能的完全可写的文件系统,让您通过使用适配任何应用的软件包来定制设备。

OpenWrt SDK 更简化了开发软件的工序。OpenWRT不同于其他许多用于路由器的发行版,它是一个从零开始编写的、 功能齐全的、容易修改的路由器操作系统。实际上,这意味着您能够使用您想要的功能而不加进其他的累赘, 而支持这些功能工作的linux kernel又远比绝大多数发行版来得新。

对于开发人员来说,OpenWrt是一个无需围绕它构建完整固件就能开发应用程序的框架; 对于普通用户来说,这意味着拥有了完全定制的能力,能以意想不到的方式使用该设备。

OpenWrt官方网站:https://openwrt.org

OpenWrt官方Git仓库:https://github.com/openwrt/openwrt

我们使用基于官方openwrt-19.07长期支持版本源码,并由野火基于EBF6ULL平台进行定制的版本来制作OpenWrt文件系统。

下载地址:http://gitlab.ebf.local/openwrt/gateway/gateway_openwrt_imx6ull.git

10.2. 下载安装编译镜像系统(如果没有编译环境)

使用平台:Ubuntu 18.04 LTS 版本

可以使用我们提供的虚拟机镜像 https://doc.embedfire.com/products/link/zh/latest/linux/ebf_i.mx6ull.html#id4

也可以自己下载ubuntu 18.04 LTS官方镜像搭建 https://mirrors.aliyun.com/ubuntu-releases/bionic

10.3. 安装编译工具和依赖

编译OpenWrt之前需要安装必要的环境工具。

1
2
3
sudo apt install -y subversion g++ zlib1g-dev build-essential git
sudo apt install -y libncurses5-dev gawk gettext unzip file libssl-dev
sudo apt install -y python rsync man-db wget zip time aria2

10.4. 获取野火OpenWrt源码

通常一个内核仓库往往维护着不同分支的内核源码,进入仓库目录下可通过命令查看及切换内核分支

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#克隆野火OpenWrt源码
git clone http://gitlab.ebf.local/openwrt/gateway/gateway_openwrt_imx6ull.git

#查看uboot分支
git branch -a

#打印消息如下
* openwrt-19.07
  remotes/origin/HEAD -> origin/openwrt-19.07
  remotes/origin/openwrt-19.07


#切换openwrt-19.07分支
git checkout openwrt-19.07

#打印消息如下
已经位于 'openwrt-19.07'
您的分支与上游分支 'origin/openwrt-19.07' 一致。

#重新查看当前分支
git branch

#打印消息如下,成功切换分支到 openwrt-19.07
* openwrt-19.07

也可以在下载时指定分支,如下所示

1
git clone -b openwrt-19.07 http://gitlab.ebf.local/openwrt/gateway/gateway_openwrt_imx6ull.git

10.5. OpenWrt工程结构分析

OpenWrt内核源码目录如下

1
2
3
4
5
bin          dl                  key-build.pub           make_fire.sh  staging_dir
BSDmakefile  feeds               key-build.ucert         package       target
build_dir    feeds.conf.default  key-build.ucert.revoke  README        tmp
config       include             LICENSE                 rules.mk      toolchain
Config.in    key-build           Makefile                scripts       tools

我们简单分析一下部分目录的作用

  • bin :编译最终生成的ipk软件包和使用打包脚本生成的最终文件,如压缩打包好的根文件系统和设备树、内核等。

  • dl : 编译前下载的软件包源码(此过程对网络条件有要求,须访问国外软件服务器)。

  • staging_dir : 保存工具、内核、工具链等所有代码的编译结果。

  • feeds :第三方软件包索引存放的位置。

  • package :官方软件包索引存放的位置。

  • target :主要是和平台有关的代码,最主要的是linux文件夹。

  • build_dir :用来解压所有的源代码和编译它们的位置。

  • include :顶层通用Makefile,其他Makefile中包含的Makefile都可以在其中找到。

  • toolchain :交叉编译工具链相关。

  • scripts :脚本工具,包括一些用shell,perl,python编写的通用工具。

  • tools :编译使用到的工具集。

除了上述目录外,还有一些文件值得我们关注

  • .config :OpenWrt的配置文件

  • feeds.conf.default :feeds包的远程地址

  • make_fire.sh :野火构建脚本,可用于挖完成编译前的准备工作

10.6. OpenWrt编译前的准备工作

在编译OpenWrt源码前,我们还要进行一些准备工作,以满足编译的要求。

10.6.1. 更新升级软件包

从git拉取软件包索引仓库到本地,并更新本地软件包列表。相关内容存放在feeds目录。

1
2
3
#更新升级软件包列表
./scripts/feeds update -a
./scripts/feeds install -a

10.6.2. 修改OpenWrt配置文件

我们需要运行以下命令来选在硬件平台和需要的软件包。

10.6.2.2. 配置说明

Target System : 选择NXP i.MX 6

Subtarget:选择NXP i.MX 6 with Cortex-A7

Target Profile:根据型号选择,编译nand版本则选择 Embedfire 6ULL NAND

Target Images:配置生成镜像打包时的相关参数,rootfs和kernel的分区大小可以在这里配置。

选择完成后,退出并保存。

警告

由于没有在OpenWrt自带内核中添加野火EBF6ULL开发板,直接选择 Embedfire 6ULL NAND 会导致编译失败。 如果想要编译野火定制镜像,请查看野火定制镜像构建章节。如想体验原生OpenWrt编译过程,请选择非野火硬件进行编译。

如果要保存当前的配置文件,可以运行以下脚本。配置文件的保存名称和保存路径可以任意修改。 下面的脚本将配置文件保存在OpenWrt根目录下,名称为defconfig

1
2
#保存配置文件
./scripts/diffconfig.sh > defconfig

如果要将保存的配置文件应用到编译中,可以使用下面的命令。

1
2
3
#应用保存的配置文件
cat defconfig > .config
make defconfig

10.6.3. 下载软件包源码

由于大部分软件包的源码托管服务器都在国外,请使用适当方法加速访问,否则会导致软件包下载缓慢或下载失败。

当网络情况良好时,我们可以使用-j选项来进行多线程下载,n为同时下载的线程数,建议不要太大,n小于4。 如果不想多线程下载,着忽略-j选项。

1
2
#下载软件包源码
make download -jn

10.7. 编译OpenWrt

1
2
#下载软件包源码
make V=s -jn

使用make命令进行源码的编译。参数V表示输出log的等级,V=s为输出所有的信息,等同于V=99,V=0为不输出,不使用V参数时默认为0。 -j表示同时进行指定数量的任务进行编译,也就是指定编译的线程数,n为线程数大小,不指定-jn参数时自动判断编译所需的线程数。

由于OpenWrt部分软件包不支持多线程编译,当我们指定n大于1时,会有极大的可能导致编译失败, 所以推荐大家使用 make V=s命令来减少不必要的麻烦。

由于我们在实际的开发过程中使用服务器进行编译,服务器具有核心多但单核频率低的特点, 如果仅使用单线程编译,效率甚至不如普通PC。所以,我们往往会先进行多线程编译, 直到工程编译失败,再使用单线程编译,具体过程如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#首先进行多线程编译
make V=s -j56

#遇到编译错误,尝试单线程编译
make V=s -j1

#如果单线程编译不通过,检查详细报错信息并解决错误

#单线程编译报错软件包通过之后,Ctrl+C打断编译,继续使用多线程编译
make V=s -j56

#重复上述过程,直到编译完成

注解

以上开发编译流程可以有效提高开发效率,减少编译源码占用的时间。

10.8. 编译完成

经过一段时间的编译(具体时间与编译服务器性能相关),我们就得到了编译好的OpenWrt根文件系统,在此过程中还顺便完成了kernel、设备树、Uboot的编译。

编译产生的最终文件,存放在 bin/targets/ 目录下,并根据处理器型号架构进行分类。

10.9. 总结

以上就是一个典型的OpenWrt编译流程,借助于OpenWrt SDK的完善,整个过程近似于一键编译。

但是由于我们要定制很多的功能,就需要将更改的配置保存下来,并根据实际情况替换内核和Uboot。

有关野火定制固件的构建将在后面章节详细说明。