當前位置:
首頁 > 最新 > C 編譯:makefile 基礎

C 編譯:makefile 基礎

在編譯一個大型項目的時候,往往有很多目標文件、庫文件、頭文件以及最終的可執行文件。不同的文件之間存在依賴關係(dependency)。比如當我們使用下面命令編譯時:

$gcc -c -o test.o test.c

$gcc -o helloworld test.o

可執行文件helloworld依賴於test.o進行編譯的,而test.o依賴於test.c。

依賴關係

在我們編譯一個大型項目時,我們往往要很多次的調用編譯器,來根據依賴關係,逐步編譯整個項目。這樣的方式是自下而上的,即先編譯下游文件,再編譯上游文件。

UNIX系統下的make工具用於自動記錄和處理文件之間的依賴關係。我們不用輸入大量的」gcc」命令,而只需調用make就可以完成整個編譯過程。所有的依賴關係都記錄在makefile文本文件中。我們只需要make helloworld,make會根據依賴關係,自上而下的找到編譯該文件所需的所有依賴關係,最後再自下而上的編譯。

(make有多個版本,本文將基於GNU make。make會自動搜索當前目錄下的makefile, Makefile或者GNUmakefile)

依賴

基本概念

我們使用一個示例C語言文件:

#include

/*

* By Vamei

* test.c for makefile demo

*/

intmain()

{

printf("Hello world!");

return;

}

下面是一個簡單的makefile

# helloworld is a binary file

helloworld:test.o

echo"good"

gcc-ohelloworldtest.o

test.o:test.c

觀察上面的makefile

#號起始的行是注釋行

target: prerequisite為依賴關係,即目標文件(target)依賴於前提文件(prerequisite)。可以有多個前提文件,用空格分開。

依賴關係後面的縮進行是實現依賴關係進行的操作,即正常的UNIX命令。一個依賴關係可以附屬有多個操作。

用直白的話說,就是:

想要helloworld嗎?那你必須有test.o,並執行附屬的操作。

如果沒有test.o,那你必須搜索其他依賴關係,並創建test.o。

我們執行

$make helloworld

來創建helloworld。

make是一個遞歸創建的過程:

Base Case 1: 如果當前依賴關係中沒有說明前提文件,那麼直接執行操作。

Base Case 2: 如果當前依賴關係說明了目標文件,而目標文件所需的前提文件已經存在,而且前提文件與上次make時沒有發生改變(根據最近寫入時間判斷),也直接執行該依賴關係的操作。

如果當前目標文件依賴關係所需的前提文件不存在,或者前提文件發生改變,那麼以前提文件為新的目標文件,尋找依賴關係,創建目標文件。

虛線: 依賴關係檢索

上面是make的核心功能。有了上面的功能,我們可以記錄項目中所有的依賴關係和相關操作,並使用make進行編譯。下面的內容都是在此核心內容上的拓展。

make中可以使用宏(MACRO)。宏類似於文本類型的變數。比如下面的CC:

CC=gcc

# helloworld is a binary file

helloworld:test.o

echo"good"

$(CC)-ohelloworldtest.o

test.o:test.c

我們用CC來代表」gcc」。在makefile中,使用$(CC)的方式來調用宏的值。make會在運行時,使用宏的值(gcc)來替代$(CC)。

shell的環境變數可以直接作為宏調用。如果同一個自定義的宏同時也有同名環境環境變數,make將優先使用自定義宏。

(可以使用$make -e helloworld來優先使用環境變數)

類似於C語言的宏,makefile中的宏可以方便的管理一些固定出現的文本,並方便替換操作。比如我們未來使用ifort編譯器時,只需要更改宏定義為:

CC = ifort

就可以了

內部宏

make中有內部定義的宏,可以直接使用。$@中包含有當前依賴關係的目標文件名,而$^包含當前目標的前提文件:

CC=gcc

# helloworld is a binary file

