Skip to content

部署系统环境 ​

在开始操作系统内核的开发之前,我们需要搭建一套完整的开发环境。本章将详细介绍所需的各类工具软件,包括宿主机操作系统的选择、集成开发环境的配置、编译工具链的安装,以及虚拟机调试环境的搭建。

本文档的开发环境基于 Fedora Linux 操作系统。如果你使用的是其他 Linux 发行版(如 Ubuntu、Arch Linux 等),安装命令可能会有所不同,但整体流程和原理是相通的。

Linux操作系统简介 ​

为什么选择Linux ​

在开始这个操作系统项目之前,我需要选择一个合适的宿主机操作系统作为开发环境。经过一番考虑,我最终选择了 Linux。

选择 Linux 的原因其实很简单:操作系统开发需要用到的 GCC、GDB、NASM 这些工具,本来就是为 Unix/Linux 环境设计的,在 Linux 下使用它们最省心。如果在 Windows 上折腾,要么用 WSL,要么用 Cygwin,总归会遇到各种奇怪的兼容性问题。

另外,Linux 本身就是一个开源的操作系统内核。在开发过程中遇到不懂的地方,可以直接去看 Linux 的源码是怎么实现的,这对学习操作系统原理很有帮助。Linux 的系统调用设计也可以作为我们设计自己操作系统接口时的参考。

Linux 的命令行工具也很强大。编译内核、制作磁盘镜像、启动虚拟机这些操作,写几行 Shell 脚本就能自动化完成,比在图形界面里点来点去方便多了。

虽然用 Windows + WSL 或者 macOS 也能做操作系统开发,但我个人觉得直接用 Linux 原生环境更省事,不用担心各种环境配置的坑。

Linux发行版概述 ​

Linux 有很多发行版可以选择,像 Ubuntu、Fedora、Arch Linux、Debian 这些都挺常见的。

我这次用的是 Fedora。选它主要是因为 Fedora 的软件包更新比较快,能用到比较新版本的 GCC 和其他开发工具。Fedora 用的是 DNF 包管理器,装软件挺方便的。另外 Fedora 和企业版的 RHEL 是一家的,稳定性也不错。

如果你习惯用 Ubuntu 或者其他发行版,其实也没问题,只是安装软件的命令会有点不一样。Ubuntu 用 apt,Arch 用 pacman,道理都是一样的。后面的教程我都会给出 Fedora 下的命令,如果你用其他发行版,自己换一下对应的包管理器命令就行。

宿主机系统:Fedora ​

Fedora简介 ​

我用的是 Fedora Linux,具体来说是 Fedora KDE Spin 版本。Fedora 是 Red Hat 社区维护的发行版,特点是软件包更新很积极,基本上能第一时间用上最新版本的各种开发工具。

Fedora 的包管理器叫 DNF,用起来挺顺手的。想装什么软件直接 sudo dnf install 包名 就行,依赖关系它会自动处理好。

我选择 KDE 桌面环境主要是个人喜好,KDE Plasma 看起来比较现代,而且自定义选项很丰富。当然用 GNOME 或者其他桌面环境也完全没问题,这个对开发没什么影响。

Fedora KDE 桌面

系统环境准备 ​

拿到一个新装的 Fedora 系统,第一件事是把系统更新到最新:

bash
sudo dnf update -y
Fedora 系统更新

更新完可能需要重启一下,特别是如果有内核更新的话。

接下来装一些基础的开发工具。Fedora 提供了一个开发工具组,一条命令就能把常用的东西都装上:

bash
sudo dnf groupinstall -y "Development Tools" "Development Libraries"

这会装上 GCC、Make 这些基础组件,还有一些常用的开发头文件。虽然后面我们还会单独介绍每个工具的安装,但先把这个开发工具组装了可以省去很多麻烦。

Fedora 的软件仓库分成好几个部分,像 fedora、updates 这些。对于我们做操作系统开发需要的工具,官方仓库基本都有,不用额外配置什么第三方源。

