一個通用的Makefile


一 makefile的作用

    Makefile是用於自動編譯和鏈接的,一個工程有很多文件組成,每一個文件的改變都會導致工程的重新鏈接,但是不是所有的文件都需要重新編譯,Makefile中記錄有文件的信 息,在make時會決定在鏈接的時候需要重新編譯哪些文件。Makefile的宗旨就是:讓編譯器知道要編譯一個文件需要依賴其他的哪些文件。當那些依賴文件有了改變,編譯器會自動發現最終的生成文件已經過時,而應該重新編譯相應的模塊。 makefile帶來的好處就是—"自動化編譯",一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟件開發的效率。默認的情況下,make命令會在當前目錄下按順序找尋文件名為"GNUmakefile"、"makefile"、"Makefile"的文件,找到了解釋這個文件。當然也可以使用make -f DIR/makefile 來指定用於makefile文件

二 makefile語法簡述

2.1 makefile規則

target ... : dependencies ... 
            command

target目標文件,可以是Object File,也可以是執行文件,還可以是一個標簽 
dependencies就是,要生成那個target所需要的文件或是目標。 
command也就是make需要執行的命令。(任意的Shell命令,可以有若干行)

    這是一個文件的依賴關系,也就是說,target這一個或多個的目標文件依賴於dependencies中的文件,其生成規則定義在command中。dependencies 中如果有一個以上的文件時間要比target文件要新的話,command所定義的命令就會被執行。這就是 Makefile的規則。也就是Makefile中最核心的內容。在Makefile中的命令,必須要以[Tab]鍵開始。

2.2 變量定義

    Makefile中變量的定義一般有兩種: =和:=。 =符號定義的變量叫延時變量,只有在使用的時候才擴展開來; :=符號定義的變量為立即變量,一旦定義就擴展。 使用=定義的變量不能追加新值,使用:=定義的變量可以使用+=追加新值

2.3 文件指示

    在Makefile使用include關鍵字可以把別的Makefile包含進來,這很像C語言的#include,被包含的文件會原模原樣的放在當前文件的包含位置。include的語法是:include <filename> filename可以是當前操作系統Shell的文件模式(可以保含路徑和通配符)

2.4 偽目標

    偽目標並不是一個文件,只是一個標簽,由於偽目標不是文件,所以make無法生成它的依賴關系和決定 它是否要執行。我們只有通過顯示地指明這個目標才能讓其生效。當然,偽目標的取名不能和文件名重名,不然其就失去了偽目標的意義了。當然,為了避免和文件重名的這種情況,我們可以使用一個特殊的標記.PHONY來顯示地指明一個目標是偽目標,向make說明,不管是否有這個文件,這個目標就是偽目標。

2.5 自動化變量

    $<    第一個依賴文件的名稱

    $?    所有的依賴文件,以空格分開,這些依賴文件的修改日期比目標的創建日期晚

    $@    目標的完整名稱

    $^    所有的依賴文件,以空格分開,不包含重復的依賴文件

 三 通用的makefile實例

工程必備:

頂層Makefile 頂層Makefile.build 子目錄Makefile

編譯過程:

    從頂層開始遞歸進入子目錄,當進入到一個目錄的最底層時,開始使用GCC編譯,再將該層的所有.o文件打包成build-in.o,返回它的上一層目錄再遞歸進入子目錄,當編譯完所有的子目錄后,就開始編譯頂層的.c文件,最后將頂層的.o文件和頂層每個子目錄的build-in.o鏈接成我們的目標文件

頂層Makefile解析(隨工程而變):

#----------------------------------------------指定編譯工具鏈---------------------------------------------------

CROSS_COMPILE =                             #指定編譯器種類

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                           #將定義的變量導出,方便其他makefile使用

export STRIP OBJCOPY OBJDUMP                   #將定義的變量導出,方便其他makefile使用

 

CFLAGS := -Wall -O2 -g                                    #編譯器參數

