制作一个简洁的树莓派系统 - 公鸡下单篇(交叉编译篇)

发布时间 2023-09-22 17:19:50作者: XYZ59C

“一只公鸡要下蛋,不是它的活它要干。”

开始之前

编译设备需要具有网络连接以及5GB的空闲磁盘空间
因为整个过程将不生成镜像文件,直接把系统写入磁盘,所以需要一张额外的空白MicroSD储存卡(推荐至少8GB),以及相应的读卡器
为了节省时间,除/boot外,/home/proc等都将直接包含在/下,不额外进行分区

主机信息

所有操作均在Debian发行版系统上完成

磁盘分区

将准备好的sd卡放入读卡器,插入编译设备的USB口让系统进行识别,准备开始分区工作
如果没有接入其他的储存设备,那么新的设备将在/dev/sdb
执行以下命令开始磁盘分区:sudo /sbin/fdisk /dev/sdb
成功进入fdisk后,首先输入p并回车,让fdisk打印磁盘信息,记录磁盘标识符 (Disk identifier)的值(如:0xac9d888d),这在之后会用到
fdisk打印信息

观察磁盘标签类型 (Disklabel type)的值,如果不是dos则输入o并回车,将磁盘的分区表修改为DOS,之后便可进行分区

  • 输入n并回车,创建第一个分区(启动分区)
    分区类型 (Partition type)分区号 (Partition number)以及First sector (第一个扇区)选项保持默认,无需输入任何数值,直接回车
    最后一个扇区 (Last sector)选项输入526335,回车完成分区创建,此时将回到fdisk主菜单
    回到主菜单后,输入t并回车
    fdisk将自动跳转到Hex代码或别名 (Hex code or alias)选项,输入b,回车修改分区文件系统类型为W95 FAT32
    完成分区文件系统类型更改后,将再次回到fdisk主菜单
    输入a并回车,fidks将自动为分区添加“可启动”标识
  • 输入n并回车,创建第二个分区(系统分区)
    分区类型 (Partition type)分区号 (Partition number)以及First sector (第一个扇区)依旧保持默认选项
    最后一个扇区 (Last sector)选项时,如不使用交换分区,则直接回车,完成分区工作;如需使用交换分区,则输入结束扇区的扇区号并回车完成第二分区分区工作
  • 【可跳过】输入n并回车,创建第三个分区(交换分区)
    所有选项全部保持默认,一路回车完成创建工作并回到fdisk主菜单
    回到主菜单后,输入t并回车
    分区号 (Partition number)选项输入3,回车
    Hex代码或别名 (Hex code or alias)选项输入82,回车完成分区工作

执行完上述操作后,输入w并回车,让fdisk将更改写入磁盘,写入完成后,fdisk将自动退出
最后使用mkfs系列命令进行分区格式化

  • 格式化启动分区:sudo /sbin/mkfs.vfat /dev/sdb1
  • 格式化系统分区:sudo /sbin/mkfs.ext4 /dev/sdb2

新接入的储存设备

构建内核

首先需获取构建内核所需要的依赖

  • 如果需构建32位系统,请执行以下命令:
    sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev
    sudo apt install crossbuild-essential-armhf
    
  • 如果需构建64位系统,请执行以下命令:
    sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev
    sudo apt install crossbuild-essential-arm64
    

当命令执行完成后,执行git clone --depth=1 https://github.com/raspberrypi/linux下载内核源码

如果需要获取不同版本的源码,请参考该命令:
git clone --depth=1 --branch <branch> https://github.com/raspberrypi/linux
Github的版本列表中一众以rpi-开头的分支才是内核源码
Github版本列表

源码下载完成后,对于不同的设备,接下来的操作也会有些许不同

构建32位系统:

  • 如果正在为Raspberry Pi 1Raspberry Pi ZeroRaspberry Pi Zero WRaspberry Pi Compute Module 1构建32位操作系统,请执行以下命令:
    cd linux
    KERNEL=kernel
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcmrpi_defconfig
    
  • 如果正在为Raspberry Pi 2Raspberry Pi 3Raspberry Pi 3+Raspberry Pi Zero 2 WRaspberry Pi Compute Modules 3Raspberry Pi Compute Modules 3+构建32位操作系统,请执行以下命令:
    cd linux
    KERNEL=kernel7
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
    
  • 如果正在为Raspberry Pi 4Raspberry Pi 400Raspberry Pi Compute Module 4构建32位操作系统,请执行以下命令
    cd linux
    KERNEL=kernel7l
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig
    