helloworld:test.o

echo$@

$(CC)-o$@$^

test.o:test.c

$(CC)-c-o$@$^

內部宏 功能

$* 當前依賴關係中的目標文件名,不包括後綴。

$* 當前依賴關係中,發生改變的前提文件

$$ 字元」$」

如果目標或者前提文件是一個完整路徑,我們可以附加D和F來提取文件夾部分和文件名部分,比如$(@F)表示目標文件的文件名部分。

後綴依賴

在makefile中使用

.SUFFIXES: .c .o

來說明.c和.o是後綴。

我們可以使用後綴依賴的方式,比如:

CC=gcc

.SUFFIXES:.c.o

.c.o:

$(CC)-c-o$@$^

#--------------------------

# helloworld is a binary file

helloworld:test.o

echo$@

$(CC)-o$@$^

test.o:test.c

我們定義.c和.o為後綴。並有後綴依賴關係.c.o:。前者為前提,後者為目標。(注意,與一般的依賴關係順序不同)

上面的test.o和test.c有依賴關係,但沒有操作。make會發現該依賴關係符合.c.o的後綴依賴,並執行該後綴依賴後面的操作。

如果項目很大型的時候,後綴依賴非常有用。符合後綴依賴的文件往往有類似的操作,我們可以將這些操作用後綴依賴表示,而避免重複輸入。

其他

makefile的續行符為

makefile中經常會定義下面依賴關係:

all:

如果make後沒有跟隨文件名,那麼將執行該依賴關係。

clean:

常用於清理歷史文件。

比如:

CC=gcc

.SUFFIXES:.c.o

.c.o:

$(CC)-c-o$@$^

#--------------------------

all:helloworld

@echo"ALL"

# helloworld is a binary file

helloworld:test.o

@echo$@

$(CC)-o$@$^

test.o:test.c

clean:

-rm helloworld *.o

注意: echo前面的@和rm前面的-。@後的命令將不顯示命令本身。-後面的命令將忽略錯誤(比如刪除不存在的文件)。

總結

make的核心功能是根據依賴關係來實現編譯管理。

make的其他功能是讓用戶可以更加便捷的寫出makefile。

來源:Vamei

鏈接:http://www.cnblogs.com/vamei/archive/2013/04/29/3051062.html

程序員共讀整理髮布,轉載請聯繫作者獲得授權。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員共讀 的精彩文章:

程序員最喜歡說的十句話
由一個例子到 python 的名字空間
無休止加班的成因
9個實戰及面試常用Shell腳本編寫
那些讓程序員水深火熱的境況……

TAG:程序員共讀 |

您可能感興趣

使用Visual Studio Code編譯、調試Apollo項目
對於linux下交叉編譯鏈以及Makefile的簡單理解
Facebook發布Tensor Comprehensions:自動編譯高性能機器學習核心的C+庫
Windows 版本的 Chrome 停用微軟的編譯器 改用 Clang
kali下編譯學習python3
php7在FreeBSD靜態編譯iconv,導致BUS ERROR (core dump)解決
Flutter 的編譯模式
Fortran For Fun 之編譯工具 FoBis
Vdex Extractor:從Vdex文件反編譯和提取Android Dex位元組碼
棄用微軟 C+編譯器,Win版Chrome 改用 Clang
布蘭詩歌Carmina Burana 音樂史編譯
開發者編譯Windows 10 ARM版Chromium瀏覽器,一加6T等成功運行
在tinycolinux上編譯pypy和hippyvm
一統所有AI晶元:Facebook揭秘深度學習編譯器Glow
Linux查看Nginx、Apache、MySQL、PHP的編譯參數
使用Mono將C#編譯運行至WebAssembly平台
微軟開啟編譯和測試Windows 10 Redstone 5
Dropbox創建了一種新的Python編譯器:mypyc
php+Swoole——編譯安裝
TVM:Deep Learning模型的優化編譯器