OpenWrt 编译入门教程基础概念入门编译常见问题

很多开源项目可能无法直接使用,需要有人通过编译产出成品才能使用,或者你想修改代码后测试验证,那么都需要通过编译来完成,本篇文章为初入门的技术人员讲解 OpenWrt 编译相关的基础知识,常见问题等。

遵纪守法

虽然软件、网络等技术产物是虚拟的,但最终是作用于现实生活中,与大众的日常生活息息相关,所以必然要接受各种法律法规的管控,各类技术人员首先需要学习并牢记当地的法律法规,以免误入歧途,玩火自焚。

在中国工作和生活的技术人员请学习如下法律法规:
《中华人民共和国网络安全法》《计算机信息网络国际联网安全保护管理办法》《计算机软件保护条例》《中华人民共和国计算机信息系统安全保护条例》

编译概念

什么是编译?

一个程序是由人编写的,编写而成的文件称为“源代码”文件,这个文件本质上就是纯文本文件,里面是人类能看懂的字符内容(称为高级语言),但计算机系统是看不懂的,计算机只认识 0和1 (称为机器语言),而要想作为程序运行,则必须要将源代码文件转换为操作系统能看懂的文件(称为可执行文件),这个转换的过程就称为“编译”。

编译流程

“编译”在整个程序开发过程中,只是其中一个简单的环节,只需要执行几个简单的命令,然后等待“编译器”自动执行完毕即可。

编译常见问题

正常情况下,编译只需要简单的命令(通用 make),然后等待编译完成即可。
但仍然可能会遇到编译失败,这和程序作者有关,这个程序是给什么平台用、作者的编译环境是什么、作者最新的代码修改是否出现了笔误、网络原因导致文件下载损坏等等,这些都是可能的影响因素。

即便是看似同类型的操作系统,有时也不一定能编译成功,比如常见的 Centos 和 Ubuntu,虽然都是 Linux 系统,但它们的软件并不能通用,在一个系统编译成功,可能在另一个系统却会编译失败。

遇到编译错误时,就需要检查错误日志,分析原因,有时可能还需要调整部分源代码来解决编译错误,这往往需要一定程度的技术经验才能解决,并不是靠复制粘贴几个命令就能解决的。

编译所需条件

虽然编译对于程序员等专业技术人员来说是最简单的步骤,但是如果你只是一个外行,或者技术经验尚浅的学生,那么仍然需要具备一些基础条件,否则你将事倍功半,编译的目的是将源代码转换为程序,虽然你无需编写代码,但是为了编译成功,你至少需要学会看懂部分与编译有关的代码,要明白编译时需要哪些依赖项、正确的编译步骤等,否则你就属于无头苍蝇到处乱撞,就算误打误撞编译成功,也很可能因为你错误的编译步骤等,导致程序出现本不应该出现的功能异常等。

玩转编译至少需要:具备一定程度的英语阅读理解能力,有较大的耐心,自学能力强,逻辑思维较强,一定程度的 Linux 相关使用经验,熟练掌握了现代计算机基础知识。

如果你只是为了解决自己的个性化需求,并且不愿意投入时间和精力去学习相关的各类知识,只是寄希望于翻阅几篇教程,靠复制粘贴几个命令,或简单的点几下鼠标就搞定一切,那你肯定选错了方向。

对于连基础计算机知识都懒得学的同学,或忙得没时间学的上班族,不想自学,又想满足自己的各种技术类需求 ,最好的选择是找专业人士提供技术服务,只要钱给到位,一切问题都能解决。

程序开发流程

通过上面的流程图,不难发现,编译其实只是程序开发的其中一环,而且是最简单的一环,只需使用少许固定的编译命令即可,甚至可以使用脚本来执行自动化编译。

正确的反馈问题

程序员开发一款软件后,并不能保证百分百没有任何问题,所以需要反复进行“调试”步骤,不断改进和修复软件,而开源软件项目往往因为程序员的时间精力有限,只能做到有限的软件“测试”,无法针对各类复杂的应用环境进行全面测试,所以如果你是开源项目的用户,想要出力做贡献,除了提供“资金支持”,你至少还可以提供“测试”反馈,以帮助开发者完善软件。

