时间/log/参数传递和makefile全自动编译

项目工程

Posted by Bruce Lee on 2024-08-08

关于我

欢迎来到我的博客!这里汇集了我对编程和技术的洞见和总结。本站内容分为几个主要类别,涵盖从具体技术实现到编程理念的广泛话题。

主要内容分类

  • 项目工程:深入探讨技术的实现细节和理解。
  • C/C++:围绕C/C++语言的技术点和编程技巧进行详细总结。
  • 程序员哲学:分享程序员在职业生涯中应该具备的哲学理念和思考方式。

想要了解更多具体内容,您可以访问文章分类页面。

联系我

如果您有任何问题或想要交流,欢迎通过关于页面与我联系。

感谢您的阅读和支持,希望我的博客能为您的技术旅程带来帮助!


总体概览

init_rand()

该函数定义在timer.c文件中,条件包含了sys/time.h和time.h头文件

前者用于获取精确时间的获取和计算

timeval用来表示秒,gettimeofday函数获取当前时间

get_time函数返回了now - boot_time的时间,应该是一个间隔时间

后者主要是获取处理器时间,计算时间差.

这个文件对于评估程序的运行很重要

init_log

调用了init_log函数,传入了log_file参数,这个参数在monitor.c中全局定义:

1
static char *log_file = NULL;

在log.c文件中定义了init_log函数,这里就是做初始化工作,并且打印相关的信息,目标写入文件.

init_log函数中,还做了一层防护:如果log_file文件打开失败,那么就输出到stdout中,并不中断程序.这也映射了强大的程序,是尽量不宕机的,近可能的处理好错误,然后回归到正确的任务上去.

在am中的nemu.mk中,NEMUFLAGS追加了-l参数,并且给出了nemu-log.txt的位置

init_isa

将img拷贝到客机地址RESET_VECTOR中.

guest_to_host得到的是实际分配的物理地址.

在这里得到的就是在paddr.c中全局定义的pmem数组的首地址.

memcpy函数会将这个默认的img拷贝到pmem数组中

img是客户程序,而一般呢,我们的img是可以改变的,加载不同的img

然后调用restart函数.

restart函数是直接将cpu.pc置为RESET_VECTOR.

然后继续将cpu.gpr[0]保持为0.

load_img函数

在init_isa函数之后,也就是说,如果传参为1,那么就会有fread函数,将pmem首地址开始往后的内容覆写新的img.

使用了fseek(fp, 0, SEEK_SET)来从img文件头开始读取.

这里的SEEK_SET是头文件提供的宏,用来表示是从文件头,当前,末尾开始读.

这里读取多少呢,我们怎么知道客户程序的大小呢?

fread的参数,size是大小,第三个参数是个数.如果大小为1字节,个数为n.

那么我们就自己束缚自己了,因为我们并不知道客户程序的n是多少.

那我们可以设法将个数设置为1,大小呢,就设置为整个img那么大就好了.

1
2
fseek(fp, 0, SEEK_END);
long size = ftell(fp);

再看parse_args函数

看到getopt_long函数,就想起来以前在宿舍攻破这个相关库的时候.

多个参数传递, 这里只关注传参1

img_file是monitor.c全局定义的char*类型

如果getopt_long的返回值是1的话,那么img_file就会从optarg中获得一个字符串,这个字符串就是img file的名称,然后交给load_img函数.

关于在am中的Makefile是如何传入参数,以及如何编译,在nemu中又是怎样不同的,我很感兴趣.

am的makefile的1参数传递.

make ARCH=riscv32-nemu ALL=add run 和make ARCH=riscv32-nemu run的区别

表面区别很简单,makefile1是如何实现的呢?

左边的很好解释,我们需要ALL变量,并且给出一个源文件名,如果不给ALL变量,那么makefile1就默认会执行测试所有的程序.

1
ALL = $(basename $(notdir $(shell find tests/. -name "*.c")))

查找所有.c文件,去除目录名,去除后缀

这里有一个问题,make工具是如何做到,将所有的.c文件都单独的自动的执行一遍.

顶级makefile手法,自动独立编译,执行所有的源测试代码文件

首先在cpu-tests目录下的makefile中,ALL目标是一个很巧妙的东西.

这里的ALL跟之前我自己编写的简陋makefile不一样,我的是直接将源文件全名作为ALL中的一部分.

这里是经过了:

1
ALL = $(basename $(notdir $(shell find tests/. -name "*.c")))

将所有的.c文件,脱去了衣服和尾巴,只有基础名字.

然后all目标,将所有的源程序基础名都加了Makefile.前缀

为何呢,这是为了生成一个新的名字,这个名字将来会作为一个文件名,而这个文件名,就是每一个Makefile.源程序基础名的makefile文件

并且在Makefile.目标下,依赖所有的.c文件,和latest目标(这个是遗留的,用于扩展的,目前没有任何内容)

Makefile.的make命令是所有的灵魂:
向独立的Makefile.源文件基础名写入"NAME = $“/nSRCS = $</ninclude $${AM_HOME}/Makefile”

这就将创建一个独立的编译makefile.

然后进行make编译,并且写下关键的信息到RESULT变量中.

然后删除掉Makefile.源文件基础名

要理解这里,必须理解依赖关系.

由于all命令依赖Makefile.$(ALL)

而这个ALL依赖所有的源文件

所有all依赖所有的Makefile.源文件基础名

make all之后,便会挨个编译执行所有的Makefile.源文件基础名.

为何会"挨个",什么命令给出让make工具挨个执行的,并没有给出循环结构呀?

这就是依赖关系,由于依赖所有的Makefile.源文件基础名,所有在处理完其中一个之后,便会继续处理下一个.

这里的Makefile.%便是代表所有的文件,然后处理过程中,是先处理完一个,再处理下一个.而不是先对一个文件执行一条命令,所有文件挨个执行完之后,再开始下一个命令.而这个依赖关系对应的命令是连贯的.

这种依赖关系的处理方式确保了所有的.c文件被编译和执行

这里还需要继续理解,如何编译的呢

生成的Makefile文件内容有NAME,SRCS,和一个include语句

这里的include语句就是包含了一个通用makefile文件-am的makefile

在am中的makefile,有NAME目标,有SRCS目标

在生成的makefile中,这里的NAME和SRCS都是单一目标,所有可以单独编译执行.


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. All the images used in the blog are my original works or AI works, if you want to take it,don't hesitate. Thank you !