先来看一个简单的Makefile,我们把它放在目录/boot下,可以用来编译boot.bin和loader.bin。

# Makefile for boot

# Programs, flags, etc.
ASM = nasm
ASMFLAGS = -I include/ # This Program
TARGET = boot.bin loader.bin # All Phony Targets
.PHONY : everything clean all # Default starting position
everything : $(TARGET) clean :
rm -f $(TARGET) all : clean everything boot.bin : boot.asm include/load.inc include/fat12hdr.inc
$(ASM) $(ASMFLAGS) -o $@ $< loader.bin : loader.asm include/load.inc include/fat12hdr.inc include/pm.inc
$(ASM) $(ASMFLAGS) -o $@ $<

以字符#开头的行是注释。=用来定义变量,这里的ASM和ASMFLAGS就是两个变量,要注意的是,使用它们的时候要用$(ASM)和$(ASMFLAGS),而不是它们的原型。

.PHONY暂时不管,来看一下Makefile的最重要的语法:

target : prerequisites
command

上面这样的形式代表两层意思:

1.要想得到target,需要执行命令command。

2.target依赖prerequisites,当prerequisites中至少有一个文件比target文件新时,command才被执行。

比如这个Makefile的最后两行,翻译出来就是:

1.要想得到loader.bin,需要执行“$(ASM) $(ASMFLAGS) -o $@ $<”。

2.loader.bin依赖于以下文件:

a.loader.asm

b.include/load.inc

c.include/pm.inc

d.include/fat12hdr.inc

当它们中至少有一个比loader.bin新时,command被执行。

$@代表target;$<代表prerequisites的第一个名字。联系前面我们说过的$(ASM)和$(ASMFLAGS),这个命令行便等价于:

nasm -o loader.bin loader.asm

在Makefile中我们容易注意到,不但boot.bin和loader.bin两个文件后面有冒号,everything、clean和all后面也有冒号,可是它们3个并不是3个文件,仅仅是动作名称而已。如果运行“make clean”,将会执行“rm -f $(TARGET)”,也即“rm -f boot.bin loader.bin”。

all后面跟着的是clean和everything,这表明如果执行“make all”,clean和everything所表示的动作将分别被执行。下面就是make all执行的结果:

>make all

rm -f boot.bin loader.bin

nasm -I include/ -o boot.bin boot.asm

nasm -I include/ -o loader.bin loader.asm

刚才的关键字.PHONY,其实是表示它后面的名字并不是文件,而仅仅是一种行为的标号。

未完。。。

编译方法:

make image

运行结果:

源码

操作系统开发系列—12.e.Makefile的更多相关文章

  1. 操作系统开发系列—12.f.在内核中添加中断处理 ●

    因为CPU只有一个,同一时刻要么是客户进程在运行,要么是操作系统在运行,如果实现进程,需要一种控制权转换机制,这种机制便是中断. 要做的工作有两项:设置8259A和建立IDT. /*========= ...

  2. 操作系统开发系列—12.c.从Loader加载ELF内核,顺便解释下函数调用过程 ●

    实际上,我们要做的工作是根据内核的Program header table的信息进行类似下面这个C语言语句的内存复制: memcpy(p_vaddr, BaseOfLoaderPhyAddr+p_of ...

  3. 操作系统开发系列—12.g.在内核中设置键盘中断

    8259A虽然已经设置完成,但是我们还没有真正开始使用它呢. 所有的中断都会触发一个函数spurious_irq(),这个函数的定义如下: PUBLIC void spurious_irq(int i ...

  4. 操作系统开发系列—12.d.扩充内核 ●

    现在把esp.GDT等内容放进内核中,我们现在可以用C语言了,只要能用C,我们就避免用汇编. 下面看切换堆栈和GDT的关键代码: ; 导入函数 extern cstart ; 导入全局变量 exter ...

  5. 操作系统开发系列—12.b.从Loader跳入保护模式

    现在,内核已经被我们加载进内存了,该是跳入保护模式的时候了. 首先是GDT以及对应的选择子,我们只定义三个描述符,分别是一个0~4GB的可执行段.一个0~4GB的可读写段和一个指向显存开始地址的段: ...

  6. 操作系统开发系列—12.a.从Loader到内核 ●

    Loader要做两项工作,我们先来做第一项,把内核加载到内存: 1.加载内核到内存. 2.跳入保护模式. 首先编译无内核时: nasm boot.asm -o boot.bin nasm loader ...

  7. 操作系统开发系列—13.g.操作系统的系统调用 ●

    在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是 ...

  8. 操作系统开发系列—11.ELF格式 ●

    ELF文件的结构如下图所示: ELF文件由4部分组成,分别是ELF头(ELF header).程序头表(Program header table).节(Sections)和节头表(Section he ...

  9. 操作系统开发系列—9.Loader

    一个操作系统从开机到开始运行,大致经历“引导—>加载内核入内存—>跳入保护模式—>开始执行内核”这样一个过程.也就是说,在内核开始执行之前不但要加载内核,而且还有准备保护模式等一系列 ...

随机推荐

  1. 计算机中数据实体和数据表示形式(以C#为例)

    摘自网络的一段话: “在程序代码中,可以用多种方式表示数据,十进制.十六进制.八进制都是常用的表示方式,但计算机内部永远就只使用二进制,与你写程序时用什么无关.你说要定义数组int a[10],其中涉 ...

  2. Microsoft Orleans 之 入门指南

    Microsoft Orleans 在.net用简单方法构建高并发.分布式的大型应用程序框架. 原文:http://dotnet.github.io/orleans/ 在线文档:http://dotn ...

  3. ASP.NET MVC动态生成网站菜单及子菜单

    在开发ASP.NET MVC网站时,Insus.NET想实现动态产生网站的主菜单及子菜单. 你需要在网站管理后台管理此2张表(Menu,SubMenu)的信息,添加,删除,编辑,更新等. Sequen ...

  4. js 模块化历程

    作者:吕大豹 网址:http://www.cnblogs.com/lvdabao/p/js-modules-develop.html 这是一篇关于js模块化历程的长长的流水账,记录js模块化思想的诞生 ...

  5. css3代码让页面倾斜

    教大家一个方法使用CSS把整个网页倾斜,代码只有在支持CSS3.0的浏览器上有效果.目前只有IE9以上版本及firefox高版本支持,其它浏览器没有测试.代码如下 body{ -webkit-tran ...

  6. C#执行存储过程的简化

    下面的方法是我在实际开发中摸索出来的,可以在很大程度上简化调用存储过程的代码. 首先来看一下C#调用存储过程的一般过程:1.打开数据库连接SqlConnection:2.生成一个SqlCommand: ...

  7. Swift注释

    Swift 中的普通注释与 Objective-C 中的一致,大概分为以下三种 // 单行注释 何问起 / *  多行注释 hovertree.com */ /// 标记注释1 http://hove ...

  8. 割点和桥---Tarjan算法

    使用Tarjan算法求解图的割点和桥. 1.割点 主要的算法结构就是DFS,一个点是割点,当且仅当以下两种情况:         (1)该节点是根节点,且有两棵以上的子树;         (2)该节 ...

  9. springmvc(4)注解简单了解

    对于我这样的新人来说,因为是刚开始做项目,所以以前的技术不是用的很多,就比如springmvc来说,实际上使用的都是注解形式的,对于那些全部都是配置的来说,虽然也了解一些,但是实际上还是没试用过的. ...

  10. Global和Globals

    $a= '1234'; $a = 'abc'; $GLOBAS['b']='123'; function showVar(){ echo $a;//什么也输不出来 echo $b;//123(全局变量 ...