linux之Makefile 編寫、規則、偽目標、變量


  什么是Makefile?首先,make是一個工具程序(Utility software),是一種控制編譯或者重復編譯軟件的工具;make可以自動管理軟件編譯的內容、方式和時機從而使程序員能夠把精力集中在編寫代碼上。那make怎樣工作呢?其實make是通過makefile文件實現的。makefile是一個文本形式的數據庫文件。其中包含一些規則,這些規則告訴make需要編譯哪些文件、怎樣編譯這些文件以及在什么樣的條件下去編譯。

  關於Makefile的基本規則:

target: dependency [dependency [...]]
           command
           command
           [...]
每個命令的第一個字符必須是制表符,使用空格代替是不正確的。

其中,target是需要創建的二進制文件或目標文件,雖然目標體通常是程序,但它們也可以是文本文件、手冊頁面等任何東西甚至可以被用作測試和設置環境變量。dependency是在創建target時需要輸入的一個或者是多個文件的列表。命令序列是創建target文件所需的步驟,如編譯命令。一般,沒有特殊指定的情況下,make的工作目錄就是當前的目錄。當GNU make被調用時會順序查找名為GNUmakefile、makefile或者是Makefile的文件,但不知出於於某種不可描述的原因,絕大部分的Linux程序員習慣性的使用 Makefile這種形式。 

  簡單的makefile寫法:

 首先有這么幾個簡單的程序 howdy.c helper.h helper.c

 howdy.c

#include<stdio.h>
#include"helper.h"
int main()
{
        printf("hello,linux programming world\n");
        msg();
        return 0;
}

頭文件 helper.h

void msg(void);

helper.c

#include<stdio.h>
void msg(void)
{
        printf("This message sent form helper.c .\n");
}

 好了,利用上述的這些程序寫一個簡單的Makefile文件

    

howdy:howdy.o helper.o helper.h
        gcc howdy.o helper.o -o howdy
helper.o:helper.c helper.h
        gcc -c helper.c 
howdy.o:howdy.c
        gcc -c howdy.c
clean:
        rm howdy *.o

要編譯howdy,只要在Makefile目錄下鍵入make即可。第一個目標體howdy稱為默認(default)目標體--這就是該Makefile文件要創建的文件。howdy有三個依賴體,分別為howdy.o helper.o helper.h;要生成howdy這個文件就必須要他所依賴的這三個文件。第二行就是調用編譯器的命令來供make執行來創建howdy文件,其中helper.h也列入依賴體的原因是為了防止編譯器調用未申明的函數產生錯誤。接下來的規則是告訴make怎樣生成單個目標文件:helper.o和howdy.o。這兩個規則用了gcc -c選項,其含義為只編譯但不鏈接文件。

    嗯,,,大概的編譯鏈接過程就是上圖這樣,howdy.c和helper.c這兩個源文件經過預處理后編譯成目標文件,然后連接器把來自howdy.o和helper.o的目標代碼以及標准庫和c啟動代碼鏈接到一起生成可執行的二進制文件howdy。通常情況下,如果在依賴體helper.o和howdy.o不存在的情況下使用命令編譯howdy,那么gcc會報錯並退出。On the other hand,編譯器在看到howdy需要這兩個文件(以及helper.h)后,make先看它們是否存在,如果不存在則根據規則命令生成它們,然后再根據第一條規則生成howdy。顯然地,如果helper.h不存在,也會報錯退出,因為Makefile文件中並沒有規則命令生成helper.h。              

  好了,大概明白make是怎么執行的了,那新的問題又來了,make怎么知道什么時候該重新編譯一個新的文件呢?  其實很簡單:如果指定的目標文件不存在,那么毫無疑問,make就會根據規則命令生成它;如果目標文件已經存在,那么make就會將目標文件和依賴文件的時間戳進行對比,如果有一個以上的依賴文件比目標文件新(就是依賴文件的修改時間比目標文件的時間新),那么make就會重新編譯生成新的目標體。  

 

偽目標:

