Makefile 是一個簡單的組織代碼編譯的方式。這個教程沒有深入的講解make,但能夠幫助初學者快速並且容易的創建自己的中型規模以下項目的makefiles。
一個簡單例子
首先讓我們創建三個文件,hellomake.c,hellofunc.c及hellomake.h,這三個文件是一個典型的main程序。
hellomake.c
#include <hellomake.h>
int main() {
// call a function in another file
myPrintHelloMake();
return(0);
}
hellofunc.c
#include <stdio.h>
#include <hellomake.h>
void myPrintHelloMake(void) {
printf("Hello makefiles!\n");
return;
}
hellomake.h
/*
example include file
*/
void myPrintHelloMake(void);
通常我們通過下面的命令編譯這些代碼集合:
gcc -o hellomake hellomake.c hellofunc.c -I.
上面命令編譯兩個cpp文件,並生成可執行文件hellomake,“-I.”是gcc需要的include文件,上面命令指當前目錄,主要爲hellomake.h。makefile可以免於我們每次在測試、修改、調試的時候都要重複的在命令行敲上面的命令,尤其我們需要添加更多.c文件時,makefile會爲我們節省大量時間。下面就讓我們開始寫makefile吧!
最簡單的makefile就像下面的示例:
Makefile 1
hellomake: hellomake.c hellofunc.c
gcc -o hellomake hellomake.c hellofunc.c -I.
如果你把上面規則放在一個叫Makefile或makefile的文件中,然後在命令行敲make命令,就會按你在makefile中寫的進行編譯操作。
- make後沒有參數,則執行makefile文件中的第一條規則。
- 把命令依賴的文件列表放在第一行的“:”後,make就清楚,如果這些文件任意一個改變,規則hellomake就會被重新編譯執行。
現在我們已經能夠避免重複敲冗長的編譯命令。
有一個特別重要的說明,爲了使代碼更加有效率,我們在makefile所有的gcc命令前寫一個聲明標籤,如下:
Makefile 2
CC=gcc
CFLAGS=-I.
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o $(CFLAGS)
上面我們定義的常量CC和CFLAGS將告訴make,我們如何編譯hellomake.c和hellofunc.c。宏常量CC是C編譯器使用的,CFLAGS是傳遞給編譯命令的一個便籤列表。通過放對象文件:hellomake.o 和 hellofunc.o在規則的依賴列表中,make就知道它首先要逐一的編譯.c文本,然後執行hellomake。
使用上面的makefile形式,對於小規模的工程是有效的。然而有一個重要的事情沒有說明:include的文件的依賴。如果我們改變了hellomake.h,make將不會重新編譯.c文件。爲了補充這個缺點,我們需要告訴make,所有的.c文件依賴的.h文件,示例如下:
Makefile 3
CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o $(CFLAGS)
這個首先添加了一個宏DEPS,它是.c文件依賴的.h文件的集合。然後我們定義了一個新規則,主要應用於所有已.o結尾的文件,這個規則告訴.o文件在宏DEPS中包含的所依賴的.c文本和.h文件。它也會告訴make,爲了生成.o文件,make需要編譯.c文件。“-c”標籤表明生成對象文件,“-o
爲了簡化我們的編寫,我們使用特殊的宏“
Makefile 4
CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
OBJ = hellomake.o hellofunc.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS)
而且如果我們想放我們的.h文件在include目錄下,我們的源碼文件在src目錄下,並且放一些本地依賴庫文件在lib目錄下,那我們怎麼辦呢?而且我們如何隱藏這些煩人的出現在所有地方的.o文件呢?
下面的makefile定義了include和lib目錄的路徑,並且把對象文件放在了src目錄的obj子目錄下。它還定義了一個你想包含的庫的宏,例如math庫-lm。這個makefile應該被放在src目錄下。這個makefile還有一個規則,如果執行make clean,將會清空你的源文件和對象目錄。“.PYONY”規則使得make免於加參數clean的清理操作。
Makefile 5
IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR =../lib
LIBS=-lm
_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)
gcc -o $@ $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
現在你已經有一個特別好的用來管理小型和中型規模項目的makefile,你可以增加更多規則到你的makefile,你甚至能創建調用其它規則的規則。對於更多makefiles和make函數,可以訪問GNU Make Manual,這裏可以得到更多我們想知道的。