什么样的反馈信息才能真正帮助开发者?
当你使用某个软件发生错误现象时,这时你应该收集系统日志、当前系统安装的软件列表、当前运行的进程信息、这个软件当前的配置文件、你执行了哪些操作、问题是否能百分百复现、相关截图说明、屏幕录像等等,诸如此类对排查问题有帮助的信息都应该收集起来,然后提供给开发者,这样开发者才能排查问题原因,如果你提供的信息足够详细且准确,开发者甚至只需要翻阅你提供的反馈信息就能找到问题所在,很快就能着手开始修复工作,能极大的减少开发者的工作量。

OpenWrt 编译准备

提示:初学者建议优先使用 Ubuntu 桌面系统进行编译操作,因为是图形界面,可以更方便的调整各种目录和文件,进行自定义操作也更直观易懂。

Windows 用户

  1. 一台配置够用的电脑(内存至少8G)
  2. 下载并安装 VMware Workstation Pro
  3. 下载 Ubuntu 22.04.1 Desktop 64位安装镜像。
  4. 已连接国际互联网。

Linux 用户

  1. 安装编译所需依赖。详情请参阅:[OpenWrt Wiki] Build system setup
  2. 已连接国际互联网。

部署编译环境

1. 打开 VMware 新建虚拟机:CPU 配置为实际核心数,内存至少 4G,硬盘至少 60G。

2. 选择 Ubuntu 安装镜像,启动虚拟机开始安装系统,选择自动分区,最小化安装即可。

3. 登录虚拟机 Ubuntu 系统,安装编译所需的依赖软件包。

sudo apt-get update

sudo apt install -y build-essential clang curl flex g++-multilib gawk \
gettext git libelf-dev libncurses5-dev libssl-dev python3-distutils \
mkisofs qemu-utils

sudo apt-get clean

4. 任意进入一个目录,开始下载所需的软件项目。

新手请注意:编译 OpenWrt 时的操作,均不要追加 sudo 命令,目录不要使用中文,否则会百分百导致编译失败。

OpenWrt 官网项目:

git clone https://github.com/openwrt/openwrt.git

OpenWrt-Life 项目:

git clone https://git clone -b openwrt-21.02 https://github.com/ikghx/openwrt-life.git

5. 进入源代码目录,更新并安装软件库。

./scripts/feeds update -a

./scripts/feeds install -a

6. 打开编译菜单界面,按个人需要进行定制。

make menuconfig

7. 执行编译命令

make

8. 等待编译完成,编译成功后会在源代码目录内生成 “bin” 目录,内含固件和配套的软件 ipk 包,首次编译预计耗时 3-6 小时,根据你的网络速度和电脑性能有关。

OpenWrt 其它常用编译命令

多线程加速编译,例如系统配备了4核心处理器。

make -j4

单线程编译并显示详细信息,用于排查编译错误。

make V=s

打开内核菜单界面,按需定制内核功能。

make kernel_menuconfig

清除当前编译机型的软件编译目录,以便快速测试软件包更改。

make clean

清空所有编译目录,以便开始全新编译。

make dirclean

检查已选择的项目,相关编译文件是否有明显错误。

make check

仅下载已选择项目的源码包。

make download

生成默认的 .config 文件,用于快速应用编译配置,以跳过执行 make menuconfig

make defconfig

刷新补丁文件,排查是否有补丁文件错误,能自动修正细微差异。

# 刷新软件包补丁,并显示详细信息。
make package/samba4/refresh V=s

# 刷新当前编译机型的内核补丁,并显示详细信息。
make target/linux/refresh V=s

单独编译某个软件包。

# 编译指定软件包,并显示详细信息。
make package/samba4/compile V=s

# 清理指定软件包编译目录,并显示详细信息。
make package/samba4/clean V=s

OpenWrt 自编译固件使用官网软件源

一些初入门的技术爱好者,觉得 OpenWrt 官网固件不合心意,想使用源代码自行编译,却又不敢过多修改 OpenWrt 的源代码,害怕弄巧成拙出现新的 Bug,于是想仅仅自定义一些简单参数,比如修改默认 LAN 口 IP、默认分区大小、集成几个软件等等个性化固件参数,然后让自己编译的固件直接使用 OpenWrt 的官网软件源。

