Openwrt 编译官方固件详解


共计 9865 个字符,预计需要花费 25 分钟才能阅读完成。

一、OpenWrt 简介

OpenWrt 是一个开源的嵌入式操作系统,专为无线路由器和其他网络设备而设计。平常我们买的路由器基本都是厂家烧录的固件,功能非常有限。而刷了 openwrt 固件或其他如潘多拉固件,这些固件可以以安装插件的方式,让我们更加方便灵活的使用一些功能,如 DDNS、广告屏蔽等插件。

OpenWrt 在方便的地方还是在于它的可定制性,因为不同的硬路由设备它的 falsh 和内存都不一样,所以可以根据自己的需要和路由器的硬件参数来编译自己的 openwrt 系统,因为每个人的路由器不一样,也许用别人编译的固件不一定适合。

接下来就说说如何编译自己的 openwrt 镜像,本次使用的源代码是官方的,地址:https://github.com/openwrt/openwrt

另外,国内也有大神对 openwrt 系统做了一些定制,整合了更多国内需要的插件,地址:https://github.com/coolsnowwolf/lede

其实使用官方源码也是可以自己整合主题和需要的插件的,这些内容将会在后面讲到。

二、纯官方源码编译

1. 编译前准备

最好是挂梯子,否则很有可能因为网络问题编译失败

首先官方推荐使用 ubuntu 或者 debian 来编译 openwrt 镜像,所以需要准备一台虚拟机或物理机安装好系统,本次使用的是 ubuntu 22.04。

安装好以后更新软件源和安装编译所需的软件,这里用到的是 lede 大神提供的命令。

sudo apt update -y
sudo apt full-upgrade -y
sudo apt install -y ack antlr3 asciidoc autoconf automake autopoint binutils bison build-essential \
bzip2 ccache cmake cpio curl device-tree-compiler fastjar flex gawk gettext gcc-multilib g++-multilib \
git gperf haveged help2man intltool libc6-dev-i386 libelf-dev libglib2.0-dev libgmp3-dev libltdl-dev \
libmpc-dev libmpfr-dev libncurses5-dev libncursesw5-dev libreadline-dev libssl-dev libtool lrzsz \
mkisofs msmtp nano ninja-build p7zip p7zip-full patch pkgconf python2.7 python3 python3-pyelftools \
libpython3-dev qemu-utils rsync scons squashfs-tools subversion swig texinfo uglifyjs upx-ucl unzip \
vim wget xmlto xxd zlib1g-dev python3-setuptools

2. 编译配置

接下来就可以下载源代码进行自定义配置了。

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

下载完源码后,还需要进入 openwrt 里面更新 feed。feed 可以认为是 openwrt 的一些组件,这些组件自己维护自己的源码,以免和 openwrt 核心源码耦合太高。feed 源可以在 feeds.conf.default 文件中看见,内容如下:

# 软件包
src-git packages https://git.openwrt.org/feed/packages.git
# openwrt 图形界面
src-git luci https://git.openwrt.org/project/luci.git
# 路由相关的软件包
src-git routing https://git.openwrt.org/feed/routing.github
# 电话通信相关的软件包
src-git telephony https://git.openwrt.org/feed/telephony.git
#src-git video https://github.com/openwrt/video.git
#src-git targets https://github.com/openwrt/targets.git
#src-git oldpackages http://git.openwrt.org/packages.git
#src-link custom /usr/src/openwrt/custom-feed

了解完这些以后,接下来需要更新和安装 feed。

cd openwrt
# 下载软件到 feeds 目录
./scripts/feeds update -a
# 实际上是将 feeds 目录下的文件软链到 package/feeds 目录下的文件
./scripts/feeds install -a

然后接下来就是重中之重了,这里 openwrt 提供一个图形化界面进行相应的配置,配置好以后会生成一个 .config 文件。进入图形化界面,输入以下命令即可:

make menuconfig

如果第一次进来,看见这么多选项肯定会有点懵,没关系,下面将给出大概的解释。其实,就算是自己编译固件,如果不是很特殊的需求,只需要注意几点即可。

首先是确定目标的型号,比如编译 x86 通用的镜像还是说针对自己硬路由型号的固件。

然后就是 LuCI 中配置主题和需要的插件,当然这里的插件不要贪多,根据自己的需求即可,否则可能冲突导致编译报错。LuCI 配置要选 Collections 其中一项,因为默认是没有勾选的,不勾选将没有图形界面。Modules 里面选择 Translations 包含语言,简体中文是默认没有勾选的,需要勾选上。LuCI compatibility libraries 也需要勾选上,这个是 LuCI 的兼容库,不勾选可能导致页面加载缓慢。插件和主题的话根据自己需要进行选择,注意这里 * 代表编译并包含进固件镜像,M 代表仅仅编译,空则表示不编译。

下面就是对 make menuconfig 界面的一些解释了,一般来说都需要了解,否则可能不能编译出自己需要的特殊镜像。

  1. Target System:目标系统的体系结构,比如 x86 架构、arm 架构等。

  2. Subtarget:目标系统的子目标,更精细化的选择,比如 x86 架构下有 64 位,还有传统的 32 位选项,另外还有 amd 和 i386。

  3. Target Profile:选择目标配置文件。

  4. Target Images:选择要生成的目标镜像类型。比如 x86 为例,可以生成 ext4、squashfs 等文件系统镜像,还可以直接生成虚拟机所用的磁盘文件,比如 qcow2、vhdk 文件等。这里还可以选择镜像的打包格式,这样可以节省空间,可以选择 cpio.gz 和 tar.gz。

ramdisk:内存盘。它是一个临时的文件系统,可以加载到内存中使用。

Root filesystem archives - 根文件系统的归档格式选项

  • cpio.gz:使用 cpio.gz 格式来打包根文件系统。
  • tar.gz:使用 tar.gz 格式来打包根文件系统。

Root filesystem images - 根文件系统的映像格式选项

  • ext4:ext4 是一种日志化的文件系统,具有较高的性能和可靠性。支持读写操作,并提供了对大文件和大容量存储设备的支持。可以比较方便的调整分区大小,如果有扩展根分区的需求选这个。
  • squashfs:squashfs 是一种只读压缩文件系统。它将文件系统打包成只读的压缩镜像,可以有效地减小文件系统的尺寸,并提供压缩和随机访问的功能,还有利于恢复系统

Build GRUB images:构建 GRUB 引导加载程序的镜像,仅适用于 Linux x86 或 x86_64 主机。

Build GRUB EFI images:构建 GRUB EFI 引导加载程序的镜像,仅适用于 Linux x86 或 x86_64 主机。

Use Console Terminal (in addition to Serial):在串口之外使用控制台终端,启用时需要配置串口设备名称和串口波特率。

  • Serial port device:串口设备名称。
  • Serial port baud rate:串口波特率。
  • Use RTE/cTs on serial console:启用 Use Console Terminal 时,可以启用该项在串口控制台上使用 RTE/cTs。

Extra kernel boot options:额外的内核启动选项,可以在此项输入字符串。

Seconds to wait before booting the default entry:在启动默认条目之前等待的时间(秒)。常用于引导加载程序(如 GRUB)的配置中,比如 centos 启动时有很多项可以选择,但是超过该时间就会选择默认条目。

Title for the menu entry in GRUB:GRUB 菜单条目的标题。

Build LiveCD image (ISO):构建 LiveCD 镜像(ISO 格式)。

Build PVE/KVM image files (Qcow2):构建 PVE/KVM 镜像文件(Qcow2 格式)。

Build VirtualBox image files (VDI):构建 VirtualBox 镜像文件(VDI 格式)。

Build VMware image files (VMDK):构建 VMware 镜像文件(VMDK 格式)。

Build Hyper-V image files (VHDX):构建 Hyper-V 镜像文件(VHDX 格式)。

Gzip images:对镜像进行 gzip 压缩。

Image Options - 镜像选项

  • Kernel partition size (in MiB):内核分区的大小(以 MiB 为单位)。
  • Root filesystem partition size (in MiB):根文件系统分区的大小(以 MiB 为单位)。一般该根文件系统分区会分得比较大些,剩下的空间将分配给 overlay。
  • Root partition on target device:目标设备上的根分区。该选项通常是空白或未指定的。这意味着>根文件系统镜像不会自动安装到目标设备上的任何特定分区。根文件系统将会被写入设备的整个存储空间(通常是闪存或磁盘),而不是特定的分区。这种方式被称为“全闪存安装”或“整盘安装”。
  • Make /var persistent:使/var 目录持久化。/var 目录通常是一个临时目录,其内容保存在内存中,每次重启内容都会丢失。可以将 /var 目录的存储改为持久化,使其在设备重启后保留数据。这对于存储需
    要在重启间保持的配置文件、日志、临时数据等非易失性数据非常有用。

