C編譯 makefile基礎

2021-09-06 09:25:04 字數 3489 閱讀 6685

在編譯乙個大型專案的時候,往往有很多目標檔案、庫檔案、標頭檔案以及最終的可執行檔案。不同的檔案之間存在依賴關係(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()

下面是乙個簡單的makefile

# helloworld is a binary file

helloworld: test.o

echo "good"

gcc -o helloworld test.o

test.o: test.c

gcc -c -o test.o test.c

觀察上面的makefile

用直白的話說,就是:

我們執行

$make helloworld

來建立helloworld。

make是乙個遞迴建立的過程:

虛線: 依賴關係檢索

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

make中可以使用巨集(macro)。巨集類似於文字型別的變數。比如下面的cc:

cc = gcc

# helloworld is a binary file

helloworld: test.o

echo "good"

$(cc) -o helloworld test.o

test.o: test.c

$(cc) -c -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。

參考

C 編譯多個檔案makefile

逐步編譯 g c apcluster.cppapcluster.h 生成apcluster.o 中間檔案 g c example.cppapcluster.h 生成example.o中間檔案 g o main apcluster.o example.o makefile gnu的make很強大,它可...

使用makefile編譯c程式

一 makefile的規則 makefile的規則如下 target prerequisites command 這裡的command是指生成或是處理target隨執行的命令 prerequisites指的是生成target所需要依賴的檔案.二 乙個示例 自行編寫了2個c檔案 get max.c,f...

使用makefile編譯C 工程

目錄結構 kexin 外層cmakelists.txt編寫 cmake 最低版本號要求 cmake minimum required version 3.7 fatal error 專案資訊 project kexin include路徑 include directories include 設定...