Makefile 笔记

最近在写Makefile 中途出了一些错误和Makefile的一些用法, 正好在这里记下, 语言功底太差, 直接上出错的代码。

出自 https://github.com/bedreamer/fdos/

绿色表示解决问题要处理的地方
红色表示出错的地方
蓝色部分为出错的地方及解决方案。
描述:
https://github.com/bedreamer/fdos/blob/master/Makfile
# Makefile for fdos.
# < cuplision@163.com>
# 通过include来包含其他的Makefile相关文件
# config file, auto been generated
include .config
# define exported values.
include .exports

KERNELFILE=KFOOL
# RELEASE=0 release
# RELEASE=1 debug
# RELEASE=2 demon
RELEASE=2
VMDIR=/home/cup/VBoxVMs/fdos/fdos.vbox
CC=gcc
AS=nasm
LD=ld
AR=ar
MAKE=make
MAKEPARAM=--no-print-directory
#MAKEPARAM=
OMIT=-
PWD=pwd
WORKDIR=$(shell pwd)
IMGFILE=$(WORKDIR)/floppy.img
Q=@
#Q=
CFLAGS=-D_KERNEL_ -D_VERSION_=$(RELEASE) -I$(WORKDIR)/$(ARCH)\
        -I$(WORKDIR)/include -Wall -ffreestanding \
       -fno-builtin -fno-builtin-function -fno-stack-protector\
         -z nodefaultlib -I$(WORKDIR)/include/drivers -c 
CCFLAGS+=-D_ARCH_$(ARCH)_
CBUILDIN=-D_BUILDIN_ $(CFLAGS)
# used for some directory.
CPFLAGS=
ASFLAGS+=-I $(WORKDIR)/include/ -I $(WORKDIR)/$(ARCH) -f elf
BINASFLAGS=
# build-in objects.
y-objs=
yobjs-list=$(WORKDIR)/.yobjs
# module objects.
m-objs=
mobjs-list=$(WORKDIR)/.mobjs
# separate objects.
s-objs=
sobjs-list=$(WORKDIR)/.sobjs
# binary objects.
b-objs=
PHONY+=y-objs m-objs s-objs b-objs
EXPORTS+=KERNELFILE VERSION CC AS LD AR MAKE MAKEPARAM OMIT \
        PWD ARCH WORKDIR IMGFILE Q CFLAGS CCFLAGS CMODULE \
        CBUILDIN ASFLAGS BINASFLAGS CPFLAGS yobjs-list mobjs-list\
         sobjs-list
SEP-DIRS=kernel lib $(ARCH)
# must be the last one.
LAST-DIR=boot
SUB-DIRS=drivers fs

all: _all
PHONY+=all _all
# FIXME: maybe there is a better way to refresh objects-list files.
_all:
$(Q)echo ''> $(yobjs-list);echo ''> $(mobjs-list);echo ''> $(sobjs-list);
$(Q)for d in $(SEP-DIRS) $(SUB-DIRS) $(LAST-DIR); do\
  $(MAKE) $(MAKEPARAM) -C $$d all;\
     done
PHONY+=all
clean:
cmd1: $(Q)$(OMIT)rm $(WORKDIR)/$(KERNELFILE) 2>/dev/null;
cmd2: $(Q)$(OMIT)for d in $(SEP-DIRS) $(SUB-DIRS) $(LAST-DIR); do\
cmd3:   $(MAKE) $(MAKEPARAM) -C $$d clean 2>/dev/null;\
     done
# 这里出错了执行make clean时无法执行上面cmd2, cmd3, 后来发现是cmd1执行失败了, 导致make退出,
# 这里的解决办法是忽略执行命令行时出现的错误, 可以通过在命令行前加'-'来实现, 在这里通过$(OMIT) 实现。

PHONY+=clean

image:

            $(Q)$(MAKE) $(MAKEPARAM) -C boot boot-img

PHONY+=image

debug:

           $(Q)$(OMIT)virtualbox --startvm $(VMDIR) --dbg &

           $(Q)$(OMIT)echo "Debuger starting....."

PHONY+=debug

DOEXPORTS=$(EXPORTS)

export $(EXPORTS) DOEXPORTS

# 导出两次环境变量是为了解决子目录中存在递归式Makefile的问题。
.PHONY: $(PHONY)

https://github.com/bedreamer/fdos/blob/master/Rule.make
# if you need a sub-dir Makefile, you can define
# `sub-didrs:=$(somedirs)` in your Makefile before include this rule file.
# define `m-objs:=$(module)` to build a kernel module, depends on m-deps
# so you need define the other value named`m-deps:=$(some-objects` also.
include $(WORKDIR)/.config
# 如果子目录中存在需要使用Makefile, 则在Makfile中定义变量sub-dirs并将需要递归执行make操作的目录初始化至sub-dirs
# this is for sub-dirs Make rule.
ifdef sub-dirs
suball:=sub_all
subclean:=sub_clean

sub_all:
$(Q)$(OMIT)for d in $(sub-dirs); do $(MAKE) $(MAKEPARAM) -C $$d all;done;
PHONY+=sub_all

sub_clean:
$(Q)$(OMIT)for d in $(sub-dirs); do $(MAKE) $(MAKEPARAM) -C $$d clean;done;
PHONY+=sub_clean
endif
# 如果是编译内核模块, 则将该宏定义添加到编译参数中, 其中CPFLAGS为编译的扩展参数。
ifdef m-objs
CPFLAGS+=-D_MODULE_
endif


