makefile 自動生成頭文件依賴關係

在使用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會繼續向下進行,從而準確的定位出產生錯誤的原因。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章