跟我一起寫 Makefile(一)

2021-09-06 18:27:55 字數 4868 閱讀 2673

跟我一起寫 makefile

陳皓

概述

——

什麼是makefile?也許非常多winodws的程式猿都不知道這個東西,由於那些windows的ide都為你做了這個工作,但我認為要作乙個好的和professional的程式猿,makefile還是要懂。這就好像如今有這麼多的html的編輯器,但假設你想成為乙個專業人士,你還是要了解html的標識的含義。特別在unix下的軟體編譯,你就不能不自己寫makefile了,會不會寫makefile,從乙個側面說明了乙個人是否具備完畢大型project的能力。

由於,makefile關係到了整個project的編譯規則。乙個project中的原始檔不計數,其按型別、功能、模組分別放在若干個資料夾中,makefile定義了一系列的規則來指定,哪些檔案須要先編譯,哪些檔案須要後編譯,哪些檔案須要又一次編譯,甚至於進行更複雜的功能操作,由於makefile就像乙個shell指令碼一樣,當中也能夠執行作業系統的命令。

makefile帶來的優點就是——「自己主動化編譯」,一旦寫好,僅僅須要乙個make命令,整個project全然自己主動編譯,極大的提高了軟體開發的效率。make是乙個命令工具,是乙個解釋makefile中指令的命令工具,一般來說,大多數的ide都有這個命令,比方:delphi的make,visual c++的nmake,linux下gnu的make。可見,makefile都成為了一種在project方面的編譯方法。

如今講述怎樣寫makefile的文章比較少,這是我想寫這篇文章的原因。當然,不同產商的make各不同樣,也有不同的語法,但其本質都是在「檔案依賴性」上做文章,這裡,我僅對gnu的make進行講述,我的環境是redhat linux 8.0,make的版本號是3.80。必竟,這個make是應用最為廣泛的,也是用得最多的。並且其還是最遵循於ieee 1003.2-1992 標準的(posix.2)。

在這篇文件中,將以c/c++的源**作為我們基礎,所以必定涉及一些關於c/c++的編譯的知識,相關於這方面的內容,還請各位檢視相關的編譯器的文件。這裡所預設的編譯器是unix下的gcc和cc。

關於程式的編譯和鏈結

——————————

在此,我想多說關於程式編譯的一些規範和方法,一般來說,不管是c、c++、還是pas,首先要把原始檔編譯成中間**檔案,在windows下也就是 .obj 檔案,unix下是 .o 檔案,即 object file,這個動作叫做編譯(compile)。然後再把大量的object file合成執行檔案,這個動作叫作鏈結(link)。

編譯時,編譯器須要的是語法的正確,函式與變數的宣告的正確。對於後者,一般是你須要告訴編譯器標頭檔案的所在位置(標頭檔案裡應該僅僅是宣告,而定義應該放在c/c++檔案裡),僅僅要全部的語法正確,編譯器就能夠編譯出中間目標檔案。一般來說,每乙個原始檔都應該相應於乙個中間目標檔案(o檔案或是obj檔案)。

鏈結時,主要是鏈結函式和全域性變數,所以,我們能夠使用這些中間目標檔案(o檔案或是obj檔案)來鏈結我們的應用程式。鏈結器並無論函式所在的原始檔,僅僅管函式的中間目標檔案(object file),在大多數時候,因為原始檔太多,編譯生成的中間目標檔案太多,而在鏈結時須要明顯地指出中間目標檔名稱,這對於編譯非常不方便,所以,我們要給中間目標檔案打個包,在windows下這樣的包叫「庫檔案」(library file),也就是 .lib 檔案,在unix下,是archive file,也就是 .a 檔案。

總結一下,原始檔首先會生成中間目標檔案,再由中間目標檔案生成執行檔案。在編譯時,編譯器僅僅檢測程式語法,和函式、變數是否被宣告。假設函式未被宣告,編譯器會給出乙個警告,但能夠生成object file。而在鏈結程式時,鏈結器會在全部的object file中找尋函式的實現,假設找不到,那到就會報鏈結錯誤碼(linker error),在vc下,這樣的錯誤通常是:link 2001錯誤,意思說是說,鏈結器未能找到函式的實現。你須要指定函式的object file.

好,言歸正傳,gnu的make有很多的內容,閒言少敘,還是讓我們開始吧。

makefile 介紹

———————

make命令執行時,須要乙個 makefile 檔案,以告訴make命令須要怎麼樣的去編譯和鏈結程式。

首先,我們用乙個演示樣例來說明makefile的書寫規則。以便給大家乙個感興認識。這個演示樣例**於gnu的make使用手冊,在這個演示樣例中,我們的project有8個c檔案,和3個頭檔案,我們要寫乙個makefile來告訴make命令怎樣編譯和鏈結這幾個檔案。我們的規則是:

1)假設這個project沒有編譯過,那麼我們的全部c檔案都要編譯並被鏈結。

2)假設這個project的某幾個c檔案被改動,那麼我們僅僅編譯被改動的c檔案,並鏈結目標程式。

3)假設這個project的標頭檔案被改變了,那麼我們須要編譯引用了這幾個標頭檔案的c檔案,並鏈結目標程式。