最后建议创建一个专门的目录来放我们的操作系统项目:

bash
mkdir -p ~/code/os
cd ~/code/os

后面的开发工作我都是在这个目录下进行的。你也可以放到别的地方,按自己习惯来就行。

集成开发环境:CLion ​

CLion简介 ​

写操作系统的代码量不小,用一个好的 IDE 可以大大提高效率。我选择的是 JetBrains 的 CLion。

CLion 是专门为 C/C++ 开发设计的 IDE,代码补全、跳转定义、重构这些功能都很强。它原生支持 CMake 项目,我们的操作系统项目刚好用的就是 CMake 来管理构建,所以用起来很顺手。

当然 CLion 是收费软件,不过学生可以申请免费的教育许可证。如果不想用 CLion,VS Code 配合 C/C++ 插件也是不错的选择,或者用 Vim/Emacs 这些传统编辑器也行,看个人习惯。

安装步骤 ​

在 Fedora 上安装 CLion 有几种方式。最简单的是用 JetBrains Toolbox:

JetBrains Toolbox

可以从 JetBrains 官网下载 Toolbox App,然后通过它来安装和管理 CLion。Toolbox 会自动处理更新,比较省心。

另一种方式是直接下载 CLion 的 tar.gz 包解压使用,或者用 Flatpak 安装:

bash
flatpak install flathub com.jetbrains.CLion

项目配置 ​

打开 CLion 后,直接选择 Open 然后定位到我们的项目目录就行。CLion 会自动检测到 CMakeLists.txt 并加载项目。

CLion 打开项目

第一次打开可能需要等一会儿,CLion 要建立代码索引。索引完成后,代码跳转和补全就都能用了。

CLion 主界面

GCC编译器 ​

GCC简介 ​

GCC(GNU Compiler Collection)是我们编译操作系统内核的主力工具。它是一个开源的编译器套件,支持 C、C++ 等多种语言。

我们的内核主要用 C++ 编写,少部分底层代码用 C,所以需要用到 GCC 的 g++ 和 gcc。GCC 在 Linux 下是标准配置,基本上每个发行版都会预装或者很容易安装。

安装配置 ​

如果之前执行了开发工具组的安装,GCC 应该已经装好了。可以验证一下:

bash
gcc --version
g++ --version

如果没装的话,手动安装也很简单:

bash
sudo dnf install -y gcc gcc-c++

我这里用的是 GCC 15.2.1,Fedora 仓库里的版本比较新。

GCC 版本信息

交叉编译说明 ​

这里有个需要注意的地方:我们编译的是一个独立的操作系统内核,不是运行在 Linux 上的普通程序。所以编译的时候需要加一些特殊的参数,告诉 GCC 不要链接标准库,生成的是 freestanding 代码。

具体的编译参数在 CMakeLists.txt 里已经配置好了,包括 -ffreestanding、-fno-builtin、-nostdlib 这些。后面讲到具体模块的时候会再详细解释。

NASM汇编器 ​

NASM简介 ​

虽然我们的内核主体用 C++ 编写,但有些底层的东西还是得用汇编来写,比如 bootloader、中断处理入口、上下文切换这些。我用的汇编器是 NASM(Netwide Assembler)。

NASM 使用的是 Intel 语法,和 GAS(GNU Assembler)的 AT&T 语法不一样。我个人觉得 Intel 语法更直观一些,mov eax, 1 比 movl $1, %eax 看着顺眼。

安装配置 ​

Fedora 仓库里有 NASM,直接装就行:

bash
sudo dnf install -y nasm

这里顺便说一下 Linux 作为开发环境的方便之处。很多人觉得 Linux 难用、麻烦,但实际上对于开发来说恰恰相反。你看,安装 NASM 就一条命令的事,不用去官网下载安装包、不用配环境变量、不用担心版本冲突。包管理器会帮你把一切都处理好。这就是为什么我选择 Linux 作为开发环境的原因之一。

