1.1在这之前,我们需要了解程序的编译过程
a.预处理:检查语法错误,展开宏,包含头文件等
b.编译:*.c-->*.S
c.汇编:*.S-->*.o
d.链接:.o +库文件=*.exe
1.2体验在VC下程序的编译
a.先编译,在链接
b.修改了哪个文件,就单独编译此文件,在链接
c.修改了哪个头文件,就单独编译使用该头文件的源文件,在链接
1.3在linux下实现上述要求
2.编写一个测试的Makefile
2.1直接编译链接
gcc -o test a.c b.c
缺点:改变其中一个文件,还需要重新编译所有文件,最后链接,效率低
2.2编写一个通用的Makefile
核心:规则
目标:依赖1 依赖2...
命令
命令的执行条件:
a.依赖文件比目标文件新
b.没有目标文件
2.2.1一个简单的Makefile文件
test:a.c b.c a.h
gcc -o test a.c b.c
缺点:当其中一个文件发生改变时,另一个文件又将从新编译链接
2.2.2针对上述,改为如下
test:a.o b.o
gcc -o test a.o b.o a.o : a.c
gcc -c -o a.o a.c b.o : b.c
gcc -c -o b.o b.c
缺点:a.如果test依赖于多个文件,将写许多代码。
b.修改a.h程序没有反应。
2.2.3
针对上述a,可将其改为通配符;针对b,可增加“a.o:a.c a.h”这段代码。
$@:表示目标;$^:表示全部依赖;$<:第一个依赖。
test:a.o b.o
gcc -o test a.o b.o a.o:a.c a.h %.o : %.c
gcc -c -o $@ $<
缺点:如果一个文件的头文件非常多,不可能一个一个列出来,应该生成一个依赖文件。
2.2.4生成依赖文件
wildcard:检查文件是否存在
-Wp,-MD:生成依赖文件
objs := a.o b.o test:$(objs)
gcc -o test $^ # .a.o.d .b.o.d
dep_files := $(foreach f,$(objs),.$(f).d)//对于objs里的每个文件,生成对应的依赖文件。eg:a.o-->.a.o.d
dep_files := $(wildcard $(dep_files)) ifneq ($(dep_files),)
include $(dep_files)
endif %.o : %.c
gcc -Wp,-MD,.$@.d -c -o $@ $< clean:
rm *.o test
3.参照内核的Makefile和上述的test_Makefile,编写一个通用的Makefile
3.1子目录下的Makefile
它最简单,形式如下:
obj-y += file.o
obj-y += subdir/
"obj-y += file.o"表示把当前目录下的file.c编进程序里,
"obj-y += subdir/"表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。
注意: "subdir/"中的斜杠"/"不可省略
3.2顶层目录的Makefile:
它除了定义obj-y来指定根目录下要编进程序去的文件、子目录外,主要是定义工具链、编译参数、链接参数──就是文件中用export导出的各变量。
CROSS_COMPILE = arm-linux- //交叉编译工具链
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump export AS LD CC CPP AR NM //导出变量
export STRIP OBJCOPY OBJDUMP CFLAGS := -Wall -O2 -g //编译选项
CFLAGS += -I $(shell pwd)/include LDFLAGS := -lm -lfreetype //链接选项 export CFLAGS LDFLAGS TOPDIR := $(shell pwd)
export TOPDIR TARGET := show_file obj-y += main.o
obj-y += display/
obj-y += draw/
obj-y += encoding/
obj-y += fonts/ all :
make -C ./ -f $(TOPDIR)/Makefile.build //打开文件,按照顶层目录下的Makefile.build来编译
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o //link clean:
rm -f $(shell find -name "*.o")
rm -f $(TARGET) distclean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)
3.3顶层目录的Makefile.build:
这是最复杂的部分,它的功能就是把某个目录及它的所有子目录中、需要编进程序去的文件都编译出来,打包为built-in.o。
PHONY := __build
__build: obj-y :=
subdir-y := include Makefile
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o) cur_objs := $(filter-out %/, $(obj-y))
dep_files := $(foreach f,$(cur_objs),.$(f).d)
dep_files := $(wildcard $(dep_files)) ifneq ($(dep_files),)
include $(dep_files)
endif PHONY += $(subdir-y) __build : $(subdir-y) built-in.o $(subdir-y):
make -C $@ -f $(TOPDIR)/Makefile.build built-in.o : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^ dep_file = .$@.d %.o : %.c
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $< .PHONY : $(PHONY)