编译的镜像不但有内核镜像和根文件系统镜像,还有一个带 combined 后缀的镜像,这个镜像实际上是将根文件系统和内核合并到一个镜像文件中可以更方便地部署和使用。所以其大小为内核分区 + 根文件系统的大小。

  1. Enable experimental features by default:这个选项允许默认启用实验性的功能。如果选择启用,编译生成的 OpenWrt 固件将会默认包含实验性的功能。这些功能可能还不够稳定或经过充分测试,因此仅供开发和测试目的使用。

  2. Global build settings:这个选项打开了全局构建设置,允许对 OpenWrt 的构建进行全局配置。

  3. Advanced configuration options:这个选项提供了高级配置选项,适用于开发人员。

  4. Build the OpenWrt Image Builder: 这个选项允许构建 OpenWrt 的镜像构建工具(Image Builder)。Image Builder 是一个独立的工具,允许你在已编译的基础上自定义和生成 OpenWrt 镜像。这个工具可以在编译好镜像以后,单独编译主题或者是软件包。 另外还支持配置网络设置、创建预配置的固件、构建定制的固件等。

  5. Build the OpenWrt SDK:这个选项允许构建 OpenWrt 的软件开发工具包(SDK)。SDK 提供了开发应用程序和软件包所需的工具和库,以便在 OpenWrt 上进行应用程序开发。

  6. Package the OpenWrt-based Toolchain:这个选项允许打包基于 OpenWrt 的工具链。工具链是一组编译器、库和工具,用于在特定平台上进行软件开发和编译。

后续的选项是组织 OpenWrt 固件的不同部分和组件,如基本系统、管理、引导加载程序、开发、额外软件包、固件、字体、内核模块、语言、库、LuCI(Web 界面)、邮件、多媒体、网络、声音、实用工具和 Xorg(X Window 系统)等。通过选择这些选项,你可以定制所需的功能和组件,并将其包含在编译生成的 OpenWrt 固件中。

  1. Base system:包括操作系统的核心组件和基本工具。这些组件是构建 OpenWrt 固件所必需的基本部分。比如防火墙、opkg 工具、dnsmasq 等包含在这里。

  2. Administration:提供管理和配置功能的软件包。这包括系统管理、网络管理、用户管理、文件管理等相关工具。比如 htop、Zabbix、netdata 等。

  3. Boot Loaders:用于启动设备的引导加载程序,例如 GRUB、U-Boot 等。这些组件负责引导加载和启动 OpenWrt 固件。

  4. Development:包括开发工具链和库,用于在 OpenWrt 上进行应用程序开发和定制。这使得用户能够为特定需求开发自己的软件和功能。

  5. Extra packages:提供额外功能和应用的软件包。这些包括各种网络工具、媒体应用、安全性软件、Web 服务器等。

  6. Firmware:包括路由器固件和其他设备所需的驱动程序和固件文件。这些组件负责设备的硬件支持和功能。

  7. Fonts:提供不同字体样式和字体库的软件包。这允许设备显示不同的字体和文本效果。

  8. Kernel modules:提供额外的内核模块,以支持特定的硬件功能和驱动程序。这些模块可以根据需要进行选择和包含。

  9. Languages:配置支持的编程语言。

  10. Libraries:提供各种库文件和依赖项。这些库提供了不同应用程序和组件的基础功能和支持。

  11. LuCI:包括 LuCI Web 界面的相关组件和应用。LuCI 是 OpenWrt 的默认 Web 管理界面,用于配置和管理路由器。

  • Collections:这个目录包含了一组逻辑相关的 LuCI 插件。每个集合都有一个名称,并包含一组相关的功能模块。集合的目的是为了组织和管理 LuCI 的功能模块。 比如有支持 docker 的集合,还有使用 nginx 的集合等等。
  • Modules:这个目录包含了 LuCI 的功能模块,也称为插件。每个模块对应 LuCI 界面的一个特定功能或配置项。模块可以是路由器的不同配置部分(如网络设置、无线设置、防火墙等),也可以是其他功能模块(如系统日志、文件管理等)。
  • Applications:这个目录包含了一些额外的应用程序或服务插件,可以通过 LuCI 进行配置和管理。这些应用程序可能包括 DHCP 服务器、DDNS 客户端、VPN 客户端等。
  • Themes:这个目录包含了 LuCI 的界面主题,用于改变 LuCI 界面的外观和样式。
  • Protocols:这个目录包含了 LuCI 支持的不同网络协议的配置和管理插件。例如,可以配置 ipv6 和 ppp 网络协议的插件。
  • Libraries:这个目录包含了 LuCI 使用的各种库文件,这些库文件提供了 LuCI 运行所需的核心功能和支持。
  1. Mail:提供邮件客户端和服务器的软件包。这使得设备能够发送和接收电子邮件。几乎用不到,所以默认不勾选。

  2. Multimedia:包括多媒体应用和库的软件包。这包括音频播放器、视频播放器、图像处理等。包括 ffmpeg 工具,还有解锁网易云灰色歌曲工具。

  3. Network:提供不同网络协议和网络工具的软件包。这包括网络协议栈、路由协议、网络分析工具等。包括常见的 iperf、wol 工具。

  4. Sound:提供音频处理和声音功能的软件包。这包括音频编解码器、音频处理工具等。软路由上几乎用不到,所以默认也几乎没有勾选。

  5. Utilities:包括各种实用工具和辅助软件的软件包。这些工具可以用于系统调试、日志记录、网络测试等。包括常见的 lsof、lscpu 等。

  6. Xorg:提供 X Window 系统的相关组件和应用。这允许设备具有图形用户界面和图形应用的功能。