僅僅要我們的makefile寫得夠好,全部的這一切,我們僅僅用乙個make命令就能夠完畢,make命令會自己主動智慧型地依據當前的檔案改動的情況來確定哪些檔案須要重編譯,從而自己編譯所須要的檔案和鏈結目標程式。

一、makefile的規則

在講述這個makefile之前,還是讓我們先來粗略地看一看makefile的規則。

target ... : prerequisites ...

command

......

target也就是乙個目標檔案,能夠是object file,也能夠是執行檔案。還能夠是乙個標籤(label),對於標籤這樣的特性,在興許的「偽目標」章節中會有敘述。

prerequisites就是,要生成那個target所須要的檔案或是目標。

command也就是make須要執行的命令。(隨意的shell命令)

這是乙個檔案的依賴關係,也就是說,target這乙個或多個的目標檔案依賴於prerequisites中的檔案,其生成規則定義在command中。說白一點就是說,prerequisites中假設有乙個以上的檔案比target檔案要新的話,command所定義的命令就會被執行。這就是makefile的規則。也就是makefile中最核心的內容。

說究竟,makefile的東西就是這樣一點,好像我的這篇文件也該結束了。呵呵。還不盡然,這是makefile的主線和核心,但要寫好乙個makefile還不夠,我會以後面一點一點地結合我的工作經驗給你慢慢到來。內容還多著呢。:)

二、乙個演示樣例

正如前面所說的,假設乙個project有3個頭檔案,和8個c檔案,我們為了完畢前面所述的那三個規則,我們的makefile應該是以下的這個樣子的。

edit : main.o kbd.o command.o display.o /

insert.o search.o files.o utils.o

cc -o edit main.o kbd.o command.o display.o /

insert.o search.o files.o utils.o

main.o : main.c defs.h

cc -c main.c

kbd.o : kbd.c defs.h command.h

cc -c kbd.c

command.o : command.c defs.h command.h

cc -c command.c

display.o : display.c defs.h buffer.h

cc -c display.c

insert.o : insert.c defs.h buffer.h

cc -c insert.c

search.o : search.c defs.h buffer.h

cc -c search.c

files.o : files.c defs.h buffer.h command.h

cc -c files.c

utils.o : utils.c defs.h

cc -c utils.c

clean :

rm edit main.o kbd.o command.o display.o /

insert.o search.o files.o utils.o

反斜槓(/)是換行符的意思。這樣比較便於makefile的易讀。我們能夠把這個內容儲存在檔案為「makefile」或「makefile」的檔案裡,然後在該資料夾下直接輸入命令「make」就能夠生成執行檔案edit。假設要刪除執行檔案和全部的中間目標檔案,那麼,僅僅要簡單地執行一下「make clean」就能夠了。

在這個makefile中,目標檔案(target)包括:執行檔案edit和中間目標檔案(*.o),依賴檔案(prerequisites)就是冒號後面的那些 .c 檔案和 .h檔案。每個 .o 檔案都有一組依賴檔案,而這些 .o 檔案又是執行檔案 edit 的依賴檔案。依賴關係的實質上就是說明了目標檔案是由哪些檔案生成的,換言之,目標檔案是哪些檔案更新的。

在定義好依賴關係後,興許的那一行定義了怎樣生成目標檔案的作業系統命令,一定要以乙個tab鍵作為開頭。記住,make並無論命令是怎麼工作的,他僅僅管執行所定義的命令。make會比較targets檔案和prerequisites檔案的改動日期,假設prerequisites檔案的日期要比targets檔案的日期要新,或者target不存在的話,那麼,make就會執行興許定義的命令。

這裡要說明一點的是,clean不是乙個檔案,它僅僅只是是乙個動作名字,有點像c語言中的lable一樣,其冒號後什麼也沒有,那麼,make就不會自己主動去找檔案的依賴性,也就不會自己主動執行其後所定義的命令。要執行其後的命令,就要在make命令後明顯得指出這個lable的名字。這個方案很實用,我們能夠在乙個makefile中定義不用的編譯或是和編譯無關的命令,比方程式的打包,程式的備份,等等。

->

跟我一起寫 Makefile

概述 什麼是makefile?或許很多winodws的程式設計師都不知道這個東西,因為那些windows的ide都為你做了這個工作,但我覺得要作乙個好的和professional的程式設計師,makefile還是要懂。這就好像現在有這麼多的html的編輯器,但如果你想成為乙個專業人士,你還是要了解h...

跟我一起寫 Makefile

概述 什麼是makefile?或許很多winodws的程式設計師都不知道這個東西,因為那些windows的ide都為你做了這個工作,但我覺得要作乙個好的和professional的程式設計師,makefile還是要懂。這就好像現在有這麼多的html的編輯器,但如果你想成為乙個專業人士,你還是要了解h...

跟我一起寫 Makefile

跟我一起寫 makefile 陳皓 概述 什麼是makefile?或許很多winodws的程式設計師都不知道這個東西,因為那些windows的ide都為你做了這個工作,但我覺得要作乙個好的和professional的程式設計師,makefile還是要懂。這就好像現在有這麼多的html的編輯器,但如果...