构建64位系统:

  • 如果正在为Raspberry Pi 3Raspberry Pi 3+Raspberry Pi 4Raspberry Pi 400Raspberry Pi Zero 2 WRaspberry Pi Compute Modules 3Raspberry Pi Compute Modules 3+Raspberry Pi Compute Modules 4构建64位操作系统,请执行以下命令:
    cd linux
    KERNEL=kernel8
    make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig
    

在正式构建前,可以使用menuconfig修改内核的配置

注意,该步骤并不是必要的,有时候保持默认配置并不是一个坏的选择

开始使用menuconfig前,请执行sudo apt install libncurses5-dev以确保必要依赖
命令执行完成后,即可使用menuconfig修改内核配置

  • 对于32位内核,使用下方命令修改配置:
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
    
  • 对于64位内核,使用下方命令修改配置:
    make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
    

menuconfig界面

(以下内容为树莓派官方文档中对menuconfig的介绍,原文英文,由机器翻译)
menuconfig实用程序具有简单的键盘导航功能。经过简短的编译后,您将看到一个子菜单列表,其中包含您可以配置的所有选项;有很多,所以花点时间仔细阅读并熟悉一下。
使用箭头键进行导航,使用Enter键进入子菜单(由--->指示),使用Escape两次进入上一级或退出,使用空格键循环选项的状态。有些选项有多个选项,在这种情况下,它们将显示为子菜单,并按Enter键选择一个选项。您可以在大多数条目上按h来获取有关特定选项或菜单的帮助。
在你的第一次尝试中,要抵制启用或禁用很多东西的诱惑;破坏配置相对容易,所以从小处着手,熟悉配置和构建过程。

完成内核配置后,即可开始进行编译工作

  • 对于32位内核,请执行以下命令:
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j2 zImage modules dtbs
    
  • 对于64位内核,请执行以下命令:
    make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j2 Image modules dtbs
    

内核的编译将耗费大量的时间以及CPU资源,请保持编译设备拥有充足的电源以及良好的散热

制作rootfs

在内核编译完成后,使用cd ../回到上一级目录
在开始前请先执行sudo apt install qemu qemu-user-static binfmt-support debootstrap安装所需依赖
安装完成后,创建sdcard文件夹并cd进入,并在其中创建rootfs文件夹,用于挂载sd卡
执行sudo mount /dev/sdb2 rootfs/挂载已格式化的文件系统
接着使用debootstrap构建基础系统

命令参考:
debootstrap --foreign --arch [体系结构] [发行版本代号] [目录] [下载源]

[下载源]参数如不填则将使用默认的下载站点
下方链接中包含了所有可用的下载源,替换默认源请使用离自己最近的站点:
https://www.debian.org/mirror/list

由于编译设备系统与目标系统的体系架构不相同,添加了--foreign参数

debootstrap在安装后存在于/sbin下,并且需要root权限
这里以构建arm64体系结构,版本为bullseye的基础系统作为示例参考:

sudo /sbin/debootstrap --foreign --arch=arm64 bullseye rootfs/

正在运行中的debootstrap

debootstrap执行完成后,将qumu-user-static包提供的文件拷贝到rootfs内,让编译设备系统能够chrootarm架构的系统内

  • 对于32位系统:
    sudo cp -a /usr/bin/qemu-arm-static rootfs/usr/bin/
    
  • 对于64位系统:
    sudo cp -a /usr/bin/qemu-aarch64-static rootfs/usr/bin/
    

下载ch-mount.sh到文件夹中,用以进入制作好的rootfs

wget https://raw.githubusercontent.com/psachin/bash_scripts/master/ch-mount.sh

使用chmod +x ./ch-mount.sh赋予脚本执行权限,再使用./ch-mount.sh -m rootfs/生成临时挂载点并进入rootfs

脚本执行时会请求root权限,但不要以root身份执行脚本
进入rootfs后,可能会出现I have no name!字样,为正常现象
接下来如无特殊说明,本节内的所有操作均在rootfs内的系统中完成

成功执行的ch-mount.sh

debootstrap二次解压:debootstrap/debootstrap --second-stage
命令执行成功后将会输出以下信息:

I: Base system installed successfully.

解压完成后,需先执行apt install ca-certificates为rootfs内的系统安装CA证书
证书安装完毕后,便可以打开/etc/apt/source.list文件更换镜像源
更换镜像源后,执行apt update更新软件列表,完成后继续安装必要程序

apt install dhcpcd5 locales sudo wget

