理解Makefile

本次筆記是看了陳皓的《跟我一起寫Makefile》而作的整理,原版鏈接地址如下

http://pan.baidu.com/s/1skBumRF


第一部分

一、Makefile介紹

make命令編譯和鏈接文件的的規則是:

1、如果這個工程沒有編譯過,那麼我們所有的C文件都要編譯並被鏈接。

2、如果這個工程的某幾個C文件被修改,那麼我們只需編譯被修改的C文件,並鏈接目標文件。

3、如果這個工程的頭文件被修改了,那我我們要編譯引用這個頭文件的幾個C文件,並鏈接目標程序


二、Makefile的規則

Makefile規則如下:

target...:prerequisites...

command

target也就是目標文件,可以是.obj文件也可以是執行文件,還可以是一個標籤(Label)

prerequisites就是要生成那個target所需要的文件或是目標,一般稱爲“依賴”

command也就是make需要執行的命令(需要注意的是,command命令一定要以tab鍵作爲開頭)

根據make的編譯規則,如果prerequisites中有一個以上的文件比target文件要新的haul,command命令會被執行,這就是Makefile的核心內容。

make命令會根據文件的依賴性一層一層地尋找對應的文件,直到最終編譯出第一個目標文件。在尋找的過程中,如果出現錯誤,比如最後被依賴的文件找不到,那麼make會直接退出,並報錯。而對於所定義的命令的錯誤,或是編譯不成功,make根本不去理會。


三、Makefile如何工作

在Makefile中可以使用變量,使其更容易維護,Makefile的變量也就是一個字符串,理解成C語言中的宏可能會更好。實現如下:

假如我們有 main.o  key.o  command.o  search.o insert.o  file.o init.o display.o這幾個.obj文件,那麼我們在Makefile一開始就這樣定義:

obj=main.o  key.o  command.o  search.o insert.o  file.o init.o display.o  

在Makefile中就以“$(obj)”的方式來使用這個變量了,而假如我們需要添加新的obj文件,只需要在定義中添加即可,灰常方便


四、Makefile自動推導

GNU的make很強大,它可以自動推導文件以及文件依賴關係後面的命令,於是我們就沒有必要去在每個.o文件後面寫上依賴的命令,make能自動識別,因此在.o文件下只需要寫所依賴的.h文件即可。一個例子如下:

原先的規則如下:

main.o: main.c  defs.h 

cc -c main.c 

 由於make的自動推導,可以簡化寫爲

main.o:  defs.h 


五、清空文件的規則

每個Makefile中都應該寫一個清空目標文件(.o和執行文件)的規則,這不僅便於編譯,也有利於保持文件的清潔。

比較良好的清理規則如下:

.PHONY:clean

clean:

-rm  edit  $(obj)

.PHONY的意思表示clean是一個僞目標,而在rm參數前加一個減號的意思是,也許某些文件出現問題,但不要管,繼續做後面的事情。當然,clean規則不要放在開頭,否則被當成第一個目標文件。其中一個潛規則是——將clean放在文件的最後。


第二部分

一、Makefile裏面有什麼?

Makefile主要包含這5個東西:顯示規則、隱晦規則、變量定義、文件指示和註釋

1、顯示規則

顯示規則說明了如何生成一個或者多個目標文件。這是有Makefile書寫者明顯指出,要生成的文件,文件的依賴文件,生成的命令

2、隱晦規則

由於我們的make有自動推導的功能,所以隱晦規則可以讓我們較爲粗糙簡略地書寫Makefile

3、變量的定義

在Makefile中我們要定義一系列的變量,變量一般都是字符串,這個類似於C語言的宏。

4、文件指示

其包括三個部分,1)在一個Makefile中引用另一個Makefile,就像C語言中的include一樣;2)指根據某些情況制定Makefile中的有效部分,就像C語言中的預編譯#if一樣;3)定義一個多行命令

5、註釋

Makefile中只有行註釋,用#字符執行

二、引用其他的makefile

在makefile中使用關鍵字include可以把別的makefile文件包含進來,語法和C語言的一樣:include<filename>

filename可以是當前操作系統shell的文件模式,(可以包含路徑和通配符),在include前面可以有一些空格字符,但是絕不能是tab鍵開始。

如果make命令找不到所包含的文件,不會第一時間出現致命的錯誤,此時會發出一條警告,接着繼續尋找其他被包含的文件,過最後還是沒有找到那個文件,make纔會出現一條致命信息。

爲了解決上述問題,可以在include前面加一個減號,表示無論include過程中出現什麼錯誤,都不要報錯,繼續執行。

三、make工作方式

GNU的meke工作時執行的步驟如下:(其他的make也類似)

1、讀入所有的makefile

2、讀入被include的其他makefile

3、初始化文件中的變量

4、推到隱晦規則,並分析所有規則

5、爲所有的目標文件創造依賴關係鏈

6、根據依賴關係,決定哪些目標需要重新生成

7、執行生成命令

1-5步驟爲第一階段,6-7步驟爲第二階段

第三部分 書寫規則

一、規則語法

target...:prerequisites...

command

或是

target...:prerequisites...;command

若command和它們在同一行,那麼應該以分號(英文輸入格式)作爲分隔,若不在同一行,則應該以tab鍵開頭。

二、在規則中使用通配符

make支持三種通配符分別是  *  ?  [...]

通配符代替了一系列的文件,比如*.c表示所有後綴爲c的文件 

而需要注意的一個特殊情況是前面說道的定義變量,如下:

obj=*.o  然而使用了通配符之後,obj的值就是*.o,並不會展開,爲了解決這個問題,可以這樣定義:obj:=$(wildcard *.o)

三、僞目標

在前面提到的clean這個命令是一個僞目標,因爲我們並不生成clean這個文件,僅僅是一個標籤。由於它不是一個文件,所以make命令無法生成它的依賴關係和決定它是否要執行,我們只有通過顯示地指明這個“”目標“”才能讓其生效。看下面的例子

.PHONY : clean

只要有這個聲明,不管是否有clean這個文件,要運行clean這個目標,只有“”make clean“”這樣的命令,於是可以寫爲:

.PHONY:clean

clean:

-rm  edit  $(obj)


第四部分 補充

一、編譯命令

arm-linux-objcopy 把一種目標文件中的內容複製到另一種類型的目標文件中。

arm-linux-objdump 顯示一個或者更多目標文件的信息。使用選項來控制其顯示的信息,它所顯示的信息通常只有編寫編譯工具的人才感興趣。


例子:

arm-linux-objdump -D -m arm boot_elf > boot.dis

-m後面跟的是cpu的架構,例子中表示arm架構,

表示將反彙編語言寫入boot.dis中而不在終端顯示。


二、編譯參數的解釋

-O優化參數,後面可跟數字來表示優化的級別。-O0表示不優化,大部分平臺最多使用-O3,建議使用到-O2,另外-Os表示對代碼的大小進行優化,生成儘可能小的機器碼

-E僅僅對代碼進行預處理,不編譯。實際上是將頭文件包含和宏定義展開。

-c緊急彙編及編譯代碼,不進行鏈接。也就是將源代碼編譯成.o文件

-S僅僅彙編而不進行編譯及鏈接。也就是將源代碼編譯成彙編指令。

-o  filename 指明輸出文件名。一般配-E -c -S三個命令來使用。例如:gcc -c a.c -o a.o

-w關閉所有告警提示

-Wall打開大部分告警提示,而不是全部。

-W對某些告警顯示更詳細的信息

-D定義宏。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章