# for module complire.
$(m-objs) : $(m-deps)

all : $(b-objs) $(s-deps) $(y-deps) $(m-objs) $(suball) $(nothing)
$(Q)$(OMIT)for o in $(y-deps); do PWD=`pwd`; echo $$PWD/$$o >> $(yobjs-list); done;
$(Q)$(OMIT)for o in $(s-deps); do PWD=`pwd`; echo $$PWD/$$o >> $(sobjs-list); done
PHONY+=all

clean: $(subclean)
$(Q)$(OMIT)echo "    RM        `pwd`/{m-objs m-deps y-deps s-deps}"
$(Q)$(OMIT)rm build-in.a $(m-objs) $(m-deps) $(y-deps) $(s-deps);
PHONY+=clean
# 根据扩展名来实现规则的自动匹配, 可以通过.c文件生成.o文件, 或通过.s 文件生成.o文件, make会自动匹配。
%.o : %.c Makefile
$(Q)echo "    CC        `pwd`/$<"
$(Q)$(CC) $(CFLAGS) $(CCFLAGS) $(CPFLAGS) -o $@ $<
%.o : %.s Makefile
$(Q)echo "    ASM         `pwd`/$<"
$(Q)$(AS) $(ASFLAGS) -o $@ $<

# 生成boot-loader文件时无法生成boot.s和loader.s对应的.bin 文件后来发现把下面一行写成了%.bin : %s Makefile
# 忘记了 '%' 和 's'之间少了 '.'

%.bin : %.s Makefile
    $(Q)echo " ASM [BIN] `pwd`/$<"
    $(Q)$(AS) $(BINASFLAGS) -o $@ $<
# kernel module file is a share libary file.
%.ko : $(m-deps) Makefile
    $(Q)echo " LD [M] $@"
    $(Q)$(LD) --shared $(m-deps) -o $@
    $(Q)echo "`pwd`/$@" >> $(mobjs-list); done
# used for multi level Makefile.
.PHONY:$(PHONY)
# you can export some private value in sub-dir also.
# usage: EXPORT+=SOME-VALUE
export $(EXPORT)
# for sub-dir enviroment.
export $(DOEXPORTS)

https://github.com/bedreamer/fdos/blob/master/fs/Makfile
# 通过y-deps 变量指定当前目录中要生成的目标文件
# 同时可以使用sub-dirs 变量指定要递归执行make 的功能。

y-deps:=open.o read.o write.o ioctl.o close.o iname.o mount.o umount.o
sub-dirs:=fat ext ntfs proc rootfs tmpfs

include $(WORKDIR)/Rule.make


https://github.com/bedreamer/fdos/blob/master/drivers/ide/Makfile
$(IDE-CONFIG)-objs:=ide.ko
$(IDE-CONFIG)-deps:=pci.o pciclass.o
# 可以在任意目录中通过sub-dirs来实现递归make
sub-dirs:=i3600 i3800 i3900 i4000 i4100 i4200
include $(WORKDIR)/Rule.make

https://github.com/bedreamer/fdos/blob/master/fs/ext/Makefile
# 通过make中的函数自动生成需要的变量, SRC 变量会被初始化为当前目录下所有扩展名为 .c 的文件名。
# 然后通过patsubst函数.c 替换为 .o

SRCS=$(wildcard *.c)
OBJS=$(patsubst %.c,%.o,$(SRCS))

$(EXTFS-CONFIG)-objs:=ext.ko
$(EXTFS-CONFIG)-deps:=$(OBJS)
include $(WORKDIR)/Rule.make








                
### 关于 Makefile 使用笔记 #### 嵌套 Makefile 提升项目结构管理效率 对于大型项目而言,将不同类型的源文件分类存放在各自的子目录中是一种常见的做法。为了提高项目的可维护性和清晰度,在各个子目录内编写独立的 `Makefile` 文件并采用嵌套方式来构建整个项目是一个不错的选择[^1]。 ```makefile SUBDIRS = subdir1 subdir2 subdir3 all: for dir in $(SUBDIRS); do \ $(MAKE) -C $$dir; \ done ``` 这段代码展示了如何通过循环调用各子目录下的 `Makefile` 来实现多级联编译过程。 #### 获取当前执行中的 Makefile 路径 GNU Make 自动把每次加载的 `Makefile` 文件名按顺序追加至环境变量 `MAKEFILE_LIST` 中。因此可以利用此特性结合其他内置函数轻松获得当前正在运行的 `Makefile` 完整路径及其所在目录位置[^2]: ```makefile mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) cur_dir := $(patsubst %/Makefile,%,$(mkfile_path)) ``` 这里先使用 `abspath` 函数转换成绝对路径形式;再借助 `lastword` 取得列表最后一个元素即为目标 `Makefile` 名字;最后运用 `patsubst` 替换掉字符串结尾部分从而得到父级工作区的位置信息。 #### Override 操作符用于强制覆盖命令行传入参数 当某些特定情况下希望即使用户已经通过命令行指定了某个选项也能够确保内部设定生效,则可以在定义这些特殊配置项之前加上关键字 `override` 。这允许开发者在必要时候绕过外部输入而直接应用预设值[^3]: ```makefile override CFLAGS += -Wall -Wextra ``` 上述语句表示无论外界是否提供了自己的编译器标志集合,最终都会额外附加 `-Wall` 和 `-Wextra` 这两个警告级别开关作为补充条件参与后续处理流程之中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值