执行useradd添加用户,例如:useradd nolen
修改新用户的密码,例如:passwd nolen
打开/etc/sudoers文件,在# User privilege specification下方新增一行,允许用户使用sudo命令:

nolen   ALL=(ALL:ALL) ALL

允许新用户使用sudo

在修改sudoer文件时,可能遭遇W10: Warning: Changing a readonly file警告
这时只需退出编辑器,使用chmod 640 /etc/sudoers修改sudoers文件的权限即可
不要忘记修改回去:chmod 440 /etc/sudoers

打开/etc/fstab文件,修改其中内容,让内核能够正常挂载文件系统,例如:

# UNCONFIGURED FSTAB FOR BASE SYSTEM
proc /proc proc defaults 0 0
PARTUUID=ac9d888d-01 /boot vfat defaults 0 2
PARTUUID=ac9d888d-02 / ext4 defaults,noatime 0 1
PARTUUID=ac9d888d-03 swap swap defaults 0 0

在示例中
ac9d888d是之前分区时获取到的磁盘id:0xac9d888d
后方的-01-02代表着磁盘的第一个分区(启动分区)、第二个分区(系统分区)
ac9d888d-03是交换分区

格式参考:
<file system> <mount point> <type> <options> <dump> <pass>
<file system> - 为要挂载的分区或存储设备,即相应的UUID
<mount point> - 为挂载点
<type> - 为文件系统类型
<options> - 为挂载时使用的参数
<dump> - 为是否做备份
<pass> - 为需要检查的文件系统的检查顺序

fstab文件内容

最后可以修改/etc/hostname修改主机名称,例如:echo 'my-rpi' > /etc/hostname
以及在/etc/hosts中新增127.0.0.1 my-rpi以防止sudo命令出现警告信息

完成后即可输入exit退出rootfs,然后使用./ch-mount -u rootfs/卸载掉临时挂载点

安装内核以及驱动

执行sudo mount /dev/sdb1 boot/挂载已格式化的文件系统
使用cd ../linux切换到内核源码目录,为rootfs中的系统安装必要模块

  • 对于32位系统,请执行以下命令:
    sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=../sdcard/rootfs modules_install
    
  • 对于64位系统,请执行以下命令:
    sudo make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=../sdcard/rootfs modules_install
    

在系统模块安装完成后,即可将内核以及驱动放入启动分区

  • 对于32位系统,请执行以下命令:
    sudo cp arch/arm/boot/dts/*.dtb ../sdcard/boot/
    sudo cp arch/arm/boot/dts/overlays/*.dtb* ../sdcard/boot/overlays/
    sudo cp arch/arm/boot/dts/overlays/README ../sdcard/boot/overlays/
    sudo cp arch/arm/boot/zImage ../sdcard/boot/$KERNEL.img
    
  • 对于64位系统,请执行以下命令:
    sudo cp arch/arm64/boot/dts/broadcom/*.dtb ../sdcard/boot/
    sudo cp arch/arm64/boot/dts/overlays/*.dtb* ../sdcard/boot/overlays/
    sudo cp arch/arm64/boot/dts/overlays/README ../sdcard/boot/overlays/
    sudo cp arch/arm64/boot/Image ../sdcard/boot/$KERNEL.img
    

虽然内核以及驱动都以安装完成,但缺少启动必要文件
cd ../回到上一级,执行git clone --depth=1 https://github.com/raspberrypi/firmware获取文件
当文件拉取完成后,执行以下命令将文件放入启动分区:

sudo cp firmware/boot/*.dat sdcard/boot/
sudo cp firmware/boot/*.elf sdcard/boot/

文件复制完成后,使用cd命令切换到已挂载的启动分区内,创建启动配置文件cmdline.txt以及内核配置文件config.txt

cd sdcard/boot/
sudo touch cmdline.txt
sudo touch config.txt

制作完成的启动分区

打开并修改cmdline.txt文件内容:

dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=ac9d888d-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles psi=1

cmdline.txtroot=PARTUUID=选项的值指向的是磁盘系统分区,注意替换

打开并修改config.txt文件内容:

  • 对于32位系统:
    [all]
    arm_64bit=0
    framebuffer_width=1280
    framebuffer_height=720
    disable_overscan=1
    dtparam=audio=on
    
  • 对于64位系统
    [all]
    arm_64bit=1
    framebuffer_width=1280
    framebuffer_height=720
    disable_overscan=1
    dtparam=audio=on
    

完成后回到上一级目录,卸载各文件系统

cd ../
sudo umount boot/
sudo umount rootfs/