Makefile for boot
Makefile
# Makefile for boot
# Programs, flags, etc.
ASM = nasm
ASMBFLAGS =
# This Program
TARGET = bootsec.com
# All Phony Targets
.PHONY : everything clean all
# Default starting position
everything : $(TARGET)
clean :
rm -r $(TARGET)
all : clean everything
bootsec.com : bootsec.asm
$(ASM) $(ASMBFLAGS) -o $@ $<
Makefile对格式有要求:每一行文本除非顶头开始,如果需要格式编排,不能使用空格键来控制文本行缩进,必须使用Tab键。我们严格一些,全部使用tab建进行文本行缩进。

这样,执行make,效果:

修改目标文件路径:tutor-os/build,保持源码目录干净。
# Makefile for boot
# Programs, flags, etc.
ASM = nasm
ASMBFLAGS =
# This Program
TARGET = ../build/bootsec.com
# All Phony Targets
.PHONY : everything clean all
# Default starting position
everything : $(TARGET)
clean :
rm -r $(TARGET)
all : clean everything
../build/bootsec.com : bootsec.asm
$(ASM) $(ASMBFLAGS) -o $@ $<
Makefile说明
以字符#开头的行是注释。
=用来定义变量。
这里ASM和ASMFLAGS就是两个变量。使用它们的时候需要用$(ASM)和$(ASMFLAGS),而不是它们的原型。
Makefile最重要的语法:
target : prerequisites
command
就是上面的
../build/bootsec.com : bootsec.asm
$(ASM) $(ASMBFLAGS) -o $@ $<
上面的行是表示两层意思:
1、要想得到target,需要执行命令command;
2、target依赖于prerequisites,当prerequisites中至少有一个文件比target文件新时,command才被执行。
(所以上面,执行完make后,紧接着再执行make的时候,会提示Nothing to be done...)
比如这个Makefile的最后两行,翻译出来就是:
1、要想得到../bulid/bootsec.com,需要执行命令(ASMBFLAGS) -o
<
2、../bulid/bootsec.com依赖于bootsec.asm,当bootsec.asm比../bulid/bootsec.com新时,command被执行。
那么$(ASM) $(ASMBFLAGS) -o $@ $<是什么呢?
<表示target和prerequisites的第一个名字,因此,这个命令便等价于:
nasm -o ../build/bootsec.com bootsec.asm
everything、clean、all是3个动作名称。
如果运行make clean, rm -f $(TARGET)这个命令将会被执行,相当于rm -f ../build/bootsec.com。(后面的编译命令不会执行!!!)
all 后面跟着的是clean和everything,这表明如果我们执行make all,clean和everything所表示的所有的动作都会被执行。

