如下要說的顯然是C語言的項目。html
固然能夠考慮用其餘工具替代make,好比SCons和CMake,或者auto tools什麼的,但不少時候手寫Makefile仍是很是乾淨利索,爽快好用的,尤爲在項目比較小的時候。工具
規模一旦擴大,確實寫Makefile就有點費勁了。比較突出的一個問題是對頭文件的依賴。make本身是沒有辦法處理的,必需要藉助編譯器。post
如下會列舉三種常見的Makefile寫法。後兩種處理了對頭文件的依賴,推薦使用最後一種。spa
說下演示用的項目,只包含三個代碼文件,結構以下:code
. ├── bar.c ├── bar.h ├── foo.c └── Makefile
#ifndef _BAR_H_ #define _BAR_H_ void bar(void); #endif
#include <stdio.h> void bar(void) { printf("bar!\n"); }
#include <stdio.h> #include "bar.h" int main() { printf("foo -> "); bar(); return 0; }
若是不處理對頭文件的依賴,能夠寫出相似下面這樣的「萬能Makefile」,作作小東西無往不利。
缺陷是頭文件修改了之後不能自動從新編譯,須要不斷make clean && make
。htm
TARGET := foo CC := gcc LDLIBS := -lm SRCS := $(wildcard *.c) OBJS := $(SRCS:.c=.o) .PHONY: all clean all: $(TARGET) $(TARGET): $(OBJ) clean: rm -f $(OBJ) $(TARGET)
這是一種應該拋棄的方案,詳細的步驟分解能夠看這篇文章:Autodependencies with GNU make。blog
簡要歸納下,就是利用gcc的選項-M
或-MM
,來生成依賴文件。(-M
包括對系統頭文件的依賴,-MM
不包括。下面要說的-MD
和-MMD
也是同樣的關係。)生成的依賴文件還須要用腳本作一些修改,以保證後期修改了代碼以後,依賴文件可以從新生成。ci
煩人的地方就是用腳本修改依賴文件,有這樣改的:get
%.o: %.c gcc -c $(CFLAGS) $*.c -o $*.o gcc -MM $(CFLAGS) $*.c > $*.d @cp -f $*.d $*.d.tmp @sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | \ sed -e 's/^ *//' -e 's/$$/:/' >> $*.d @rm -f $*.d.tmp
也有這樣改的:編譯器
%.d: %.c @set -e; rm -f $@; \ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$
須要拋棄的緣由不言而喻。。。
目前最好的方案,是利用gcc的選項-MMD
來自動生成依賴文件。這個早該普及的方法其實沒那麼多人知道,常常見到有人在死記sed命令。其實gcc早就提供更好的方式了。只要加上萌萌的-MMD
選項,會在編譯的過程當中順便生成依賴文件。沒有手動修改依賴文件的必要,依賴文件總能正確地從新生成。
就是像下面這樣寫:
TARGET := foo CC := gcc LDLIBS := -lm CFLAGS := -MMD -MP SRCS := $(wildcard *.c) OBJS := $(SRCS:.c=.o) DEPS := $(SRCS:.c=.d) .PHONY: all clean all: $(TARGET) $(TARGET): $(OBJS) -include $(DEPS) clean: rm -f $(OBJS) $(DEPS) $(TARGET)
能夠和前面的「萬能Makefile」對比一下:
只是簡單添加了幾行。要注意-include $(DEPS)
不能放在all
規則以前,all
必須是第一個規則嘛。
還有要提一下的是選項-MP
,它的做用是爲頭文件生成這樣的依賴規則:
bar.h:
空的,沒有依賴,沒有動做,但並非沒有做用。若是沒有這個規則,萬一誤刪了bar.h,或者更名了,而foo.c忘了改,make會這樣提示:
勉強能接受?可要是加上-MP
選項,提早生成了上面那個空的規則,make會繼續執行,而後讓編譯器給出更準確的錯誤信息:
因此沒事仍是把-MP
加上吧。。。
本文同步自:http://suosuopuo.com/2015/01/01/makefile-dependencies/