CFLAGS += -I $(shell pwd)/include                     #指定編譯器頭文件(根據實際項目手動修改)

LDFLAGS := -lm -lfreetype -lvga                         #指定編譯器鏈接庫(根據實際項目手動修改)

export CFLAGS LDFLAGS                                #將定義的變量導出,方便其他makefile使用

TOPDIR := $(shell pwd)                                     #獲得當前程序的頂層目錄

export TOPDIR                                                 #輸出頂層目錄

 TARGET := show_file                                      #編譯后的程序名(根據實際項目手動修改)

#-------------------------頂層要生成的.o文件以及頂層文件夾(根據實際項目手動修改)------------------

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    #將編譯好的built-in.o文件鏈接生成我們的目標文件

#------------------------------------------------頂層的清除規則-------------------------------------------------------

clean:

    rm -f $(shell find -name "*.o")                        #刪除所有的.o文件

    rm -f $(shell find -name "*.d")                        #刪除所有的.d文件

    rm -f $(TARGET)                                         #刪除目標文件

.PHONY:all clean

頂層Makefile.build解析(無需改動):

PHONY := __build                                        #定義一個PHONY變量

__build:                                                       #開頭說明__build偽目標,使其成為Makefile.build的第一個目標

obj-y :=                                                        #定義當前目錄的目標變量,初始值為空

subdir-y :=                                                   #定義當前目錄的子目錄變量,初始值為空

include Makefile                                          #將當前目錄的Makefile包含進來,初始化obj-y

                                                                   #obj-y:=a.o b.o c/ d/

__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))   #篩選出當前目錄的目標變量中的子目錄,並且去掉/

                                                                                   #$(filter %/, $(obj-y)):c/ d/

                                                                                   #__subdir-y:c d

subdir-y += $(__subdir-y)                                           #將開始定義的subdir-y賦值為__subdir-y

                                                                                   #subdir-y:c d

subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)  #對於subdir-y里面的每一個值(目錄),增加一個相應的目錄/built-in.o的變量值

                                                                                   #subdir_objs:c/built-in.o d/built-in.o

cur_objs := $(filter-out %/, $(obj-y))                            #得到obj-y中的.o文件

                                                                                   #cur_objs:a.o b.o

dep_files := $(foreach f,$(cur_objs),.$(f).d)                #對於所有的.o文件,定義它的依賴文件名

                                                                                   #dep_files: .a.d .b.d

dep_files := $(wildcard $(dep_files))

ifneq ($(dep_files),)                                                    #根據依賴文件名,判斷依賴文件是否存在,存在就包含就來

    include $(dep_files)

endif

PHONY += $(subdir-y) #將$(subdir-y)也加入到變量PHONY中

--------------------------------------------Makefile. build的第一個規則--------------------------------------------------------------

__build : $(subdir-y) built-in.o                                    #第一個規則

$(subdir-y):                                                                #第一個規則的第一個依賴規則

    make -C $@ -f $(TOPDIR)/Makefile.build              #依次進入該子目錄變量里面存儲的值,使用的Makefile.build進行編譯

 built-in.o : $(cur_objs) $(subdir_objs)                       #第一個規則的第二個依賴規則

      $(LD) -r -o $@ $^                                                 #該規則的命令:將該目錄下的.o和$(subdir_obj)打包成built-in.o文件

dep_file = .$@.d                                                        #

%.o : %.c                                                                   #第一個規則的第二個依賴規則的依賴規則 

$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $<#用於將目錄下所有的.c文件編譯成.o文件

.PHONY : $(PHONY)                                                  #將PHONY聲明為偽目標

 子目錄Makefile(隨工程而變):

子目錄的Makefile就是包含該目錄下所有的目標文件名和子目錄文件夾名。

例如任何一個子目錄可寫成:

objs-y := a.o

objs-y += b.o

objs-y += c/

objs-y += d/

四 示例工程

     http://pan.baidu.com/share/link?shareid=145262&uk=101680913


免責聲明!

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



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