128 lines
4.2 KiB
ReStructuredText
128 lines
4.2 KiB
ReStructuredText
.. _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)
|
||
|
||
这里和前面一致。大家不需要太关心qemu的更多细节,我们涉及它的操作已经在makefile和sbi之中处理了。
|
||
|
||
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。 |