Skip to main content

RTFSC PA Makefile初探

本文是记录我学习pa中makefile和kconfig等的笔记,一直想做这件事,之前没时间,寒假有大把时间了

一.nemu中的Kconfig配置系统

参考链接:RTFSC | 官方文档 (oscc.cc)

我首先从键入make -nB menuconfig | vim -来揭开配置系统的神秘面纱

1.首先menuconfig目标存在于 nemu/scripts/config.mk 文件中,其依赖于三个目标:$(MCONF) $(CONF) $(FIXDEP),并执行$(Q)$(MCONF) $(Kconfig)与$(Q)$(CONF) $(silent) –syncconfig $(Kconfig),来读取nemu/Kconfig文件,来看看gpt对于conf和mconf程序的解释吧!

  1. mconf nemu/Kconfig:
    • 这个命令启动 mconf 程序,并传递 nemu/Kconfig 作为配置文件。
    • mconf 提供一个基于文本的菜单界面,允许用户交互式地选择和配置选项。
    • 用户在 mconf 界面中做出的选择将被写入 .config 文件。这是一个交互式过程,用户可以看到不同的配置选项,并根据需要进行选择。
  2. conf –syncconfig nemu/Kconfig:
    • 这个命令执行 conf 程序,使用 –syncconfig 选项处理 nemu/Kconfig 文件。
    • –syncconfig 选项的作用是同步配置文件。它基于 .config 文件和 Kconfig 文件的内容,确保所有依赖和条件都被正确处理,并更新 .config 文件。
    • 这一步是必要的,因为可能存在一些依赖关系或条件选项,用户在 mconf 界面中所做的选择可能需要进一步的调整或补充。conf –syncconfig 确保所有配置都是一致和正确的。

所以,即使 mconf 程序可以让用户在界面中选择配置并写入 .config 文件,conf –syncconfig 仍然是必要的,以确保所有的配置选项和依赖关系都被正确处理。简而言之,mconf 负责用户的交互和初步配置,而 conf –syncconfig 负责确保最终的配置文件是完整和一致的。

也就是mconf程序写入用户配置,conf –syncconfig来确保同步,但是conf程序好像还会生成一些其他的文件,和linux内核的conf程序好像不一样,具体会生成文件为(以下来自pa文档):

  • 运行命令conf –syncconfig nemu/Kconfig, 此时conf将会解析nemu/Kconfig中的描述, 并读取选择结果nemu/.config, 结合两者来生成如下文件:
    • 可以被包含到C代码中的宏定义(nemu/include/generated/autoconf.h), 这些宏的名称都是形如CONFIG_xxx的形式
    • 可以被包含到Makefile中的变量定义(nemu/include/config/auto.conf)
    • 可以被包含到Makefile中的, 和”配置描述文件”相关的依赖规则(nemu/include/config/auto.conf.cmd), 为了阅读代码, 我们可以不必关心它
    • 通过时间戳来维护配置选项变化的目录树nemu/include/config/, 它会配合另一个工具nemu/tools/fixdep来使用, 用于在更新配置选项后节省不必要的文件编译, 为了阅读代码, 我们可以不必关心它

2.具体对conf,mconf,fixdep的构建是通过make的-C选项调用其各自的Makefile(存在于nemu/tools/kconfig和/nemu/tools/fixdep文件夹下),其各自的makefile主要是设置SRCS变量和NAME变量,最后include scripts/build.mk文件来完成具体的编译链接过程,所以这也是抽象的思想,将编译链接具体的操作抽象,类似于函数吧,只需要传入相应的配置,写一个通用的构建模板,就无需重复劳动了,并且十分优雅。

构建这三个程序的代码应该是linus大神写的,每个文件都是上千行,(之后阅读内核代码时应该会拜读,现在实力不够),但是应该有所改动,为了生成autoconfig.h文件等。

二.nemu的Makefile

1.首先进行sanity check,通过检查是否存在nemu_main.c来检测NEMU_HOME变量是否正确

