1. 程式人生 > >關於如何編寫Makefile

關於如何編寫Makefile

陳皓老師曾經在CSDN上寫過關於Makefile很詳細的文章,有興趣的可以到這裡慢慢研讀。
http://blog.csdn.net/haoel/article/month/2004/02
這裡我把他在文章裡寫的關於Makefile的一些較為基本且常用的操作總結在這裡。

簡介

在windows的開發環境下編譯彙編連結生成目標檔案,這一系列工作全都是IDE幫我們完成。但是在Linux的開發環境下,需要開發者自己來輸入指令完成這些步驟。這個時候就出現了Makefile,Makefile在linux下的作用就是自動化編譯,它完成的工作就和IDE一樣,把工程中的各類原始檔按照開發者在Makefile裡定義的一系列規則來編譯,比如檔案的編譯先後順序,哪些檔案需要重新編譯等等。在Makefile定義好了以後,使用make指令就可以直接生成所有你要的目標檔案了。

Makefile編寫規則

基本格式為:

 target : prerequisites
     command

target是目標檔案,即你想要得到的檔案。
prerequisite是你要生成target所需要的檔案也叫依賴檔案。
command是要獲得上面目標檔案所需要執行的指令。

我在這裡寫了一個簡單的例子,包含了兩個標頭檔案和一個c檔案。
Makefile示例1
接著我們使用vim建立一個Makefile檔案,並往裡面寫入如下程式碼
Makefile示例2

退出vim使用指令make,再ls顯示資料夾內容,發現多了test可執行檔案和test.o目標檔案。
Makefile3

清空目標檔案的規則

為了便於程式碼的重編譯和檔案的清潔,我們會在Makefile中寫入一個清空目標檔案的語句。如圖2中最後clean語句。在執行make語句後我們不想再要中間生成的.o檔案,則執行指令make clean,Makefile則會執行clean下面的語句,刪除掉.o檔案。如圖
Makefile5

make的工作原理

1.make在當前目錄下找到Makefile檔案;
2.找到後,按照檔案中所寫的第一個目標檔案即最終目標;
3.如果目標檔案不存在,或是目標檔案所依賴的後面的 .o 檔案的檔案修改時間要比目標檔案新,那麼,他就會執行後面所定義的命令用來生成目標檔案;
4.如果目標檔案所依賴的.o檔案也存在,那麼make會在當前檔案中找目標為.o檔案的依賴性,如果找到則再根據那一個規則生成.o檔案。
5.當所有目標檔案所需要的檔案都建立完成後,就會建立最後的目標檔案。

這就是整個make的依賴性,make會一層又一層地去找檔案的依賴關係,直到最終編譯出第一個目標檔案。但是像clean這種,沒有被第一個目標檔案直接或間接關聯,那麼它後面所定義的命令將不會被自動執行,我們只能使用make clean去呼叫它。

Makefile中的偽目標

Makefile中有一個偽目標的概念,它的定義方式為
.PHONY:偽目標
偽目標可以是沒有依賴檔案的目標檔案,例如clean就可以定義為偽目標,防止誤觸發。或者在一個Makefile裡面你想一次make生成多個可執行檔案,也可以利用偽目標的定義。例如

all : prog1 prog2 prog3
   .PHONY : all

   prog1 : prog1.o utils.o
           cc -o prog1 prog1.o utils.o

   prog2 : prog2.o
           cc -o prog2 prog2.o

   prog3 : prog3.o sort.o utils.o
           cc -o prog3 prog3.o sort.o utils.o

all就為定義的偽目標,由於all是Makefile裡的第一個出現的目標檔案,所以它就是最終的目標檔案,他又依賴於後面的的三個目標檔案,make就會分別去生成這三個目標檔案,從而達到一次make生成多個可執行檔案的目的。

變數的宣告

當我們一個工程是由多個.o檔案組合而成的時候,這個時候為了方便修改和管理我們可以採用宣告一個變數來代替這些.o檔案。這樣如果想要修改這些.o檔案其中的哪一個的時候只要修改宣告處的就可以了。
這裡使用陳皓老師給出的例子

edit : main.o kbd.o command.o display.o \(\為續行符)
       insert.o search.o files.o utils.o
       gcc -o edit main.o kbd.o command.o display.o \
       insert.o search.o files.o utils.o

這個edit目標檔案由多個.o檔案構成,如果想要修改其中一個時,加上後面的clean要修改三處,如果工程量再大一點則很容易出現遺漏。所以這裡聲明瞭變數objects,並且在後面的Makefile描述中就可以使用$(objects)代替這些變數。

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

edit : $(objects)
       gcc -o edit $(objects)