編寫一個通用的Makefile文件


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,.$@.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)

通用Makefile


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM