X2W-OS Make Targets#
X2W-OS使用 make来管理项目。具体来说,X2W-OS的 Makefile中所有的目标可以分为三类:
编译相关目标:编译内核、编译
SBI、编译文档运行调试相关目标:使用
QEMU运行X2W-OS、使用GDB、VSCode调试X2W-OSMiscellaneous目标:具有多种用途的目标,例如杀死所有
QEMU进程、启动HttpServer阅读文档……
下面将分别介绍 X2W-OS中这三类目标。
关于
Makefile的源代码,请参考X2W-OS项目根目录下的Makefile文件
编译相关目标#
X2W-OS的 Makefile中分别提供了编译源文件、内核、SBI、文档的目标
编译源文件:obj#
Makfile中定义了 obj目标,该目标将会编译内核和 SBI的源文件、生成目标文件
make obj
编译得到的目标文件和生成得到的内核将输出至 build文件夹下
注意:
该目标通常用于检查内核和
SBI的目标文件
$ make obj
mkdir -p /Users/jack/project/OSKernel2023-X2W/build/disasms
mkdir -p /Users/jack/project/OSKernel2023-X2W/build/temps
mkdir -p /Users/jack/project/OSKernel2023-X2W/build/lib /Users/jack/project/OSKernel2023-X2W/build/lib/kernel /Users/jack/project/OSKernel2023-X2W/build/lib/user /Users/jack/project/OSKernel2023-X2W/build/kernel /Users/jack/project/OSKernel2023-X2W/build/device
mkdir -p /Users/jack/project/OSKernel2023-X2W/build/sbi
/* -------------------------- 编译内核和SBI -------------------------- */
当前内核目标文件:
build/kernel/boot.o
build/lib/stdfmt.o
build/lib/stdlib.o
build/lib/string.o
build/lib/kernel/kstdio.o
build/lib/user/ustdio.o
build/kernel/init.o
build/kernel/main.o
build/kernel/test.o
build/device/uart.o
-----------------------------------------------------------------------
当前SBI目标文件:
build/sbi/sbi_boot.o
build/sbi/sbi_main.o
-----------------------------------------------------------------------
编译内核:kernel#
Makfile中定义了 kernel目标,该目标将会编译内核源文件、生成目标文件,最后通过 kernel/kernel.ld链接脚本指导链接器链接得到内核
make kernel
编译得到的目标文件和生成得到的内核将输出至 build文件夹下
注意:
在
build文件夹下默认生成的ELF格式内核,文件名为os.elf为了方便后续的反汇编,
kernel目标还会生成内核的裸二进制文件os.bin为了方便提交测试,
kernel目标会将os.elf复制到根目录下,并将其重命名为${KNAME}
KNAME变量定义在 Makefile中,修改该变量的值即可控制最终在根目录下的内核文件名
# 编译生成的内核的名字,将会得到 <path-to-X2W-OS>/kernel.elf
KNAME := kernel.elf
编译SBI:sbi#
Makfile中定义了 sbi目标,该目标将会编译 SBI源文件、生成目标文件,最后通过 sbi/sbi.ld链接脚本指导链接器链接得到 SBI
make sbi
编译得到的目标文件和生成得到的 SBI将输出至 build文件夹下
注意:
在
build文件夹下默认生成的ELF格式SBI,文件名为sbi.elf为了方便后续的反汇编,
sbi目标还会生成SBI的裸二进制文件os.bin为了方便提交测试,
kernel目标会将sbi.elf复制到根目录下,并将其重命名为${SNAME}
SNAME变量定义在 Makefile中,修改该变量的值即可控制最终在根目录下的 SBI文件名
# 编译生成的内核的名字,将会得到 <path-to-X2W-OS>/sbi.elf
SNAME := sbi.elf
编译文档:documentation#
Makfile中定义了 documentation目标,该目标将会通过 Doxygen和 Sphinx编译文档系统
make documentation
编译得到的 Doxygen文档和 Sphinx文档将分别输出至:
<path-to-X2W-OS>/docs/doxygen/build<path-to-X2W-OS>/docs/sphinx/build
注意:
Sphinx将会输出html格式的文档Doxygen将会输出html、latex和xml三种格式的文档,你可以修改<path-to-X2W-OS>/docs/doxygen/Doxyfile来改变这一行为你可以使用
pdflatex等其它工具生成诸如PDF等其他格式的文档
关于如何在本地阅读
HTML格式的文档,请参考
编译内核和SBI:all#
Makfile中定义了 all目标,该目标将会:
编译内核
编译
SBI
make all
编译内核、SBI和文档:full#
Makfile中定义了 full目标,该目标将会:
编译内核
编译
SBI编译文档
make full
运行和调试相关目标#
X2W-OS的 Makefile中提供了直接运行内核、使用 GDB调试内核、使用 VSCode调试内核的目标
直接运行内核:run#
Makefile提供了 run目标,该目标将启动 QEMU运行内核。QEMU的输出信息将输出在终端上。
make run
警告:
当前仅在
Ubuntu上进行了测试,其他类Unix/Linux平台没有进行测试无法在
MacOS上运行,因为:
通过
brew安装的qemu-system-riscv64没有通过所有测试,无法将诸如mret等指令翻译为本地指令(JIT)通过
port安装依赖库后从源码编译QEMU-7.2.0时会因为导入头文件问题报错
GDB调试:debug-gdb#
QEMU支持通过 GDB连接到 QEMU中进行调试,因此 Makefile提供了 debug-gdb目标,以通过 GDB连接 QEMU进行调试。
make debug-gdb
运行该命令后,GDB将在前台运行,而 QEMU将在后台运行。退出时首先按下 Ctrl+C以终止 QEMU,而后输入 quit后按下回车以退出 GDB。
注意:
Makefile将搜索gdb-multiarch或者riscv64-unknown-elf-gdb,你可以通过包管理安装或者手动编译安装如果
Makefile无法找到两个GDB中的任意一个,那么就会报错,而后终止运行
VSCode调试:debug-vscode#
VSCode内嵌入了 UI形式的 GDB。因此诸如函数调用栈、全局变量、寄存器等调试信息非常易于观察,因此 Makefile提供了 debug-vscode实现以通过 VSCode连接 QEMU进行调试
make debug-vscode
此时,QEMU将在前台运行,QEMU的输出信息将输出到屏幕上,并将 GDB端口暴露到本机的 1234端口。
接下来,按照下述步骤配置 VSCode,以能够在 VSCode中调试:
在项目根目录中的
.vscode文件夹下的launch.json文件的configuration项中添加如下配置:{ "name": "GDB Debug", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/build/os.elf", "externalConsole": false, "stopAtConnect": true, "MIMode": "gdb", "miDebuggerArgs": "<本机gdb-multiarch或者riscv64-unknown-elf-gcc的绝对路径", "miDebuggerServerAddress": "<本机IP地址>:1234", "miDebuggerPath": "<本机gdb-multiarch或者riscv64-unknown-elf-gcc的绝对路径>", "cwd": "${workspaceFolder}", }
注意:
GDB的绝对路径可以通过which命令获得<本机IP地址>可以通过运行ifconfig命令查看<本机IP地址>最好写成本机在局域网下的IP地址,不要写成本地回环地址。例如192.168.0.16,而非127.0.0.1:因为
GDB Server可能运行在同一局域网下另外的机器,而VSCode运行在当前机器上若
<本机IP地址>的值设定为127.0.0.1,则VSCode会尝试访问当前机器上的GDB Server(事实上并没有运行),而非同一局域网下的另外的机器此时就无法成功运行
在
VSCode的侧边栏中的运行和调试选项卡下选择GDB Debug调试配置按下
F5启动VSCode中的GDB,即可连接到本机的1234端口开始调试
Miscellaneous目标#
X2W-OS的 Makefile中提供了其他诸多目标以帮助更好的进行开发
反汇编:disasm#
Makfile中定义了 disams目标,该目标将会对 ELF格式的内核和 SBI进行反汇编,从而得到符号表、指令序列以及裸二进制内容。
make disasm
得到的反汇编内容将输出至 build/disasms文件夹下,其中:
反汇编指令序列为:
build/disasms/{os,sbi}.disasm内核符号表为:
build/disasms/{os,sbi}.symbol二进制内容为:
build/disasms/{os,sbi}.machine
阅读文档:read#
为了提升文档阅读体验,Makefile中定义了 read目标,该目标将在本地启动 HttpServer来阅读 Sphinx文档。
make read
将会在后台运行 HttpServer,端口号每次运行时随机指定,按下 Ctrl + C即可终止 HttpServer
注意:
目前
Makefile仅支持运行Python的HttpServer,如果使用诸如node.js的HttpServer,请自行添加
Makefile对Python版本差异进行了屏蔽:
Python2中的HttpServer由SimpleHTTPServer提供
Python3中的HttpServer由http.server提供
q此外,make read默认会阻塞终端,你也可以使用如下命令来避免终端被阻塞。
make read &
注意,
Python,HttpServer的日志信息不会被重定向,因此会依旧输出到终端上,需要用户手动进行重定向。
杀死遗留QEMU、HttpServer进程:kill#
很多时候可能会导致存在遗留的进程:
在使用
GDB调试的时候,可能因为错误的退出方式,导致QEMU进程没有关闭与此类似,可能有时候把
HttpServer进程挂到后台运行忘记关闭……
因此 Makefile提供了 kill命令来杀死遗留的 QEMU、HttpServer和 GDB进程
make kill
清除中间文件:clean#
Makefile提供了 clean目标以清除编译过程中产生的所有的文件
make clean
将会清空 build文件夹和 docs文件夹中的文档。