在对应目录中放入对应的文件
/× foo.h */ #ifndef __FOO_H #define __FOO_H void foo(void) #endif/*__FOO_H*/ /* foo.c */ #include <stdio.h> #include "foo.h" void foo(void) { printf("This is foo()!\n"); } /* main.c */ #include "foo.h" int main(void) { return 0; }
执行make后报错:
这是在构建依赖文件时,gcc因为找不到foo.h而报错。那是因为foo.h和foo.c放在不同的目录中,这样需要使用gcc的 -I 选项,指定包含路径,所以,更改后的Makefile如下:
.PHONY: all clean MKDIR = mkdir RM = rm RMFLAGS =-rf CC = gcc AR = ar ARFLAGS = crs DIR_OBJS = objs DIR_EXES = $(ROOT)/build/exes DIR_DEPS = deps DIR_LIBS = $(ROOT)/build/libs DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS) $(DIR_LIBS) RMS = $(DIR_OBJS) $(DIR_DEPS) ifneq ("$(EXE)", "") EXE := $(addprefix $(DIR_EXES)/, $(EXE)) RMS += $(EXE) endif ifneq ("$(LIB)", "") LIB := $(addprefix $(DIR_LIBS)/, $(LIB)) RMS += $(LIB) endif SRCS = $(wildcard *.c) OBJS = $(SRCS:.c=.o) OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS)) DEPS = $(SRCS:.c=.dep) DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS)) ifeq ("$(wildcard $(DIR_OBJS))", "") DEP_DIR_OBJS := $(DIR_OBJS) endif ifeq ("$(wildcard $(DIR_EXES))", "") DEP_DIR_EXES := $(DIR_EXES) endif ifeq ("$(wildcard $(DIR_DEPS))", "") DEP_DIR_DEPS := $(DIR_DEPS) endif ifeq ("$(wildcard $(DIR_LIBS))", "") DEP_DIR_LIBS := $(DIR_LIBS) endif all: $(EXE) $(LIB) ifneq ($(MAKECMDGOALS), clean) include $(DEPS) endif ifneq ("$(INCLUDE_DIRS)", "") INCLUDE_DIRS := $(strip $(INCLUDE_DIRS)) INCLUDE_DIRS := $(addprefix -I, $(INCLUDE_DIRS)) endif $(DIRS): $(MKDIR) $@ $(EXE): $(DEP_DIR_EXES) $(OBJS) $(CC) -o $@ $(filter %.o, $^) $(LIB): $(DEP_DIR_LIBS) $(OBJS) $(AR) $(ARFLAGS) $@ $(filter %.o, $^) $(DIR_OBJS)/%.o: $(DEP_DIR_OBJS) %.c $(CC) $(INCLUDE_DIRS) -o $@ -c $(filter %.c, $^) $(DIR_DEPS)/%.dep: $(DEP_DIR_DEPS) %.c @echo "Creating $@ ..." @set -e ; \ $(RM) $(RMFLAGS) $@.tmp ; \ $(CC) $(INCLUDE_DIRS) -E -MM $(filter %.c, $^) > $@.tmp ; \ sed 's,\(.*\)\.o[ :]*,objs/\1.o $@: ,g' < $@.tmp > $@ ; \ $(RM) $(RMFLAGS) $@.tmp clean: $(RM) $(RMFLAGS) $(RMS)
这样就完成了支持头文件目录指定。
从Makefile的角度看,一个可以改善编译效率的地方与其中的隐式规则有关。为了了解make的隐式规则,我们把之前的simple项目的Makefile做一点更改,删除生成.o文件的规则(与隐式规则相对应的是,在Makefile中定义的规则称为显示规则)。
.PHONY: clean CC = gcc RM = rm EXE =simple SRCS =$(wildcard *.c) OBJS =$(patsubst %.c, %.o, $(SRCS)) $(EXE): $(OBJS) $(CC) -o $@ $^ #\ %.o : %.c\ $(CC) -o $@ -c $^删除这两句 clean: $(RM) -rf $(EXE) $(OBJS)
我们make一下,还是成功了,这就是make存在自带的隐式规则的缘故。
在make中存在大量的隐式规则,通过隐式规则将大大简化Makefile的编写。这里简化后的Makefile之所以能工作,是因为make中有着下面这样的隐式规则:
%.o :%.c
$(CC) -c $(CPPFLAGS) $(CFLAGS) $^
make需要查找隐式规则会降低编译效率,为了禁止使用make所自带的隐式规则,可以通过make 的 -r选项来实现。
所以,隐式规则是可以被覆盖的。当Makefile中自己定义了生成.o的文件规则时,make就以它为规则,该规则覆盖了make自带的隐式规则。更多隐式规则可以查看GNU MAKE。make -r的使用可以提高每个源文件的编译效率。
恰当的书写注释是个好习惯。
Makefile中的注释以“#”开始,注释多行可以在行末加上"\"。