從只有一個Makefile的單級Makefile開始。
對於一個稍大的項目或者說軟體來說,來源程式(.c檔案或者是.h檔案),以及來源程式檔案夾,絕對不只是一個檔案或者來源程式檔案夾,想想你寫的代碼只有一個來源程式或者程式檔案夾還是什麼時候。一個好的程式員,總是希望自己寫的代碼檔案,清晰,一目瞭然,通過不同的檔案夾,不用的名字就能大致看出該程式的功能。
當只有一個來源程式檔案的時候,比如main.h,main.c,這個時候,由於來源程式檔案少,我們可以手動對程式進行編譯:gcc main.c -o main_exe。這個時候,手動編譯器還是很方便的。但是,如果程式有幾十甚至幾百幾千個的時候,這個時候,通過gcc手動的對來源程式進行編譯的時候,就有困難了。另外,好的程式員會去考慮到程式的可移植性和程式檔案之間的關係,我們總是希望把來源程式拿過來直接編譯然後就能運行,我們會把來源程式放在不同的檔案夾下。這樣一來,對於手動編譯器就更加困難了。這個時候,Makefile優勢就顯現出來了。
下面以執行個體來說明Makefile究竟如何編寫,
/*
*************************************
name:example-one.c
*************************************
*/
#include “example-one.h”
{
…….
……..
}
*************************************
name:example-one.h
養成每個.c來源程式都有一個與之同名的.h
與之對應來做一些聲明。
*************************************
*/
#include <>
#include <>
/*
*************************************
name:example-two.c
*************************************
*/
#include “example-two.h”
#include “example-one.h”
{
…….
……..
}
*************************************
name:example-two.h
養成每個.c來源程式都有一個與之同名的.h
與之對應來做一些聲明。
*************************************
*/
#include <>
#include <>
…..
…..
*************************************
name:main.c
*************************************
#include “example-two.h”
{
}
在這裡我不講Makefile的規則,對於這些規則,網上的關於Makefile的編寫都大同小異,我主要講講Makefile的工作原理。
按照上述檔案之間的關係不難看出,example-two.c由於使用了example-one.c的東西,那麼當我們編譯example-two.c的時候就需要example-one.c。
還是先來說下幾個關鍵詞
target:cond
按照Makefile的規則,target就是目標,然後cond就是要編譯得到target目標所需要的條件。
其實在很多情況下,我們的Makefile可以唯寫出
%:%.o
這個規則就可以了。
以這個例子為例。雖然按照實際情況上來說,有個層次關係,main.o的編譯需要example-two.c, example-two.h作為必要條件,同理,example-two.o需要example-one.h和example-one.c作為必要條件。
但是,你可以試試,這個例子的Makefile可以簡化到如此簡單:
OBJS := main.o example-one.o example-two.o
EXEC := test
$(EXEC):$(OBJS)
tab gcc –o $(EXEC) $(OBJS)
寫好commamd之後,make就可以編譯出程式了,絕對沒問題。
Makefile其實也是一種指令碼語言。他只需要知道編譯成可執行程式EXEC所必須的目標檔案OBJS有哪些(這裡對於將目標檔案.o檔案,源檔案 .h, .c檔案同名很重要,所以要養成這種習慣會給變成帶來很大的方便的)。
GNU 的make 工作時的執行步驟入下:
1、讀入所有的Makefile。
2、讀入被include 的其它Makefile。
3、初始設定檔案中的變數。
4、推導隱晦規則,並分析所有規則。
5、為所有的目標檔案建立依賴關係鏈。
6、根據依賴關係,決定哪些目標要重建。
7、執行產生命令。
當make一旦知道可執行檔所需的目標檔案.o檔案之後,他發現要產生可執行檔需要哪些.o檔案,他就會在你所指定的目錄已經目前的目錄中尋找,當他找不到某一.o檔案的時候,就會啟動隱含規則去試圖產生.o檔案。同樣,當產生.o檔案的時候就會去找相應的.c檔案和.h檔案。這才是這個例子會有如此簡單的Makefile的真正原因。而Makefile的編寫工作最終落實到你給出檔案,讓make去找檔案。而本身來源程式.c檔案中的include也同時告訴Makefile,.c檔案需要哪些.h條件,所以在由.c檔案到.o檔案的過程中可以由它自動來完成,不需要我們明確的顯示的告訴他這些關係。
給個不恰當的比喻:.c .h檔案相當於人,通過#include 已經extern 等血緣關係,在make之後,構成了家庭這種.o檔案。
family.o: zhang.c wang.c zhang_son.h
所有的人都用過這種關係來構成家庭。
然後那麼社區這種可執行檔是有家庭這種.o檔案構成的。那麼在組裝可執行檔這一階段只需要列出該社區的所有的家庭,於是也就自動完成了社區的組建。
community:family_one.o family_two.o…
總之,在組裝可執行程式的規則中,要列出所需要的所有的.o檔案。
著作權申明:
轉載文章請註明原文出處http://blog.csdn.net/feiyinzilgd/archive/2010/02/07/5297161.aspx
並請聯絡譚海燕本人或者前往譚海燕個人首頁留言