uCore-Tutorial-Guide-2023S/source/chapter1/2remove-std.rst

136 lines
4.8 KiB
ReStructuredText
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

.. _term-remove-std:
makefile 和 qemu
==========================
.. toctree::
:hidden:
:maxdepth: 5
本节导读
-------------------------------
为了帮助大家进一步理解我们的项目的链接和编译的过程,这里简要介绍一下 makefile 的内容。
.. warning::
注意makefile 在整个实验过程中不可修改,否则可能导致 CI 无法通过!
makefile 内部
----------------------------------
指定编译使用的工具
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: makefile
TOOLPREFIX = riscv64-unknown-elf-
CC = $(TOOLPREFIX)gcc
AS = $(TOOLPREFIX)gas
LD = $(TOOLPREFIX)ld
OBJCOPY = $(TOOLPREFIX)objcopy
OBJDUMP = $(TOOLPREFIX)objdump
GDB = $(TOOLPREFIX)gdb
这里makefile调用了大家设定好的PATH之中的riscv64工具链。如果没有设置好那么之后的编译就会因为找不到这些文件而出错。
添加编译flag
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: makefile
CFLAGS = -Wall -Werror -O -fno-omit-frame-pointer -ggdb
CFLAGS += -MD
CFLAGS += -mcmodel=medany
CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax
CFLAGS += -I.
CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
比较需要注意的是我们设置了警告也会报错,因此大家写代码的时候最好避免 warning 的出现,这是良好的编程习惯。
设置编译目标
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: makefile
# 目录定义
K = os
BUILDDIR = build
# .o 目标的确定,也就是 os 目录下所有的 .c 和 .s 都编译成 .o
C_SRCS = $(wildcard $K/*.c)
AS_SRCS = $(wildcard $K/*.S)
C_OBJS = $(addprefix $(BUILDDIR)/, $(addsuffix .o, $(basename $(C_SRCS))))
AS_OBJS = $(addprefix $(BUILDDIR)/, $(addsuffix .o, $(basename $(AS_SRCS))))
OBJS = $(C_OBJS) $(AS_OBJS)
# kernel 镜像由所有的 .o 按照 kernel.ld 链接而成
$(BUILDDIR)/kernel: $(OBJS) $(K)/kernel.ld
$(LD) $(LDFLAGS) -T kernel.ld -o kernel $(OBJS)
请同学们自行查阅并了解``wildcard````addprefix````addsuffix````basename``的意义。
运行 qemu
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: makefile
QEMU = qemu-system-riscv64
QEMUOPTS = \
-nographic \
-smp $(CPUS) \
-machine virt \
-bios $(BOOTLOADER) \
-kernel kernel
run: $(BUILDDIR)/kernel
$(QEMU) $(QEMUOPTS)
这个就是最关键的地方:make run。我们查看这条指令的结构它首先执行上面 kernel 所需要的链接以及编译操作得到一个二进制的kernel。之后执行按照QEMUOPTS变量指定的参数启动qemu。QEMUOPTS意义如下
- nographic: 无图形界面
- smp 1: 单核 (默认值,可以省略)
- machine virt: 模拟硬件 RISC-V VirtIO Board
- bios $(bios): 使用制定 bios这里指向的是我们提供的 rustsbi 的bin文件。
- kernel 使用 elf 格式的 kernel。
因此qemu会按照上述的参数启动使用我们的rustsbi来进行一系列初始化并将程序计数器移动至0x80200000并开始执行我们的OS。我们之后所有执行测试都是使用的make run指令。
gdb 调试
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: makefile
# QEMU's gdb stub command line changed in 0.11
QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \
then echo "-gdb tcp::1234"; \
else echo "-s -p 1234"; fi)
debug: kernel .gdbinit
$(QEMU) $(QEMUOPTS) -S $(QEMUGDB) &
sleep 1
$(GDB)
使用 make debug 来使用 gdb 调试 qemu。程序自身执行的机制和直接 make run 一样。在解析 bootloader 的行为时可以使用 gdb 在其中添加断点来查看对应寄存器和内存的内容。gdb的具体使用方法和汇编课程上一致。不熟悉的同学可以在训练章节查看到可能用到的gdb指令的简单用法也十分推荐同学们自学一些基础的 gdb 使用方法掌握 gdb 对本课程帮助很大。
LOG 支持
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: makefile
ifeq ($(LOG), error)
CFLAGS += -D LOG_LEVEL_ERROR
else ifeq ($(LOG), warn)
CFLAGS += -D LOG_LEVEL_WARN
else ifeq ($(LOG), info)
CFLAGS += -D LOG_LEVEL_INFO
else ifeq ($(LOG), debug)
CFLAGS += -D LOG_LEVEL_DEBUG
else ifeq ($(LOG), trace)
CFLAGS += -D LOG_LEVEL_TRACE
endif
我们的 log 等级选择是通过 -D 参数来实现的,这也是大家 ``make run LOG=xxx`` 的原理。从这里我们也可以看到 ``LOG`` 的可选值。
.. warngin::
FIX ME:
大家在实际使用中会发现,由于 LOG 是静态编译是就确认的参数,所以如果想要改变 LOG 等级,就需要重新编译几乎所有的源文件。目前在需要改变 LOG 等级的时候需要 make clean 然后重新 make run。