Makefile进阶使用
Makefile有一本手册,按道理来说我应该看手册学习,但是我懒,而且我觉得有那个时间学那么多肯定会忘记的东西还不如玩点游戏来得实在
以这一个Makefile为例,以后我写的Makefile都以这个为模板
#!Makefile
C_SOURCES = $(shell find . -name "*.c")
C_OBJECTS = $(patsubst %.c, %.o, $(C_SOURCES))
S_SOURCES = $(shell find . -name "*.s")
S_OBJECTS = $(patsubst %.s, %.o, $(S_SOURCES))
CC = gcc
LD = ld
ASM = nasm
C_FLAGS = -c -Wall -m32 -ggdb -gstabs+ -nostdinc -fno-pic -fno-builtin -fno-stack-protector -I include
LD_FLAGS = -T scripts/kernel.ld -m elf_i386 -nostdlib
ASM_FLAGS = -f elf -F stabs
all: $(S_OBJECTS) $(C_OBJECTS) link update_image
bochs
.c.o:
@echo 编译代码文件 $< ...
$(CC) $(C_FLAGS) $< -o $@
.s.o:
@echo 编译汇编文件 $< ...
$(ASM) $(ASM_FLAGS) $<
link:
@echo 链接内核文件...
$(LD) $(LD_FLAGS) $(S_OBJECTS) $(C_OBJECTS) -o ymwm_kernel
.PHONY:clean
clean:
$(RM) $(S_OBJECTS) $(C_OBJECTS) ymwm_kernel
.PHONY:update_image
update_image:
sudo mount floppy.img /mnt/kernel
sudo cp ymwm_kernel /mnt/kernel/ymwm_kernel
sleep 1
sudo umount /mnt/kernel
.PHONY:mount_image
mount_image:
sudo mount floppy.img /mnt/kernel
.PHONY:umount_image
umount_image:
sudo umount /mnt/kernel
.PHONY:qemu
qemu:
qemu -fda floppy.img -boot a
.PHONY:bochs
bochs:
bochs
.PHONY:debug
debug:
qemu -S -s -fda floppy.img -boot a &
sleep 1
cgdb -x tools/gdbinit
首先,看
C_SOUrCES=$(shell find . -name "*.c")
这一步使用了shell语句
$(shell 这里是shell语句)
它使用了find语句
使用man find
查看其功能
这个find语句的意思是,在指定目录(当前目录)下查找文件,它的功能有很多,这里使用的是-name
选项
这一步的目的是找出所有的C文件
接下来,C_OBJECTS=$(patsubst %.c, %.o, $(C_SOURCES))
这个patsubst
是makefile里面的常用函数,与其相似的常用函数还有wildcard
、notdir
等
查看此博客:https://blog.csdn.net/clirus/article/details/46990933
- wildcard:搜索值地年目录下的所有特定格式的文件,例如
$(wildcar *c ./*/*.c)
是搜索当前目录下的所有C文件,效果和$(shell find . -name "*.c")
是一样的 - notdir:去除所有的目录信息,和wildcar配合使用
- patsubst:patten substitude的缩写,匹配的意思,
$(patsubst %.c, %.o, $(C_SOURCES))
就是,在C_SOURCES中找到所有的.c结尾的文件,然后替换为.o结尾的文件
接下来指定编译器、链接器与汇编器
然后指定编译参数
Makefile有三个非常有用的变量。分别是$@,$^,$<
代表的意义分别是:
$@
目标文件,$^
所有的依赖文件,$<
第一个依赖文件。
.c.o
代表所有的.o
文件都依赖于.c
文件
在Makefile中,.PHONY
后面的target表示的也是一个伪造的target, 而不是真实存在的文件target,注意Makefile的target默认是文件
它的作用是:如果target名字的文件已经存在,那么指令可以照常执行
看这个博客:
https://www.cnblogs.com/idorax/p/9306528.html
那么,我们可以仿照其写出一个万能makefile:
C_SOURCES = $(shell find . -name "*.c") # 所有C文件
C_OBJECTS = $(patsubst %.c, %.o, $(C_SOURCES)) # C文件对应的目标文件
TARGET = TARGET # 生成的可执行文件的名字
CC = gcc # 编译器
INCLUDE = include
C_FLAGS = -Wall -O2 -I $(INCLUDE) # 编译参数
all: $(C_OBJECTS)
$(CC) $(C_FLAGS) $^ -o $(TARGET)
.c.o:
@echo $(C_FLAGS)
@echo 编译 $@ ...
$(CC) $(C_FLAGS) -c $< -o $@
.PHONY:clean
clean:
$(RM) $(C_OBJECTS) $(TARGET)
.PHONY:remake
remake:
@make clean
@make all
这个简单的makefile足以应付大多数的简单的工程了,只需要做微小的改动就能马上使用