.PHONY也是一种行为的标号。
直接输入
make,这时make程序会从我们第一个名字所代表的动作开始执行。在本例中,第一个标号时everything,所以make和make everything是一样的。
Makefile for loader
# Makefile for loader
# Programs, flags, etc.
ASM = nasm
ASMBFLAGS =
# This Program
TARGET = ../build/loader.com
# All Phony Targets
.PHONY : everything clean all
# Default starting position
everything : $(TARGET)
clean :
rm -r $(TARGET)
all : clean everything
../build/loader.com : loader.asm
$(ASM) $(ASMBFLAGS) -o $@ $<
Makefile for lib,仅编译成.o
#Makefile for lib
#
# tutor-os/lib:在内核编程中是不能用C语言标准库函数,这里的lib目录下的库函数就是用来替代那些标准库函数的。
#
# 对外提供的函数功能有
# string.h (字符串操作)
# int strlen(const char * s); string.c
# char * strcpy(char * dst, const char *src); string.c
# extern void* memcpy(void* pDst, void* pSrc, int iSize); _string.asm
# PUBLIC int sprintf(char *buf, const char *fmt, ...); vsprintf.c
#
# print.h (屏幕打印功能)
# PUBLIC void print_str(char * info); print_str.asm
# PUBLIC void print_str_fix_pos(int pos, char * info); print_str.asm
# PUBLIC void print_color_str(char * info, int color); print_str.asm
#
# 生成的中间文件是:lib.a
#
#
ASM = nasm
ASMFLAGS = -f elf
CC = gcc
CFLAGS = -m32 -nostdinc -I ../include/string -fno-stack-protector -fno-builtin -c
# This Program
OBJS = ../build/objs/_string.o \
../build/objs/string.o \
../build/objs/vsprintf.o \
../build/objs/print_str.o
.PHONY : everything clean all
# 默认起始位置
everything : $(OBJS)
clean :
rm -r $(OBJS)
all : clean everything
### Dependencies:
#lib/string
../build/objs/_string.o : ./string/_string.asm
$(ASM) $(ASMFLAGS) -o $@ $<
../build/objs/string.o : ./string/string.c ../include/string/string.h
$(CC) $(CFLAGS) -o $@ $<
../build/objs/vsprintf.o : ./string/vsprintf.c ./string/stdarg.h ../include/string/string.h
$(CC) $(CFLAGS) -o $@ $<
#lib/.
../build/objs/print_str.o : ./print_str.asm
$(ASM) $(ASMFLAGS) -o $@ $<
Makefile for lib,生成静态库文件
# Makefile for lib
#
# tutor-os/lib:在内核编程中是不能用C语言标准库函数,这里的lib目录下的库函数就是用来替代那些标准库函数的。
#
# 对外提供的函数功能有
# string.h (字符串操作)
# int strlen(const char * s); string.c
# char * strcpy(char * dst, const char *src); string.c
# extern void* memcpy(void* pDst, void* pSrc, int iSize); _string.asm
# PUBLIC int sprintf(char *buf, const char *fmt, ...); vsprintf.c
#
# print.h (屏幕打印功能)
# PUBLIC void print_str(char * info); print_str.asm
# PUBLIC void print_str_fix_pos(int pos, char * info); print_str.asm
# PUBLIC void print_color_str(char * info, int color); print_str.asm
#
# 生成的中间文件是:lib.a
#
#
ASM = nasm
ASMFLAGS = -f elf
CC = gcc
CFLAGS = -m32 -nostdinc -I ../include/string -fno-stack-protector -fno-builtin -c
AR = ar
# This Program
OBJS = ../build/objs/_string.o \
../build/objs/string.o \
../build/objs/vsprintf.o \
../build/objs/print_str.o
LIBS = ../build/libs/lib.a
.PHONY : everything clean all
# 默认起始位置
everything : $(LIBS)
clean :
rm -r $(OBJS)
all : clean everything
### Dependencies:
# lib/string
../build/objs/_string.o : ./string/_string.asm
$(ASM) $(ASMFLAGS) -o $@ $<
../build/objs/string.o : ./string/string.c ../include/string/string.h
$(CC) $(CFLAGS) -o $@ $<
../build/objs/vsprintf.o : ./string/vsprintf.c ./string/stdarg.h ../include/string/string.h
$(CC) $(CFLAGS) -o $@ $<
# lib/.
../build/objs/print_str.o : ./print_str.asm
$(ASM) $(ASMFLAGS) -o $@ $<
# 生成lib.a
$(LIBS): $(OBJS)
$(AR) rcs $(LIBS) $(OBJS)
Makefile for kenel,当前只有protect子目录
# Makefile for kernel
#
# tutor-os/kernel:内核代码。
#
# 对外提供的函数功能有:(提供给init模块使用)
# include/protect.h
# // GDT
# PUBLIC void relocate_gdt();
# PUBLIC void print_descriptor();
# // IDT
# PUBLIC void init_idt();
#
#
ASM = nasm
ASMFLAGS = -f elf
CC = gcc
CFLAGS = -m32 -nostdinc -I ../include -fno-stack-protector -fno-builtin -c
AR = ar
# This Program
OBJS = ../build/objs/_interrupt.o \
../build/objs/interrupt.o \
../build/objs/io.o \
../build/objs/protect.o
LIBS = ../build/libs/kernel_protect.a
.PHONY : everything clean all
# 默认起始位置
everything : $(LIBS)
clean :
rm -r $(OBJS)
all : clean everything
### Dependencies:
# kernel/protect
../build/objs/_interrupt.o : ./protect/_interrupt.asm
$(ASM) $(ASMFLAGS) -o $@ $<
../build/objs/interrupt.o : ./protect/interrupt.c ../include/type.h ../include/const.h ../include/protect.h ../include/string.h ../include/vsprintf.h ../include/print.h
$(CC) $(CFLAGS) -o $@ $<
../build/objs/io.o : ./protect/io.asm
$(ASM) $(ASMFLAGS) -o $@ $<
../build/objs/protect.o : ./protect/protect.c ../include/type.h ../include/const.h ../include/protect.h ../include/string.h ../include/vsprintf.h ../include/print.h
$(CC) $(CFLAGS) -o $@ $<
# 生成../build/libs/kernel_protect.a
$(LIBS): $(OBJS)
$(AR) rcs $(LIBS) $(OBJS)
Makefile for init
# Makefile for init
#
# tutor-os/init:内核启动代码。
#
ASM = nasm
ASMFLAGS = -f elf
CC = gcc
CFLAGS = -m32 -nostdinc -I ../include -fno-stack-protector -fno-builtin -c
AR = ar
# This Program
OBJS = ../build/objs/_start.o \
../build/objs/cstart.o \
.PHONY : everything clean all
# 默认起始位置
everything : $(OBJS)
clean :
rm -r $(OBJS)
all : clean everything
### Dependencies:
# kernel/protect
../build/objs/_start.o : ./_start.asm
$(ASM) $(ASMFLAGS) -o $@ $<
../build/objs/cstart.o : ./cstart.c ../include/type.h ../include/const.h ../include/protect.h ../include/string.h ../include/vsprintf.h ../include/print.h
$(CC) $(CFLAGS) -o $@ $<
Makefile for root,根目录下,主要是调用子目录的Makefile,然后链接生成kernel.bin
# Makefile for root
#
# 1、调用其他Makefile文件,生成objs和lib
# 2、连接生成目标文件
LD = ld
LDFLAGS = -m elf_i386 -s -Ttext 0x30400
# This Program
TARGET = ../build/bootsec.com \
../build/loader.com \
../build/kernel.bin
LIBS = ../build/libs/lib.a \
../build/libs/kernel_protect.a \
OBJS = ../build/objs/_start.o \
../build/objs/cstart.o
.PHONY : everything clean all
# 默认起始位置
everything : $(TARGET)
clean :
rm -r $(TARGET)
all : clean everything
### Dependencies:
# boot & loader
../build/bootsec.com :
(cd ./boot; make)
../build/loader.com :
(cd ./loader; make)
# 生成lib
../build/libs/lib.a :
(cd ./lib; make)
../build/libs/kernel_protect.a :
(cd ./kernel; make)
# 生成objs
../build/objs/_start.o :
(cd ./init; make)
../build/objs/cstart.o :
(cd ./init; make)
# 生成kernel.bin
../build/kernel.bin : $(LIBS) $(OBJS)
$(LD) $(LDFLAGS) -o ./build/kernel.bin ./build/objs/cstart.o ./build/objs/_start.o ./build/libs/kernel_protect.a ./build/libs/lib.a
$(LD) $(LDFLAGS) -o ./build/kernel.bin ./build/objs/cstart.o ./build/objs/_start.o ./build/libs/kernel_protect.a ./build/libs/lib.a注意顺序!!!
gcc在链接静态库时是从前往后找符号。因此如果一份文件foo引用了静态库bar.a,那么在链接命令中,bar.a必须放在foo的后面,也就是像gcc ... foo ... bar.a这样;否则链接时会报找不到定义的错误(即undefined reference to ...)。
make.bat,在windows上调用wsl,调用make命令
wsl (cd /mnt/c/Users/zkai/Desktop/OsDevLab/tutor-os; make)
pause