Makefile学习12——支持头文件目录制定

时间:2022-03-16 12:46:08

在对应目录中放入对应的文件

/×    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后报错:

Makefile学习12——支持头文件目录制定

这是在构建依赖文件时,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学习12——支持头文件目录制定

这样就完成了支持头文件目录指定。

从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存在自带的隐式规则的缘故。

Makefile学习12——支持头文件目录制定

在make中存在大量的隐式规则,通过隐式规则将大大简化Makefile的编写。这里简化后的Makefile之所以能工作,是因为make中有着下面这样的隐式规则:

 %.o :%.c
 
   $(CC) -c $(CPPFLAGS) $(CFLAGS)  $^

make需要查找隐式规则会降低编译效率,为了禁止使用make所自带的隐式规则,可以通过make 的 -r选项来实现。

Makefile学习12——支持头文件目录制定

所以,隐式规则是可以被覆盖的。当Makefile中自己定义了生成.o的文件规则时,make就以它为规则,该规则覆盖了make自带的隐式规则。更多隐式规则可以查看GNU MAKE。make -r的使用可以提高每个源文件的编译效率。

恰当的书写注释是个好习惯。

Makefile中的注释以“#”开始,注释多行可以在行末加上"\"。