1.1在這之前,我們需要瞭解程式的編譯過程 a.預處理:檢查語法錯誤,展開巨集,包含頭文件等 b.編譯:*.c-->*.S c.彙編:*.S-->*.o d.鏈接:.o +庫文件=*.exe 1.2體驗在VC下程式的編譯 a.先編譯,在鏈接 b.修改了哪個文件,就單獨編譯此文件,在鏈接 c.修改了哪個 ...
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直接編譯鏈接
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,[email protected] -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 = [email protected] %.o : %.c $(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $< .PHONY : $(PHONY)