makefile 自动生成头文件依赖关系

时间:2022-11-20 12:50:17

在使用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总用量 20drwxr-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]# makegcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.cgcc -m32 -Wl,--as-needed ./objs/main.o -o main.out[root@ubuntu:makefile]# cat ./objs/main.dobjs/main.o: main.c test.htest.h:[root@ubuntu:makefile]# touch test.h[root@ubuntu:makefile]# makegcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.cgcc -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会继续向下进行,从而准确的定位出产生错误的原因。