装完验证一下版本:

bash
nasm --version

我这里是 NASM 2.16 版本,对于我们的项目来说足够用了。

编译汇编文件的命令大概是这样:

bash
nasm -f elf32 -o output.o input.asm

-f elf32 表示输出 32 位的 ELF 格式目标文件,因为我们的内核是 32 位的。这些编译命令在 CMakeLists.txt 里都配置好了,不需要手动执行。

Bochs虚拟机 ​

Bochs简介 ​

开发操作系统需要一个虚拟机来运行和测试。我选择的是 Bochs,一个专门为操作系统开发设计的 x86 模拟器。

为什么不用 QEMU 或者 VirtualBox?主要是 Bochs 的调试功能特别强大。它可以单步执行 CPU 指令、查看寄存器状态、设置断点,这对于调试 bootloader 和内核启动阶段的代码非常有用。普通的虚拟机在 OS 还没起来的时候是没法用 GDB 调试的,但 Bochs 可以。

当然 Bochs 的缺点是比较慢,毕竟是纯软件模拟。等内核开发到后期,可以切换到 QEMU 来跑,速度会快很多。

编译安装 ​

我用的是 Bochs 2.6.2 版本。这个版本比较稳定,而且网上的教程大多基于这个版本。

Fedora 仓库里的 Bochs 可能版本不对或者编译选项不合适,所以我选择从源码编译。先下载源码包,然后:

bash
tar xzf bochs-2.6.2.tar.gz
cd bochs-2.6.2
./configure --prefix=/usr/local/bochs \
            --enable-debugger \
            --enable-disasm \
            --enable-iodebug \
            --enable-x86-debugger \
            --with-x \
            --with-x11
make
sudo make install

这里 --enable-debugger 是关键,它会启用 Bochs 的内置调试器。--prefix 指定安装位置,我装到了 /usr/local/bochs。

如果想配合 GDB 远程调试,需要另外编译一份带 GDB stub 的版本:

bash
./configure --prefix=/usr/local/bochs-gdb \
            --enable-gdb-stub \
            --enable-disasm \
            --with-x \
            --with-x11
make
sudo make install

--enable-debugger 和 --enable-gdb-stub 不能同时启用,所以需要编译两份 Bochs。一份用内置调试器,一份用 GDB 调试。

配置文件 ​

Bochs 启动时需要一个配置文件来指定虚拟机的参数。我的配置文件 bochsrc.disk 长这样:

text
# Bochs使用的内存 单位MB
megs: 32

# BIOS和VGA BIOS
romimage: file=/usr/local/bochs/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/local/bochs/share/bochs/VGABIOS-lgpl-latest

# 选择启动盘符
boot: disk

# 设置日志输出
log: bochs.out
debugger_log: bochs_debugger.out

# 关闭鼠标并打开键盘
mouse: enabled=0
keyboard: keymap=/usr/local/bochs/share/bochs/keymaps/x11-pc-us.map

# 硬盘设置
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, path="hd64M.img", mode=flat, cylinders=130, heads=16, spt=63
ata0-slave: type=disk, path="hd80M.img", mode=flat, cylinders=162, heads=16, spt=63

几个重要的配置项:

  • megs: 虚拟机内存大小,32MB 对于我们的小内核够用了

  • boot: disk: 从硬盘启动

  • ata0-master: 主硬盘,我们的内核就装在这个镜像里

如果要用 GDB 调试版本的 Bochs,需要额外加一行:

text
gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0

这样 Bochs 启动后会在 1234 端口等待 GDB 连接。

CMake与Ninja构建系统 ​

CMake简介 ​

我们的项目用 CMake 来管理构建过程。CMake 是一个跨平台的构建系统生成器,它不直接编译代码,而是生成 Makefile 或者 Ninja 构建文件,然后由 Make 或 Ninja 来执行实际的编译。