3. 编译

编译前最好先进行下载编译所需的文件,避免编译时因为网络导致编译报错。其中 $(nproc) 代表 cpu 核心数,如果你知道自己电脑的核心数,直接填写数量即可。

make download -j$(nproc)

然后就是进行编译,编译的过程是非常漫长的,并且很多人建议首次编译时使用单线程,其实这只是为了方便查看报错。实际上,首次编译也可以使用多线程,如果遇到编译报错再使用单线程查看错误也是可以的,因为再次编译时会从报错的位置开始,而不是从头开始。这里设置 V=s 选项就是启用详细输出模式,让编译过程中的每个步骤都显示详细的日志信息,方便排查错误。

make V=s -j$(nproc)

编译好以后,可以在 OpenWrt 源码目录下的 bin/targets/xxx/xxx 文件查看到编译好的文件。

名称带 kernel 的固件是内核固件,带 rootfs 的固件是根文件系统,带 combined 的镜像是内核和根文件系统的组合。内核固件是操作系统的核心,负责管理硬件和提供基本的系统功能。根文件系统包含了操作系统的文件和目录结构,提供了用户空间程序和配置文件。

在正常的启动过程中,引导加载程序(bootloader)会首先加载内核固件,然后将控制权交给内核。内核会初始化系统并挂载根文件系统,然后执行用户空间程序。

如果尝试单独启动内核固件,它将无法正常运行,因为缺少必要的系统组件和文件。同样地,如果你单独启动根文件系统,它将没有一个运行的内核来提供系统功能。

为了成功启动 OpenWrt,你需要同时加载内核固件和根文件系统。这通常是由引导加载程序完成的,它会将两者结合在一起并启动系统。

当然,在某些只需要根文件系统的情况下,可以只需要根文件系统,比如使用 lxc 容器启动容器,这容器将与宿主机共享内核。

三、添加第三方插件主题编译

其实添加第三方的主题或插件一般只需要拉取代码到 package 目录,可以在此目录下新建文件夹,因为执行 make menuconfig 命令时会扫描该文件夹下的 Makefile。

这里以 argon 主题和 passwall 插件为例:

添加第三方主题

cd package
# 创建以自己用户名命名的文件夹,方便管理
mkdir hz
cd hz
# 拉取主题代码
git clone https://github.com/jerrykuku/luci-theme-argon.git

接下来就可以在 make menuconfig 界面选择 LUCI -> Theme -> Luci-theme-argon 主题了。

添加第三方插件

passwall 插件可能比较特殊,需要配置 feed 源,因为它需要依赖 v2ray-core、xray-core 等组件。

