寫makefile是乙個非常便利的編譯方法,由於以前習慣把所有的**都集中在乙個檔案中,體現不出make的優勢,當把源**拆分成若干個原始檔,makefile就顯得必要了。以下是乙份簡單的makefile的教程,參考自a ****** makefile tutorial。正如原文所說,這份教程只是打算讓初學者快速入門,寫自己的makefile,來維護中小型的專案。
乙個簡單的例子,用k&r c中4.5那個例子:主程式(main.c)、函式**(getop.c, stack.c, getch.c)、標頭檔案(calc.h)。
一般的,我們會使用
1
gcc -o calc main.c getch.c getop.c stack.c -i.
來編譯。-i.是指gcc在當前目錄(.)下尋找include檔案。如果不用makefile,在測試-修改-除錯過程中,如果我們不想重敲那條 編譯指令的話,我們必須不停地在終端中按上下鍵來尋找最後的那條編譯指令。不幸的是,這種編譯方法有兩個缺陷:1. 當你把編譯指令丟失或者換電腦的時候,這樣效率會很低;2. 當我們只修改了乙個.c檔案時,每一次都將必須重新編譯所有的檔案,這非常耗時,不划算。現在是切入主題的時候了
最簡單的makefile寫法:
version 1
1
2
calc: main.c getch.c getop.c stack.c
gcc -o calc main.c getch.c getop.c stack.c -i.
如果把這些語句寫入乙個叫makefile或者makefile的檔案,然後在終端中輸入make,她將會按你在makefile中要求地編譯。注 意:第一行中並沒有任何引數,只是在冒號(:)後列出編譯中所需的檔案,當第一行中的任何檔案中更改時,make就知道calc需要重新編譯了。現在我們 已經解決了問題1,不用上下按箭頭了,但是對於問題2依舊沒有很好地解決。注意,非常重要:gcc前面必須有乙個tab,在任何指令之前都要有乙個 tab,不然make就會罷工的。
讓事情變得更有效率一點:
version 2
1
2
3
4
5
cc = gcc
cflags = -i.
calc: main.c getch.c getop.c stack.c
$(cc) -o calc main.c getch.c getop.c stack.c $(cflags)
現在我們新定義了兩個常量cc和cflags。這些是與make交流的特殊的常量,讓make知道我們要怎麼編譯.c檔案。cc是c編譯器所使用的,cflags是編譯用的引數。make會先分別編譯.c檔案,然後生成可執行檔案calc。
這種形式的makefile在小專案中非常有效,但是有乙個遺憾:include檔案的變動。如果我們修改了calc.h檔案,make是不會重新 編譯.c檔案的,事實上我們需要重新編譯。為了解決這一問題,我們必須告訴make所有的.c檔案依賴於.h檔案。我們可以在makefile中增加一條 規則:
version 3
1
2
3
4
5
6
7
8
9
cc = gcc
cflags = -i.
deps = calc.h
%.o: %.c $(deps)
$(cc) -c -o $@ $< $(cflags)
calc: main.o getch.o getop.o stack.o
$(cc) -o calc main.o getch.o getop.o stack.o $(cflags)
首先巨集定義deps,宣告.c檔案所依賴的.h檔案。然後我們定義一條規則,為所有的.c檔案生成乙個.o檔案。規則描述:.o檔案依賴於.c檔案 和deps中宣告的.h檔案,為了產生.o檔案,make需要使用cc中宣告的編譯器來編譯.c檔案。-c 意味著產生object檔案,-o $@ 意思是編譯生成的檔案用上面的%.o來命名,$< 指依賴關係中的第一項(%.c)cflags的定義和之前一樣。
最後為了簡化,我們使用特殊的巨集定義 $@ 和 $^ ,分別表示冒號(:)的左右兩邊。為了讓make中所有的規則更具通用性,在version 4中,我們把所有的include檔案作為deps的一部分,所有的object檔案作為obj的一部分:
version 4
01
02
03
04
05
06
07
08
09
10
cc = gcc
cflags = -i.
deps = calc.h
obj = main.o getch.o getop.o stack.o
%.o: %.c $(deps)
$(cc) -c -o $@ $< $(cflags)
calc: $(obj)
$(cc) -o $@ $^ $(cflags)
如果我們想把.h檔案放在include目錄下,.c檔案放在src目錄下以及一些本地的庫放在lib目錄下,同時我們想把.o檔案整理一下,避免 整個目錄的凌亂。在version 5中,定義了include,lib的目錄,並把object檔案放到了src目錄下的obj子目錄,同時還包含了任何我們想要包含的庫(比如說math 庫-lm)。這份makefile將放在src目錄下。值得注意的是,在這一版本中新增了一條clean的規則,使make clean得以執行。目錄結構如下:
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
idir = ..
/include
cc = gcc
cflags = -i$(idir)
odir = obj
ldir = ..
/lib
libs = -lm
_deps = calc.h
deps = $(patsubst %,$(idir)/%,$(_deps))
_obj = main.o getch.o getop.o stack.o
obj = $(patsubst %,$(odir)/%,$(_obj))
$(odir)/%.o: %.c $(deps)
$(cc) -c -o $@ $< $(cflags)
calc: $(obj)
gcc -o $@ $^ $(cflags) $(libs)
.phony: clean
clean:
rm
-f $(odir)/*.o *~ core $(idir)/*~
其中patsubst函式包含3個引數:需要匹配的式樣,用什麼來替換它,需要被處理的由空格分隔的字串。
現在我們已經有了乙個不錯的makefile,根據這個,我們能維護中小型的工程。當然我們能增加一些更複雜的規則;甚至創造一些規則。更多關於makefile和make請參考gnu make manual。
乙個簡單的makefile的編寫
標頭檔案 part.h cpp檔案 包含part.h part.cpp cpp檔案 包含part.h partmain.cpp makefile編寫如下 main partmain.o part.o g o main partmain.o part.o partmain.o partmain.cpp...
乙個最簡單的Makefile例子
1.hello.c include int main 2.makefile hello hello.o cc o hello hello.o hello.o hello.c cc c hello.c clean rm hello.o 說明 cc o hello hello.o前面是乙個tab的空格 ...
乙個最簡單的makefile示例
1.hello.c include int main 2.makefile hello hello.o cc o hello hello.o hello.o hello.c cc c hello.c clean rm hello.o 說明 cc o hello hello.o前面是乙個tab的空格 ...