2.包含menuconfig自动生成的一些变量文件(auto.conf(.cmd))

3.定义一个删除双引号的函数remove_quote,使用了patsubst函数

4.通过此函数提取auto.config的某些变量来设置GUEST_ISA,ENGINE,NAME变量

5.包含filelist.mk(shell find),里面根据menuconfig的结果来选择要编译的文件

6.过滤掉某些不需要的文件(filter-out函数),生成最终需要编译的文件集合

7.提取config文件中的某些变量来设置编译选项,cflag,ldflag。

8.包含包含了menuconfig目标和编译规则的mk文件(也就是本文章的第一个板块介绍的)

9.最后包含编译nemu的规则的mk文件,$(NEMU_HOME)/scripts/native.mk

总结:上述主要包含几个步骤,完整性检查,通过menuconfig的结果来设置一些基本变量,比如isa,name,cflag等,包含menuconfig和编译运行的mk文件

附:对native.mk的解读:

1.包含build.mk,用于编译链接生成ELF

2.设置ARGS,img变量

3.run目标启动nemu($(BINARY) $(ARGS) $(IMG)),当然,得先编译链接为binary文件,参数在上层makefile中设置完毕,即SRCS和NAME变量,当然还有一些编译flag。

nemu总结

基本上,编译都是依靠build.mk这个文件,这个文件类似于一个函数,他需要正确设置SRCS和NAME的值,然后就是一个文件一个文件的编译,最后链接^-^

三.abstract machine的Makefile

看这个makefile是一个必做题,但是一个160行的makefile实在不好读啊,变量什么的太繁杂了。(我几乎每句代码都要丢到gpt中帮我解释)

1.检测MAKECMDGOALS这个特殊变量来判断在命令行中是否指定了一个目标,如果没有就设置默认目标为image

2.在目标不是clean等此类没什么用的目标时,开始接下来的检查

  • 打印一条包含NAME(一般是程序,类似dummy),目标,架构的信息
  • 检查AM_HOME环境变量设置是否正确
  • 检查am是否支持你输入的ARCH(将ARCH与$(AM_HOME)/scripts下的文件名进行对比)
  • 提取ARCH中的信息,设置ISA和PLATFORM变量
  • 检查SRCS变量是否被定义(flavor函数查看类型与undefine对比),SRCS和NAME变量应该是需要传入的变量,SRCS即是需要编译的程序路径(类似dummy.c)

3.创建一系列需要构建的目标(里面变量过于繁杂,不详述了)

4.设置一系列的编译flag,包括cross complier,flag等

5.包含架构相关的.mk文件,并检查你是否有相应的cross complier,如果没有就用gcc

6.定义一系列构建规则(说实话,我有点混乱了在这几步,之后变强了要再来看一遍)

7.之后就是一系列的clean之类的目标了(没仔细看,看不下去了,give up了)

当然真正的run目标在scripts/platform/下面的mk文件中(架构相关文件)

因为直接看Makefile让我有点混乱,我决定再make -nB看一下(即在cpu-test的makefile中修改),反正对于nemu和cpu-test来说,整个过程就是

1.交叉编译程序(类似dummy.c)

2.编译am文件并压缩至.a链接文件

3.编译klib文件并压缩至.a链接文件

4.用特定的链接脚本链接三者

总结

发表一下感慨,感觉am的makefile超级复杂,复杂之中有有条理,才能让整个编译过程不出一丝错误,难以想象余老师在写这些makefile时花了多少心思,花了多少时间debug^-^,我现在只是对整体的makefile进行了粗略的浏览,有些地方还看不太懂,希望之后能再多看几遍。

在看了一下jyy的os课程之后,越来越发现这个am这个项目的牛逼之处,am相当于是使我们编写的普通c代码程序能直接在裸机上运行,包括qemu,nemu,npc等等,甚至qemu还为他编写了bootloader等程序,所以他的makefile才显得如此的重要