# 需要在 openwrt 源码根目录下执行
echo "src-git passwall_packages https://github.com/xiaorouji/openwrt-passwall-packages.git;main" >> "feeds.conf.default"
echo "src-git passwall https://github.com/xiaorouji/openwrt-passwall.git;main" >> "feeds.conf.default"

更新并安装 feed 源:

./scripts/feeds update -a
./scripts/feeds install -a

接下来就是拉取 passwall 插件代码:

cd package
# 创建以自己用户名命名的文件夹,方便管理
mkdir hz
cd hz
# 拉取插件代码
git clone https://github.com/xiaorouji/openwrt-passwall.git

接下来就可以在 make menuconfig 界面选择 LUCI -> Applications -> Luci-app-passwall 插件,并需要把插件的 configuration 里面的选项全部选上。

这里可能报错,也许是 passwall 默认依赖了 dnsmasq-full,和之前官方默认选择的 dnsmasq 有冲突,所以把 dnsmasq 取消即可。此外,编译其他的插件也有可能出现这种情况,所以需要注意看日志。

Openwrt 编译官方固件详解

/>

四、单独编译插件

也许你可能用的官方的固件,基本上很满意,但是想要安装一个插件,那么此时可以自己编译一个插件。需要注意的是,需要知道用哪个版本的源码来编译,这个目前还不知道怎么看,只知道个大概的编译流程。

这里以编译 luci-app-aria2 为例,首先最好更新一下 feeds:

./scripts/feeds update -a
./scripts/feeds install -a

然后需要运行如下命令:

make menuconfig

在配置页面中,选择 LUCI -> Applications -> Luci-app-aria2 插件,并保存配置。

其次最重要的是知道需要单独编译的软件包,在 openwrt 源码的哪个目录下,如 aria2 的路径为 package/feeds/luci/luci-app-aria2/。知道路径以后,那么运行代码:

# 先清除模块
make package/feeds/luci/luci-app-aria/clean
# 编译模块
make package/feeds/luci/luci-app-aria2/compile V=s -j$(nproc)
# 也许因为是编译固件漏掉了该插件,那么可以执行如下命令
# 将单独编译的软件包安装到OpenWrt的软件包路径中
# make package/install
# 将软件包从软件包路径复制到目标设备中的相应位置进行安装
# make target/install 

等待 此时在 bin/packages/xxx/luci 目录下已经生成了 luci-app-aria2_git-xxx.ipk 软件包,如果你是中文环境,那么还有可能生成了 luci-i18n-aria2-zh-cn_git-xxx.ipk 汉化包。

需要注意的是,如果是自己下载源码放在 packages 的源码,目录有可能不同,可以考虑使用 find 命令查找:sudo find / -name "ipk" | grep "aria2"

如果此时直接打开 luci 界面,上传软件包并安装,会发现报错:

Collected errors:

  • pkg_hash_check_unresolved: cannot find dependency aria2 for luci-app-aria2
  • pkg_hash_fetch_best_installation_candidate: Packages for luci-app-aria2 found, but incompatible with the architectures configured
  • opkg_install_cmd: Cannot install package luci-app-aria2.

这是因为 luci-app-aria2 的依赖没有安装,它的依赖可以在 Makefile 文件中看见:

LUCI_DEPENDS:=+luci-base +aria2

说明 luci-app-aria2 依赖于 luci 基础包,还依赖于 aria2 这个软件包。一般来说,这个软件包会存在于 luci 目录同级目录下的的 packages 文件夹下。

关于软件包的依赖,还可以在官网查找:https://openwrt.org/packages/index/start。当然,如果官方源码里面没有的软件包,这里应该也是找不到的,还是需要看软件包的 Makefile 文件。

知道了需要先安装依赖那就好办了,因为在配置界面选中 luci-app-aria2 时,也会默认选中它的依赖。它能编译成功,说明他的依赖也编译成功了,可以在 bin/packages/xxx/packages 目录下找到 aria2_xxx.ipk

最后只需要按依赖顺序进行安装即可,aria2_xxx.ipk -> luci-app-aria2_git-xxx.ipk -> luci-i18n-aria2-zh-cn_git-xxx.ipk

提醒:本文发布于351天前,文中所关联的信息可能已发生改变,请知悉!

Tips:清朝云网络工作室

阅读剩余
THE END