Make是一個可擴展性極強的編譯構建工具,將它和相關語言的編譯器結合起來,我們幾乎可以用它來 編譯構建任何編程語言程序。
make主要是通過默認的 Makefile
或 makefile
的配置文件(下文統一稱 makefile
)中的規則來構建項目的。 makefile
其實是有無數的規則組成的。 我們可以用這些規則來編譯,鏈接,以及運行相關命令和腳本。這些規則的語法大概是這樣的:
target(規則生成的目標文件或者make執行的規則命令名) … : prerequisitse(規則的輸入文件,或源文件) …
recipe(make執行的規則命令)
…
…
recipe(規則命令)必須有一個製表符(TAB)。並且如果一旦任何一個源文件變化了,規則命令都會重新執行,否則不會。 make
檢測文件的是否修改是通過文件的上次修改時間來確定的
IDIR=../include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR=../lib
LIBS=-Im
_DEPS=hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ=hellomake.o hellofunc.o
OBJ=$(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o:%.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: $(OBJ)
$(CC) -o $@ $^ ${CFLAGS} $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~core $(INCDIR)/*~
文件結構
├── include
│ └ hellomake.h
├── lib
└── src
├── hellofunc.c
├── hellomake
├── hellomake.c
├── makefile
└── obj
├── hellofunc.o
└── hellomake.o
這個makefile文件會做如下工作
- 將
src
目錄下的hellofunc.c
和hellomake.c
的源文件編譯到obj
目錄下,分別生成hellofunc.o
和hellmake.o
目標文件 - 利用
obj
目錄下的hellofunc.o
和hellomake.o
的目標文件和include
目錄下的hellomake.h
文件,以及math
庫鏈接在src
目錄下生成hellomake
可執行程序
等價於運行以下程序
gcc -c -o obj/hellofunc.o hellofunc.c -I ./include
gcc -c -o obj/hellomake.o hellomake.c -I ./include
gcc -o hellomake hellomake.o hellofunc.o -I ./include -Im
makefile
中的規則分爲模式規則和標準規則。標準規則是make已經定義好的規則,比如 all
、 install
, 我們下面會介紹,標準規則可以不提供源文件。 比如:
clean:
rm -f $(ODIR)/*.o *~core $(INCDIR)/*~
模式規則,通常包含通配符。模式規則裏面必須包含源文件。 比如:
$(ODIR)/%.o:%.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: $(OBJ)
$(CC) -o $@ $^ ${CFLAGS} $(LIBS)
makefile
中定義了許多標準規則,我們可以直接在 makefile
中使用。
- all
all
會編譯整個程序,同 make all
命令。在 makefile
中一個構建是由多個規則節點構成。 all
是一個僞規則,它本質上並不做任何工作。它只表示,它會依賴文件或子規則來 完成整個程序的構建工作。我們既可以爲 all
指定子規則,也可以忽略。下面兩個例子說明這兩種用法的區別。
all: execuatble1 execuatlbe2
上面的規則表示, all
的整個構建任務是生成 executable1
和 executable2
兩個可執行程序。也可整個構建任務是依賴 executable1
和 executable2
另個文件的。
*對 executable1.cpp
和 executable2.cpp
分別採用如下規則:*
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
這裏 all
並沒有指定子規則生成 executable1
和 executable2
文件。那麼 make
將會調用默認的規則來生成這兩個文件。
**我們也可以指定相應的子規則來生成相應的依賴文件。
all: execuatble1 execuatlbe2
executable1: executable1.cpp
$(CC) $(CFLAGS) $(LDFLAGS) -o ./bin/$@ $<
executable2: executable2.cpp
$(CC) $(CFLAGS) $(LDFLAGS) -o ./bin/$@ $<
這裏我們指定了相應子規則來生成相應的可執行文件。
一般 make
只會執行生成一個可執行文件,然後就會停止, 我們通常可以將 all
作爲第一個規則,用它來爲多個源文件分別生成多個可執行文件。
InterviewProblems: InterviewProblems.cpp
$(CC) $(LDFLAGS) -o $(BINDIR)$@ $^
InterviewProblems_claimed_correct: InterviewProblems_claimed_correct.cpp
$(CC) $(LDFLAGS) -o $(BINDIR)$@ $^
這裏, make
只會生成 InterviewProblems
後就停止。
CC=g++
BINDIR=./bin/
LDFLAGS=-std=c++11
OBJ=InterviewProblems.cpp InterviewProblems_claimed_correct.cpp
EXECUTABLE=InterviewProbles InterviewProblems_claimed_correct
all: InterviewProblems InterviewProblems_claimed_correct
InterviewProblems: InterviewProblems.cpp
$(CC) $(LDFLAGS) -o $(BINDIR)$@ $^
InterviewProblems_claimed_correct: InterviewProblems_claimed_correct.cpp
$(CC) $(LDFLAGS) -o $(BINDIR)$@ $^
文件目錄結構
├── bin
│ ├── InterviewProblems
│ └── InterviewProblems_claimed_correct
├── InterviewProblems_claimed_correct.cpp
├── InterviewProblems.cpp
├── makefile
該 makefile
分別將 InterviewProblems.cpp
和 InterviewProbles_claimed_correct.cpp
編譯成 bin
目錄下的 InterviewProblems
和 InterviewProblems_claimed_correct
可執行文件。