共计 5868 个字符,预计需要花费 15 分钟才能阅读完成。
最后更新:2022/04/02
最后校对:2022/04/02
本教程分为二个部分:编译教程与问题解决 和 特殊设备问题解决。
编译教程与问题解决:序号 一 *** 至 *** 四 。特殊设备问题解决:序号 五 *** 至 * ** 后。(OpenWrt 的一些功能实现会在教程的最后面)
目录
@[toc]
基础知识
+=+
本节名词解释:
SDK —— 英文 Software Development Kit 的缩写,翻译:“软件开发套件”。
ImageBuilder —— 翻译:映像构建器。
Github —— 国际著名的开源代码托管平台,国内可能无法直接访问。
+=+
对于教程中任何出现方括号(“【】”)的内容,请将其(包括方括号)替换为方括号内文本表示的 实际内容。
如:请将“【Linux 内核版本】”替换为“5.10.4”
源码、SDK、ImageBuilder
如果你想 定制 OpenWrt,最好的方法是 直接从 OpenWrt 放在 Github 上的源码开始修改和编译。
如果你想 定制 / 编译 opkg 的软件包 (*.ipk) 或定制 OpenWrt,最好的方法是 直接从 OpenWrt 官方和各大镜像 (如清华 Tuna 镜像源) 上的 SDK 开始修改和编译。
如果你想 简单打包 OpenWrt(给 OpenWrt 封装第三方 opkg),最好的方法是 直接从 OpenWrt 官方和各大镜像 (如清华 Tuna 镜像源) 上的 ImageBuilder 开始修改和编译。
复杂度和可定制度从上往下递减。
总的来说,OpenWrt 的源码、SDK、ImageBuilder 是面向不同人、不同需求所准备的。
编译 OpenWrt 的源码也可以生成 SDK 和 ImageBuilder(需要手动选择)。
Patch 文件(补丁文件)
位置:补丁文件通常位于源码目录“target/linux/【架构】/patches-【Linux 内核版本】/”目录下,这个 目录的名字不是固定的(请勿直接复制粘贴)。
名称:“000-XXXXXX.patch”,开头的数字(如:“000”)表示这个补丁文件的序号,也对补丁文件的应用顺序做了定义。短横线(“-”)后的英文字符串为对这个补丁文件的说明。
例如:322-mt7621-fix-cpu-clk-add-clkdev.patch
需要注意:补丁文件开头的数字不能与现有补丁文件开头的数字重复!补丁文件的说明可以自定义。
语法
- 头
“头”用来表示需要修补的文件,以 +++
和---
两行开头,另一个“头”的开始结束,用来表示旧文件和新文件。
例如:
--- a/arch/mips/ralink/mt7621.c
+++ b/arch/mips/ralink/mt7621.c
“头”后面的块均用来修补“头”中指定的文件。
- 块
“块”用来表示需要修补的内容,以 @@
开头,另一个“块”的开头或另一个“头”的开头结束。
例如:
@@ -105,11 +110,94 @@ static struct rt2880_pmx_group mt7621_pi
“块”的开头第一行可以称为“‘块’的起始行”,“块”的起始行中,两个“@@”(不是两个“@”)中间的内容指定这一块的内容应该修补原文件的哪里、多少行,修改的内容是什么。
在这个示例中,这一块表示:从原文件的第 105 行开始,删除 11 行,从第 110 行开始,添加 94 行。
逗号前的数字前面的符号用于表示增加行(+
)还是删除行(-
),不写符号则表示仅引用(用于“定位”)。
要修改的内容从“块”的起始行已经开始了 ,第二个“@@”后面写的内容即为 要改为的内容 的第一行。
增加行的内容的语法取决于被修补文件,例如对于修补上述“头”中指定的需要修补的文件而言(mt7621.c
),添加行的内容的语法为 C 语言的语法。
准备工作
+=+
本节名词解释:
Linux —— 类 Unix 的开源操作系统(常用于通称基于其的系统)。
Windows —— 由微软开发的闭源操作系统的名称。
Ubuntu —— 一个 Linux 系统的名称。
Fedora —— 一个 Linux 系统的名称。
WSL —— 英文 Windows Subsystem for Linux 的缩写,翻译:“适用于 Windows 的 Linux 子系统”。
VMware —— 集成了虚拟机环境的软件的名称。
+=+
本人的编译环境:
CPU:Intel Core i5-10400
GPU:NVIDIA GeForce GTX650 (Patched for UEFI)
RAM:DDR4 16GB 2733MHz
硬盘(系统):SSD 120GB
网络:中国联通 300Mbps GPON
主系统:Windows 11 22H2 PREVIEW
子系统:Ubuntu 20.04 LTS
子系统环境:> 环境变量(PATH):/home/levi/openwrt/staging_dir/host/bin:/home/levi/openwrt/staging_dir/toolchain-mipsel_24kc_gcc-11.2.0_musl/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
编译目标:OpenWrt 22.03 (git branch)
> MediaTek Ralink MIPS
> MT7621 based boards
> Xiaomi Mi Router 3G
安装依赖
官方和我均推荐使用 Ubuntu 系统进行编译,不论是虚拟机(WSL/VMware/ 其他)还是实体机。我尝试使用 Fedora 35(WSL)进行编译的时候尽管已经安装好各种依赖,但总有一些玄学问题。最后编译成功是在 Ubuntu 20.04 LTS(WSL)系统上。
Ubuntu 推荐执行这个命令(两条都要执行):
(来自 OpenWrt 官网)
sudo apt update
sudo apt install build-essential ccache ecj fastjar file g++ gawk \
gettext git java-propose-classpath libelf-dev libncurses5-dev \
libncursesw5-dev libssl-dev python python2.7-dev python3 unzip wget \
python3-distutils python3-setuptools python3-dev rsync subversion \
swig time xsltproc zlib1g-dev
编译前准备
- 用户账户:
确认当前用户不是“root”用户,如果是,则新建并切换为普通用户(建议在安装系统时就创建,后期创建的普通用户可能会有权限问题),随后设置默认用户为普通用户。 - 环境变量:
对于 WSL,官方推荐使用下面的环境变量(因为 WSL 子系统的 $PATH 会包含部分 Windows 目录,而这些目录带有空格,可能导致编译失败):
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
并且推荐在这个环境变量的基础上添加 OpenWrt 编译工具链的变量(OpenWrt 编译工具链在编译之前不存在,但是开始编译后会自动生成,因此可以在编译前添加入系统环境变量):
PATH=~/【OpenWrt 源码目录】/staging_dir/host/bin:~/【OpenWrt 源码目录】/staging_dir/toolchain-mipsel_24kc_gcc-【GCC 版本】_musl/bin:$PATH
- 网络环境:
确保可以正常访问 OpenWrt 源码的 Github 仓库。
确保可以正常访问部分软件包源码的下载仓库 / 地址。 - 源码:
首先下载 OpenWrt 的源码(克隆仓库到本地):
git clone https://github.com/openwrt/openwrt.git
执行命令修改目录权限,防止权限问题造成编译失败:
chmod -R 777 OpenWrt
chmod -R +x OpenWrt
进入源码目录,首先要做的事情是切换分支到你想要的 OpenWrt 版本,如果没有你想要的版本,请从别处下载你想要的版本的 OpenWrt 源码,如果你想使用最新的版本,可以不切换分支,直接使用 master
分支的代码(但这样做可能导致你的固件包含许多 BUG)。
例如:强制切换到 OpenWrt 22.03 版本的分支。
git checkout openwrt-22.03 --force
切换分支完毕后,修改 feeds.conf.default
文件,添加你想要的 feeds 源后,保存。
使用命令更新并安装 feeds:
./script/feeds update -a
./script/feeds install -a
开始编译
配置 OpenWrt 的特性、功能、软件包等
例如:固件需要用在什么 架构 的什么 芯片 的什么 型号 的设备上。
比如我的就是:固件是为 MediaTek MIPS 架构的 MT7621 的芯片的 小米路由 3G设备定制的。
使用命令:
make menuconfig
随后你的终端会变成一个使用键盘操作的 GUI 界面,如果终端大小过小则无法显示 GUI 界面并进行配置!
根据每一个选项的字面意思(不懂英文的自行翻译)来进行配置。
大多数的功能和配置都会占用硬盘空间,因此如果添加过多的功能和软件包则会造成固件大小和实际安装后的大小过大!
对于部分双分区的设备而言,由于其固件可能主要使用第二个分区作为系统分区,第一个分区过小,因此无法安装过大的 initramfs 映像,从而无法
下载源码
根据你上一步的配置,下载编译需要的源码(包括软件包),这步操作将减少编译时因下载错误造成的编译失败并且节省编译时间。
使用命令:
make download -j【CPU 线程数】V=s
请根据自己电脑的 CPU 来设置,例如本人的这条命令为:
make download -j12 V=s
由于网络环境影响,有时会下载失败或卡住,这时可以通过“Ctrl + C”快捷键终止操作,执行下面的命令后再次执行上面的命令下载。小技巧:有时候无法通过“curl”工具下载特定文件或者自动下载的文件地址不正确 / 失效导致一直下载失败,这时可以直接利用搜索引擎搜索需要下载的文件名下载到电脑后放到位于 OpenWrt 源码目录内 dl/
目录下,并且执行下面的命令后继续执行上面的命令直到完全正常(无报错)。
rm -rf tmp/
推荐多执行几次,确保所需软件包的源码下载正确、完整。
编译
官方推荐使用单线程编译(make -j1 V=s
),这样会让错误显示在最底部(不同线程执行命令的顺序不同,因此错误信息返回的时间也不同,有可能导致错误信息被其他线程的正确信息推到终端后面)
开始前的建议:检查位于 OpenWrt 源码目录内 dl/
目录下下载的源文件(文件大小、哈希值等),通常文件大小小于 1M 的源码文件是下载错误的,建议重新下载。(例如:php 8.1.3
为 11.7M,Linux 显示为 12M)
我个人推荐:
使用全线程编译,当遇到错误终止后再次多线程编译(可能解决玄学问题,但我没遇到),同一问题没有消失查看错误:有明显报错信息的,根据报错信息解决。没有明显报错信息的,换单线程编译查看错误(make -j1 V=sc
)。
目前我遇到的错误:
- 修改修补文件后,内核无法编译成功。原因:修补文件“块”内容的语法错误。报错后待编译程序自动中止后修正修补文件的语法错误,随后可继续多线程编译。
- 同一个文件,但两个软件包均提供了。报错自动中止后重新配置 OpenWrt,冲突的软件包二选一(OpenWrt 自带的软件包优先保留(为了兼容性),但也可选择替换,一般不会出现问题)。
使用命令:
make -j12 V=s
根据我的电脑配置,最后编译成功实际花费时间(取决于功能和软件包的数量):
因为使用的是 WSL,存在性能损耗,因此实际编译速度应该更快一点。
错误与解决(编译时)
这里仅说明 我遇到的问题,我没遇到的也不知道,也不能乱说。
内核编译错误
这种错误通常是 Linux 内核文件在编译时发生错误,这时需要检查是否修改过内核源码文件和修补文件。
如果修改过,则进行检查,检查修改过的文件语法是否有问题,更改的内容的语法是否有问题(比如是否缺少符号,“头”指定的新的行数是否与“块”中写入的相等)。
例如:
原来修补文件的“头”是:
@@ -10,11 +12,<b>15</b> @@ static struct example
意思为从第十行删去 11 行,从第十二行添加 15 行。如果增加 / 删除了修补文件“块”中的任何一行,则上方代码中加粗的数字应当对应增加 / 减少行数。
软件包编译错误
这种错误通常是:
- 选中的软件包中的部分文件相互冲突。
- 玄学问题。
对于第 1 种问题,我们需要查看错误日志,找到对应提示的文件。
例如提示(大概意思):“软件包:XXX 无法创建文件 ABC,因为 YYY 也提供了这个文件”。
这个时候需要重新配置 OpenWrt,在冲突的软件包二选一。
对于第 2 种问题,可能是 下载的软件包源码文件有问题 或莫名其妙出现这种情况
我在用 Fedora 35 编译的时候会有莫名其妙的问题,但使用 Ubuntu 则一次性编译成功,所以请尽量使用 Ubuntu 系统进行编译。
最好的方法是再次执行编译,大多时候这种问题就会消失,但如果还不消失,则需要执行下面的命令(每个命令我会用“#”符号在末尾注释)。
rm -rf tmp/ #清空 make download 的缓存(临时文件)rm -rf dl/【提示编译失败的软件包的名字】<TAB> # 删除无法编译的软件包源码,<TAB> 表示按键盘的“TAB 键”make download -j【CPU 线程数】V=s # 重新下载缺少的软件包源码
make -j1 V=sc # <b> 单线程 </b> 编译,显示全部错误日志
随后观察是否仍有错误,如果问题消失则可以按需求使用“Ctrl + C”终止后再次多线程编译。
欢迎补充相关的编译问题。
FAQ
- 软件包
Q:为什么我没有添加某个软件包、库,在编译的时候自动开始下载编译?
A:部分软件包 编译时 依赖于其他软件包、库和一些编程语言,这种情况使用提前下载源码文件的命令是无法下载的。如 AdGuardHome 软件包。其编译时依赖于 php、node.js、golang 等语言,因此编译过程中会自动下载这些语言的源码并编译。
其他
+= OpenWrt 的一些功能实现 =+
(欢迎大家补充)
- 更改默认的 IP 地址:
OpenWrt 默认的 IP 地址是在“192.168.1.1”,但对于需要多个子网或多台路由器来说这可能不是很好。
使用命令:
uci set network.lan.ipaddr='【你要修改为的 IP 地址】' && uci commit network
然后重新启动路由器即可。
+=+
2733mhz的内存条是超频的吧,我的电脑配置跟你很像
是的,总线频率超了2.5(102.5),内存标频是2666。