用 CMake 的好处是配置比较清晰,比手写 Makefile 省事不少。而且 CLion 对 CMake 的支持很好,项目结构可以直接在 IDE 里管理。

安装CMake和Ninja ​

Fedora 仓库里有现成的:

bash
sudo dnf install -y cmake ninja-build

验证安装:

bash
cmake --version
ninja --version

我用的是 CMake 3.28 和 Ninja 1.12。

为什么用Ninja ​

CMake 默认生成 Makefile,但我配置成生成 Ninja 构建文件。Ninja 是 Google 开发的一个构建工具,特点是速度快。

对于我们这种需要频繁修改代码、重新编译的开发场景,Ninja 的增量编译速度比 Make 快不少。在 CMakeLists.txt 所在目录执行:

bash
cmake -B build -G Ninja
cmake --build build

第一行生成 Ninja 构建文件到 build 目录,第二行执行编译。CLion 会自动处理这些,不需要手动敲命令。

Git版本控制 ​

Git简介 ​

版本控制对于任何软件项目都很重要,操作系统开发也不例外。我用 Git 来管理代码版本。

Git 可以记录每次代码修改的历史,方便回溯和对比。写操作系统的时候经常会遇到改着改着把系统搞崩了的情况,有了 Git 就可以轻松回退到之前能用的版本。另外 Git 的分支功能也很有用,可以在不影响主线的情况下尝试新的实现方案。

安装配置 ​

Fedora 一般预装了 Git,如果没有的话:

bash
sudo dnf install -y git

第一次用 Git 需要配置一下用户信息:

bash
git config --global user.name "你的名字"
git config --global user.email "你的邮箱"

基本使用 ​

项目已经是一个 Git 仓库了。在这个项目里,我主要通过 CLion 内置的 Git 功能来管理版本,图形界面用起来比较直观,提交、查看历史、对比差异都很方便。

CLion 内置的 Git 界面

不过要注意的是,CLion 的 Git 功能只是一个图形前端,它底层还是调用系统安装的 Git。所以即使你打算只用 CLion 来操作 Git,也必须先把 Git 装好。

如果需要用命令行,日常开发中常用的命令就这几个:

bash
git status          # 查看当前状态
git add .           # 添加所有修改
git commit -m "描述" # 提交
git log --oneline   # 查看提交历史
git diff            # 查看未提交的修改

建议养成经常提交的习惯,每完成一个小功能就 commit 一次。提交信息写清楚改了什么,以后查历史的时候会很有用。

GDB调试器 ​

GDB简介 ​

GDB 是 GNU 项目的调试器,可以用来调试 C/C++ 程序。在操作系统开发中,GDB 配合 Bochs 的 GDB stub 功能,可以实现对内核的源码级调试。

有了 GDB,就可以在内核代码里设断点、单步执行、查看变量值,比光看 Bochs 的汇编级调试方便多了。

安装配置 ​

GDB 一般在开发工具组里已经装好了,如果没有:

bash
sudo dnf install -y gdb

验证一下:

bash
gdb --version

配合Bochs调试 ​

使用 GDB 调试内核的基本流程是这样的:

1. 启动带 GDB stub 的 Bochs(使用 bochsrc-gdb.disk 配置) 2. Bochs 会在 1234 端口等待连接 3. 启动 GDB,连接到 Bochs:

bash
gdb kernel.bin
(gdb) target remote localhost:1234
(gdb) break kernel_main
(gdb) continue

这样就可以在内核代码里调试了。CLion 也可以配置成用图形界面来进行 GDB 远程调试,设置一个 Remote Debug 配置就行。

使用 CLion 调试操作系统内核

调试内核和调试普通程序有点不一样,因为内核运行在不同的地址空间。需要确保加载的符号表和实际运行的代码地址匹配,否则断点可能不生效。

CLion 远程调试配置符号文件