这种情况遇到的问题是,自行编译的固件内核校验码与官网软件源不同,安装内核模块时会提示内核版本不匹配,导致安装失败。

要想解决这个问题也很简单,只需要将内核校验码固定为官网一样的即可。

首先根据自己需要下载对应的官网发行版源码,例如下载 19.07.5 发行版源码。

git clone -b v19.07.5 https://github.com/openwrt/openwrt.git

然后添加固定的内核校验码(vermagic 值),
打开 openwrt/include/kernel-defaults.mk,搜索 .vermagic
会找到这样一行:grep ‘=[ym]’ $(LINUX_DIR)/.config.set | LC_ALL=C sort | $(MKHASH) md5 > $(LINUX_DIR)/.vermagic

将这行代码替换为:cp $(TOPDIR)/.vermagic $(LINUX_DIR)/.vermagic

然后根据自己编译的机型平台,找到对应的官网软件源内核 vermagic 值,例如:x86_64

然后在 OpenWrt 源代码目录新建一个文件 .vermagic,里面写入OpenWrt 官网软件源的 vermagic 值即可。

接着你就可以开始执行编译命令了,编译完毕后的固件就能直接使用 OpenWrt 官网软件源。

让自编译固件使用镜像软件源

从 OpenWrt 官网下载页面可以看到,有很多软件源镜像站点,你可以选择将固件默认的软件源地址改为镜像软件源地址,这样刷机完毕后就无需再手动修改软件源地址了。

打开 openwrt/include/version.mk, 搜索 $(if $(VERSION_REPO),$(VERSION_REPO)
将此行代码中的网址替换为镜像软件站的地址即可,例如使用 “上海交通大学” 的镜像站。

关于软件源的使用技巧

很多初入门的 OpenWrt 用户有一个误解,以为第三方编译的固件完全无法使用 OpenWrt 的官网软件源,其实本质上来说只要第三方固件编译时没有修改编译库,且内核版本基本相同,那么都是可以正常使用官网软件源的。

例如 GL-iNet 路由器的固件就是基于 OpenWrt 的,想自行安装某些软件时,发现其缺少很多内核模块,首先查看 GL-iNet 的固件内核版本号,例如为:4.14.209,那么你只需要从 OpenWrt 官网软件源手动下载所需的对应版本的内核模块,大版本号相同即可(例如:4.14.209、4.14.275 内核模块一般可以通用),然后使用强制安装命令安装即可,完全可以正常运行,没有任何问题。

其它非 kmod 开头的常规软件,更是可以直接在线安装,只需修改 “配置 opkg…” ,添加软件源地址即可。
这类与内核模块无关的软件,只需要固件是使用 musl 库编译的即可安装使用。

基于 OpenWrt 的第三方编译的固件,只有在两种情况下才真正无法使用 OpenWrt 的官网软件源,
一种是修改了编译库,默认是使用 musl 库编译,但是被改为了使用 glibc 库,
一种是内核版本差异太大,比如 4.9 与 4.14 ,这种大版本差异也是完全没办法使用的。

总结

理论上来说编译确实简单,但前提条件是源代码文件已非常完善,然后只需执行简单的编译命令就能成功。

对于 OpenWrt 的编译,又不是那么简单,因为 OpenWrt 属于一个整合系统,其是由大量的各类独立软件组合而成,各个软件之间都或多或少互有关联,牵一发而动全身,加上这是开源系统,各个开发者各显神通,功能差异、版本不一、编译环境也各不相同,导致时常出现编译问题,也称为 “系统碎片化” 问题,如果你想要随心所欲的玩转 OpenWrt,实际上你需要有深厚的技术功底,有强大的代码纠错与整合能力。

有些基于 OpenWrt 修改而成的商业路由器系统,往往都采用很旧的系统内核版本,而且几乎不升级,这是因为很多商业路由器的驱动程序只能使用旧内核版本,而且为了降低维护成本,源代码不会做大更新,甚至不更新,只对使用过程中发现的错误进行修复。