1,Makefile的优化
书里面对C文件到O文件的编译处理的不是很好,每次新增文件都需要自己手动加入。
主要涉及到一些字符处理函数:
1,patsubst
$(patsubst <pattern>,<replacement>,<text>)
功能:查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符
合模式<pattern>,如果匹配的话,则以<replacement>替换。这里,<pattern>可以包括通
配符“%”,表示任意长度的字串。如果<replacement>中也包含“%”,那么,<replacement>
中的这个“%”将是<pattern>中的那个“%”所代表的字串。(可以用“\”来转义,以“\%”
来表示真实含义的“%”字符)
返回:函数返回被替换过后的字符串。用这个函数实现将所有.h文件加上-I 参数。
CFLAGS+=$(patsubst %,-I %,$(INC_DIR))
比如main.h 变成了 -I main.h
2,$(wildcard $(dir)/*.h)
由于在变量的定义和函数引用时,通配符将失效。所以使用wildcard函数,它会展开 PATTERN中的所有文件列表。这里是展开dir路径下全部的H文件。
3,$(foreach <var>,<list>,<text>)
把参数<list>中的单词逐一取出放到参数<var>所指定的变量中,然后再执行<text>所包含的表达式。每一次<text>会返回一个字符串,循环过程中,<text>返回的每个字符串会以空格分隔,最后当整个循环结束时,<text>所返回的全部字符串
所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值。INCLUDE=$(foreach dir,$(INC_DIR),$(wildcard $(dir)/*.h) )
先从INC_DIR将头文件夹目录取到dir变量 ,wildcard又会将该目录下的所以h文件都遍历完。整个字符串又返回给INCLUDE .最后多轮循环,INCLUDE变包含了全部的H文件
4,改进的地方
OBJS:该变量就是指示单个目标文件.O;这里使用了模式匹配函数patsubst,将点C文件匹配出对应的点O文件。从而找到依赖条件。
由于在链接文件时mian函数作为入口函数被链接在0xc0001500虚拟地址上。所以我们必须将main.o作为最终目标的,首要依赖条件。以便mian.o链接到正确位置。
所以我们要在OBJS变量中实现将main.o分离出来。因为便有了变量MAIN,和OBJS_EX
BUILD_DIR = ./build
SRC_DIR=./device ./kernel ./lib ./lib/kernel
INC_DIR=./device ./kernel ./lib ./lib/kernel
ENTRY_POINT = 0xc0001500
AS = nasm
CC = gcc
LD = ld
#替换原工程中的LIB
CFLAGS+=$(patsubst %,-I %,$(INC_DIR))
#LIB = -I lib/ -I lib/kernel -I kernel/ -I device/
ASFLAGS = -f elf
CFLAGS += -Wall -m32 -fno-stack-protector -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS = -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map
#OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \
$(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o \
$(BUILD_DIR)/debug.o $(BUILD_DIR)/memory.o $(BUILD_DIR)/bitmap.o \
$(BUILD_DIR)/string.o
# 获取全部头文件
INCLUDE=$(foreach dir,$(INC_DIR),$(wildcard $(dir)/*.h) )
# 获取全部C文件
SOURCES=$(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.c) )
# 将C文件替换为O文件
OBJS=$(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(SOURCES)))
MAIN=$(findstring $(BUILD_DIR)/main.o,$(OBJS))
OBJS_EX=$(filter-out $(MAIN),$(OBJS))
# 默认路径下的文件搜索 否则在编译o文件时找不到对应的C文件
VPATH=$(SRC_DIR)
# 链接 最终目标
$(BUILD_DIR)/kernel.bin:$(MAIN) $(OBJS_EX) $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o
$(LD) $(LDFLAGS) $^ -o $@
# C代码编译
$(BUILD_DIR)/%.o:%.c $(INCLUDE) | mk_dir
$(CC) -c $< -o $@ $(CFLAGS)
# 编译汇编
$(BUILD_DIR)/kernel.o: kernel/kernel.S
$(AS) $(ASFLAGS) $< -o $@
$(BUILD_DIR)/print.o: lib/kernel/print.S
$(AS) $(ASFLAGS) $< -o $@
.PHONY: mk_dir hd clean all
mk_dir:
mkdir -p $(BUILD_DIR)
hd:
dd if=/home/xxx/program/os_study/project_my/c8/c/build/kernel.bin of=/home/xiot/program/os_study/bochs/hd60M.img bs=512 count=200 seek=9 conv=notrunc
clean:
rm -rf $(BUILD_DIR)
build:$(BUILD_DIR)/kernel.bin
all: mk_dir build hd
debug:
@echo $(OBJS)
@echo $(MAIN)
@echo $(OBJS_EX)
使用方式
在SRC_DIR INC_DIR 分别加入自己工程中的文件夹
make clean #删除build文件夹以及子文件
make all # 完成编译生成kernel.bin 同时hd的目标也会被执行,将kernel.bin写入硬盘中。
注意:hd目标的命令用的是绝对地址。请核对你自己路径地址