参考:【【教程】带你编译内核,手搓自己的Linux发行版!】 www.bilibili.com/video/BV1bF...
step1 内核源代码与编译
bash
下载地址:https://www.kernel.org/
可以直接下载最新版本的内核源代码
我选择的是linux-6.18.2, 这个是因为我编译内核的linux机器的内核版本如下:
(192.168.0.101)luoye@box-fn:~/code/linux$ uname -r
6.12.18-trim
ps:为啥要和编译机器的内核版本保持一致呢?因为后续可以避免很多编译时候的版本冲突和依赖问题
下载到本地后直接解压
tar -xvf linux-6.18.2.tar.gz
cd linux-6.18.2
make defconfig # 这里可以先选择使用默认配置就行,后续如果需要折腾的话可以再修改,第一次力求成功
make -j $(nproc) # nproc指定编译的cpu核数,有多少指定多少,速度更快
step2 制作shell工具(直接使用busybox)
bash
下载地址:https://www.busybox.net/downloads/
这个没什么特殊的版本要求,不过要和linux内核的版本兼容,这里我选择的是:busybox-1.37.0
下载后解压:tar -xvf busybox-1.37.0.tar.bz2
cd busybox-1.37.0
make menuconfig # 设置busybox的编译配置
# 注意,我们配置时候有两个配置项目
# 1. 直接配置静态编译(Settings -> Build static binary)
# 2. 关闭tc,不然可能会报错,关了再说(Networking Utilities -> tc),后续可以再研究
make -j $(nproc) # 编译busybox
make install CONFIG_PREFIX=$PATH # 安装busybox,这里的安装路径自己指定,其实就是系统的后续的根目录
step3 创建磁盘镜像
ini
# 写入一个512MB的空文件
# dd 写入工具
# if=/dev/zero 输入设备
# of=linux.img 输出设备
# bs=1M 块大小
# count=512 块数量
dd if=/dev/zero of=linux.img bs=1M count=512
# 使用gdisk创建分区(gpt分区,UEFI引导)
gdisk linux.img
# 创建两个分区
# 分区1 引导分区(引导启动)
指令如下:
Command (? for help): n
Partition number (1-128, default 1):
First sector (34-1048542, default = 2048) or {+-}size{KMGTP}: # 这里告诉gdisk创建分区起始位置,直接默认就行
Last sector (2048-1048542, default = 1046527) or {+-}size{KMGTP}: 50MB # 可以指定大小,也可以指定结束为止
Current type is 8300 (Linux filesy$tem)
Hex code or GUID (L to show codes, Enter = 8300): EF00 # 这里告诉gdisk创建分区类型为EFI
# 分区2 数据分区(存储linux内核问卷,真正的启动位置)
Command (? for help): n
Partition number (2-128, default 2):
First sector (34-1048542, default = 104448) or {+-}size{KMGTP}: # 开始位置默认
Last sector (104448-1048542, default = 1046527) ог {+-}size{KMGTP}: # 结束位置默认
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'
148.5 MB
Command (? for help): w # 保存
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING PARTITIONS!!
Do you want to proceed? (Y/N): # 输入y执行退出
这样就完成了
step4 挂载磁盘镜像并且安装grub
bash
sudo losetup -f -P linux.img # 挂载磁盘镜像
lsblk # 查看挂载情况 可以看到挂载的磁盘
sudo mkfs.fat -F32 /dev/loop0p1 # 格式化第一个分区的文件系统,这里使用fat32,因为是uefi引导,所以使用fat32
sudo mkfs.ext4 /dev/loop0p2 # 格式化第二个分区的文件系统,这里使用ext4,ext4在linux下性能比较好
# 这里可以先创建两个临时目录,就先暂定为/mnt1和/mnt2,在哪里都可以,将我们的分区挂载到这两个目录
sudo mount /dev/loop0p1 /mnt1
# 将引导程序安装到第一个分区,grub-install是常见的引导程序安装工具
sudo grub-install --target=x86_64-efi --efi-directory=$(realpath mnt1) --bootloader-id=GRUB --removable --recheck
# 进入mnt1, 注意,下面使用的都是临时的目录,如mnt1,如果是自己操作,需要修改
cd /mnt1
# 创建boot/grub目录
mkdir /mnt1/boot/grub
sudo cp /mnt1/EFI/BOOT/grub.cfg /mnt1/boot/grub/grub.cfg # 将grub.cfg复制到boot/grub目录
编辑文件/mnt1/boot/grub/grub.cfg
# 添加以下内容,注意,这里的fs_uuid需要修改为之前创建的数据分区的uuid(可以用这个命令看:sudo blkid /dev/loop0p2)
search.fs_uuid d2d129dc-27b4-4ea9-8d8a-a759b1bd44a5 root hd0,msdos1 # 设置指向的数据分区
set prefix=($root)'/boot/grub' # 设置默认的引导文件存放路径
configfile $prefix/grub.cfg # 加载数据分区的grub.cfg
修改完成后可以将/mnt1/boot/grub/grub.cfg再复制回mnt1/EFI/BOOT/grub.cfg
然后就可以解除挂载了
sudo unmount /mnt1
PS:这里注意下,/mnt1/EFI/BOOT/grub.cfg这个是兜底的引导文件,磁盘引导默认使用的是/mnt1/boot/grub/grub.cfg,只有当/mnt1/boot/grub/grub.cfg不存在时,才会使用/mnt1/EFI/BOOT/grub.cfg
step5 安装系统问卷到数据分区
bash
# 先挂载上来,这里的/mnt2可以自己指定任意目录
sudo mount /dev/loop0p2 /mnt2
# 将编译好的linux系统拷贝到mnt2
sudo cp linux-6.18.2/arch/x86/boot/bzImage /mnt2/ # linux-6.18.2/arch/x86/boot/bzImage这个是编译好的文件存放位置
# 将编译好的busybox也拷贝进去
sudo cp -r busybox/* /mnt2/
cd /mnt2
mkdir /boot # 创建引导文件存放目录
mkdir /proc # 创建系统运行时信息目录
mkdir /sys # 创建系统目录,运行时设备信息
mv bzImage /boot/ # 将bzImage移动到boot目录
cd /boot # 进入boot目录
mkdir /boot/grub # 创建引导文件存放目录
cd /boot/grub
# 编辑引导文件
vim grub.cfg
# 添加以下内容
menuentry "box_linux"{
insmod part_gpt
insmod fat
insmod ext2
insmod normal
search --no-floppy --fs-uuid --set=root d2d129dc-27b4-4ea9-8d8a-a759b1bd44a5 # 这里就是数据盘根文件系统的uuid
# 下面设置下引导参数
linux /boot/bzImage root=PARTUUID=a01a9a26-33f2-4ff6-bf4b-f819c087e281 rw init=/boot/init rootdelay=3 nomodeset console=ttyS0
}
# 保存退出
# 接下来编辑init文件
cd /boot
vim init
# 添加以下内容
#!/bin/sh
mount -t sysfs none /sys
mount -t proc none /proc
mount -t devtmpfs devtmpfs /dev
mknod /dev/console c 5 1
mknod /dev/ttyS0 c 4 64
exec /bin/sh > /dev/ttyS0 2>&1
# 保存退出
# 另外这里的init文件要设置为可执行
chmod +x /boot/init
sudo unmount /mnt2 # 解除挂载
# 可以detach下磁盘镜像
sudo losetup -d /dev/loop0
step6 使用qemu启动
diff
# 串口输出、内存配置的完整命令
qemu-system-x86_64 \
-drive file=./linux.img,format=raw,if=virtio \
-bios /usr/share/ovmf/OVMF.fd \
-m 1G \
-netdev user,id=n0 \
-device e1000,netdev=n0 \
-nographic \
-cpu qemu64,-vmx \
-boot c
step7 网络配置
在编译busybox之后默认不会ifup,ifdown这些,需要手动创建软连接才行。
1.创建/etc/network/interfaces
sh
sudo vim /etc/network/interfaces
文件内容如下(启动时激活lo接口和eth0网卡接口):
sh
# 第一部分:配置本地环回网卡 lo(必选)
auto lo # 1. 系统启动/执行 ifup -a 时,自动激活 lo 网卡
iface lo inet loopback # 2. 定义 lo 网卡的类型:IPv4(inet)、环回模式(loopback)
# 第二部分:配置物理网卡 eth0(核心)
auto eth0 # 1. 系统启动/执行 ifup -a 时,自动激活 eth0 网卡(可选,不加则需手动 ifup eth0)
iface eth0 inet dhcp # 2. 定义 eth0 网卡的类型:IPv4(inet)、通过 DHCP 自动获取网络参数
2. 创建/usr/share/udhcpc/default.script
sh
#!/bin/sh
# 1. 给网卡配置 IP 地址 + 子网掩码
[ -n "$ip" ] && ip addr add $ip/$subnet dev $interface
# 2. 设置系统默认网关(让系统能访问外网)
[ -n "$router" ] && ip route add default via $router
# 3. 写入 DNS 服务器地址(让系统能解析域名)
[ -n "$dns" ] && echo "nameserver $dns" > /etc/resolv.conf
创建完成后记得给文件可执行权限chmod +x default.script
当执行ifup eth0时,dhcp会默认执行default.script脚本。
主要是因为这里是使用qemu-system-x86_64来启动磁盘镜像的,在网络上需要特殊处理下
ini
网络配置
sudo pkill dnsmasq
2. 重新启动 dnsmasq(监听 10.0.2.1 + 转发到阿里云 DNS)
sudo dnsmasq --listen-address=10.0.2.1 --server=223.5.5.5 --no-daemon &
qemu-system-x86_64 \
-drive file=./linux.img,format=raw,if=`virtio` \
-bios /usr/share/ovmf/OVMF.fd \
-m 1G \
-netdev user,id=n0,dns=10.0.2.1 \
-device virtio-net-pci,netdev=n0 \
-nographic \
-serial mon:stdio \
-cpu qemu64,-vmx \
-boot c
step8 包管理工具安装(apk)
ruby
安装apk
仓库网址:https://gitlab.alpinelinux.org/alpine/apk-tools/-/releases(这里可以下载静态包)
密钥地址:这个文件夹下aports-master/main/alpine-keys
https://gitlab.alpinelinux.org/alpine/aports
要拷贝到/etc/apk/keys下
源配置:/etc/apk/repositories
http://dl-cdn.alpinelinux.org/alpine/latest-stable/main
http://dl-cdn.alpinelinux.org/alpine/latest-stable/community
上面这个源太慢了,可以使用阿里源
https://mirrors.aliyun.com/alpine/v3.14/main
https://mirrors.aliyun.com/alpine/v3.14/community
尝试安装第一个包:(外网的源,比较慢,会以为是卡住了,其实不是)
apk --initdb add file
虚拟机里面下载根证书:
apk add ca-certificates-bundle
之后就可以改成https了
修改完成后可以试试安装vim
apk add vim