什么是偽目標?偽目標就是上面Makefile文件的clean就是偽目標,偽目標就是不對應實際的文件。但是,由於偽目標沒有依賴體,所以它的命令是不會自動被make執行的,如果要編譯執行這個目標體,那么只需 make clean,編譯器就會編譯執行clean的命令。但是,如果剛好有個名字叫做clean的文件存在,那么make就會發現它,但是clean沒有依賴體,所以make就會認為clean已經是最新的文件從而不會執行其命令。為了處理這種情況,就需要使用特殊的目標體.PHONY。.PHONY的依賴體文件的含義和通常的一樣,但是make不檢查是否存在有文件名和依賴體中的一個名字相匹配的文件,而是直接執行與之相關的命令。如果使用.PHONY,上述的Makefile文件就成了下面這樣

howdy:howdy.o helper.o helper.h
        gcc howdy.o helper.o -o howdy
helper.o:helper.c helper.h
        gcc -c helper.c 
howdy.o:howdy.c
        gcc -c howdy.c
#hello:hello.c
#       gcc hello.c -o hello
#all:howdy hello
.PHONY
clean:
        rm howdy *.o

什么意思?一句話,意思就是:make在更新目標文件時,不管clean后面有沒有依賴,都會直接執行clean下面的命令。

 

變量:

為了簡化編輯和維護Makefile,make允許在Makefile中創建和使用變量。所謂的變量就是偽指定文本串在makefile中定義一個名字,這個文本串就是變量的值。

定義變量的一般方法:

VARNAME = some_text [...]
把變量名用括號擴起來,然后在前面加上“$”,就可以引用變量的值了:$(VARNAME)

將之前的Makefile文件中使用變量:

OBJS = howdy.o helper.o
HDRS = helper.h
howdy:$(OBJS)
        gcc $(OBJS) -o howdy
helper.o:helper.c $(HDRS)
        gcc -c helper.c
howdy.o:howdy.c
        gcc -c howdy.c
clean:
        rm -rf *.o

OBJS和HDRS會在被引用的每個地方展開成它的值,編譯時也是如此。關於自動變量:

變量                                        說明
$@                                   規則的目標文件對應的文件名
$^                                    規則中依賴的文件名
$<                                    規則中第一個相關文件名
$?                                    規則中日期新於目標的所有相關文件列表,以空格為分隔符
$(@D)                               目標文件的目錄部分(目標在子目錄中)
$(@F)                                目標文件的文件名部分(目標在子目錄中)

用於程序名和標志的預定義變量:

變量                                        說明
AR                                歸檔維護程序,默認值=ar
AS                                匯編程序,默認值=as
CC                                C編譯程序,默認值=cc
CPP                               C預處理程序,默認值=cpp
RM                               文件刪除程序,默認值= rm -rf
ARFLAS                          傳給歸檔維護程序的標志,默認值 = rv
ASFLAGS                        傳給匯編程序的標志,沒有默認值
CPPFLAGS                       傳給c預處理程序的標志,沒有默認值
CFLAGS                           傳給c編譯器的標志,沒有默認值
LDFLAGS                         傳給鏈接程序(ld)的標志,沒有默認值

 

 

模式規則:

  通過用戶定義自己的隱式規則,模式規則提供了擴展make的隱式規則的一種方法。模式規則雷士與普通規則,但是它的目標中必定含有符號 “%s”,這個符號可以與任何非空字符串匹配;為與目標中的“%s”匹配,這個規則的相關部分文件也必須使用“%s”。例如: %.o:%.c

告訴make所有形式為somename.o的目標(object)文件都應該從源文件somename.c編譯而來。再將上面的Makefile文件修改:

CC = gcc
OBJ = howdy
FILES = howdy.o helper.o
HDRS = helper.h
O_FLAG = -o
C_FLAG= -c
RM  = rm -rf
howdy:$(FILES) $(HDRS)
        $(CC) $(FILES) $(O_FLAG) $(OBJ)
%.o:%.c
        $(CC) $(C_FLAG) $^ $(O_FLAG) $@
clean:
        $(RM) $(FILES) $(OBJ)

 

以上內容為自己在《GNU/Linux》一書中學習Makefile時的一點理解,有錯還請留言指正。


免責聲明!

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



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