在使用makefile 自動生成頭文件依賴是,大家多半使用了下面這個方法。
這個sed語句被稱之爲 "上帝的符號",可讀性不言而喻。(PS:CSDN這個排版怎麼也搞不好,只能用圖片了。)
gcc的 -MMD 選項可以自動生成帶有依賴規則的.d文件,爲創建頭文件依賴帶來了方便。示例如下:
CC = gcc
TARGET = main.out
LDLIBS = -m32 -Wl,--as-needed
CFLAGS = -m32 -g -MMD -MP -Wall -c
SRCS = main.c
ODIR = ./objs
OBJS = $(addprefix $(ODIR)/,$(SRCS:.c=.o))
DEPS = $(addprefix $(ODIR)/,$(SRCS:.c=.d))
.PHONY: all clean $(ODIR)
all: $(ODIR) $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDLIBS) $(OBJS) -o $@
$(ODIR)/%.o: %.c
$(CC) $(CFLAGS) -o $@ $<
-include $(DEPS)
$(ODIR):
@test -d $@ || mkdir -p $@
clean:
rm -rf $(ODIR)
rm -f $(TARGET)
測試代碼:/*main.c*/
#include <stdio.h>
#include "test.h"
int main(int argc, char *argv[])
{
printf("hello world! xtest=%d\n", xtest);
return 0;
}
/*test.h*/
#define xtest (1)
[root@ubuntu:makefile]# ll
總用量 20
drwxr-xr-x 2 root root 4096 Oct 26 16:42 ./
drwxr-xr-x 8 root root 4096 Oct 25 17:36 ../
-rw-r--r-- 1 root root 136 Oct 26 16:09 main.c
-rwxr--r-- 1 root root 488 Oct 26 16:18 makefile*
-rw-r--r-- 1 root root 20 Oct 26 16:09 test.h
[root@ubuntu:makefile]# make
gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
gcc -m32 -Wl,--as-needed ./objs/main.o -o main.out
[root@ubuntu:makefile]# cat ./objs/main.d
objs/main.o: main.c test.h
test.h:
[root@ubuntu:makefile]# touch test.h
[root@ubuntu:makefile]# make
gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
gcc -m32 -Wl,--as-needed ./objs/main.o -o main.out
[root@ubuntu:makefile]#
原理分析:gcc -MMD -MP *.c 生成帶有頭文件依賴關係的*.d
展開這個makefile的關鍵部分
CC = gcc
TARGET = main.out
LDLIBS = -m32 -Wl,--as-needed
CFLAGS = -m32 -g -MMD -MP -Wall -c
SRCS = main.c
ODIR = ./objs
OBJS = $(addprefix $(ODIR)/,$(SRCS:.c=.o))
DEPS = $(addprefix $(ODIR)/,$(SRCS:.c=.d))
.PHONY: all clean $(ODIR)
all: $(ODIR) $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDLIBS) $(OBJS) -o $@
#$(ODIR)/%.o: %.c
objs/main.o: main.c
# $(CC) $(CFLAGS) -o $@ $<
gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
#-include $(DEPS)
#-include main.d
objs/main.o: main.c test.h #-MMD選項生成
test.h: #-MP 選項生成
$(ODIR):
@test -d $@ || mkdir -p $@
clean:
rm -rf $(ODIR)
rm -f $(TARGET)
合併相同的目標,makefile的最終形式爲:
CC = gcc
TARGET = main.out
LDLIBS = -m32 -Wl,--as-needed
CFLAGS = -m32 -g -MMD -MP -Wall -c
SRCS = main.c
ODIR = ./objs
OBJS = $(addprefix $(ODIR)/,$(SRCS:.c=.o))
DEPS = $(addprefix $(ODIR)/,$(SRCS:.c=.d))
.PHONY: all clean $(ODIR)
all: $(ODIR) $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDLIBS) $(OBJS) -o $@
objs/main.o: main.c test.h
gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
test.h:
$(ODIR):
@test -d $@ || mkdir -p $@
clean:
rm -rf $(ODIR)
rm -f $(TARGET)
關於test.h:
如果沒有這個目標,當頭文件被刪除或者忘了包含時,make報錯如下:
[root@ubuntu:makefile]# make
gcc -m32 -g -MMD -Wall -c -o objs/main.o main.c
gcc -m32 -Wl,--as-needed ./objs/main.o -o main.out
[root@ubuntu:makefile]#
[root@ubuntu:makefile]#
[root@ubuntu:makefile]#
[root@ubuntu:makefile]# mv test.h test.x
[root@ubuntu:makefile]# make
make: *** 沒有規則可以創建“objs/main.o”需要的目標“test.h”。 停止。
[root@ubuntu:makefile]#
加上test.h: make報錯如下:
[root@ubuntu:makefile]# make
gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
gcc -m32 -Wl,--as-needed ./objs/main.o -o main.out
[root@ubuntu:makefile]#
[root@ubuntu:makefile]# mv test.h test.x
[root@ubuntu:makefile]# make
gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
main.c:3:18: fatal error: test.h: 沒有那個文件或目錄
#include "test.h"
^
compilation terminated.
make: *** [objs/main.o] 錯誤 1
[root@ubuntu:makefile]#
因爲目標test.h 沒有對應的規則,所以make會繼續向下進行,從而準確的定位出產生錯誤的原因。