在GNU make管理的項目中萌萌地處理頭文件依賴

如下要說的顯然是C語言的項目。html

固然能夠考慮用其餘工具替代make,好比SCons和CMake,或者auto tools什麼的,但不少時候手寫Makefile仍是很是乾淨利索,爽快好用的,尤爲在項目比較小的時候。工具

規模一旦擴大,確實寫Makefile就有點費勁了。比較突出的一個問題是對頭文件的依賴。make本身是沒有辦法處理的,必需要藉助編譯器。post

如下會列舉三種常見的Makefile寫法。後兩種處理了對頭文件的依賴,推薦使用最後一種。spa

項目結構

說下演示用的項目,只包含三個代碼文件,結構以下:code

.
├── bar.c
├── bar.h
├── foo.c
└── Makefile

bar.h

#ifndef _BAR_H_
#define _BAR_H_

void bar(void);

#endif

bar.c

#include <stdio.h>

void bar(void)
{
    printf("bar!\n");
}

foo.c

#include <stdio.h>
#include "bar.h"

int main()
{
    printf("foo -> ");
    bar();
    return 0;
}

1. 不考慮頭文件依賴的Makefile

若是不處理對頭文件的依賴,能夠寫出相似下面這樣的「萬能Makefile」,作作小東西無往不利。
缺陷是頭文件修改了之後不能自動從新編譯,須要不斷make clean && makehtm

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)

2. gcc + sed

這是一種應該拋棄的方案,詳細的步驟分解能夠看這篇文章:Autodependencies with GNU makeblog

簡要歸納下,就是利用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 $@.$$$$

須要拋棄的緣由不言而喻。。。

3. MMD萌萌的

目前最好的方案,是利用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/

相關文章
相關標籤/搜索