Makefile依赖性不会触发重建

时间:2018-11-06 23:42:04

标签: makefile dependencies

我想将.h文件作为给定.o文件的依赖项包括在内。我遵循these instructions,并将其调整为我的Makefile。但是,当我执行touch myhfile.h时,不会重建对应的.o文件。在我看来,依赖项是正确的,并包含在Makefile中。只是无法弄清楚为什么它不起作用。任何帮助表示赞赏。 Makefile包含在下面

ROOT=.

BUILDDIR=$(ROOT)/build
LIBDIR=$(BUILDDIR)/lib
OBJDIR=$(BUILDDIR)/obj
INCLUDEDIR=$(BUILDDIR)/include
DEPDIR=$(BUILDDIR)/dep
LIB=mylib
XCOMPILE=arm-linux-gnueabihf-
CC=$(XCOMPILE)gcc
AR=$(XCOMPILE)ar

DEPFLAGS+=\
          -MT $@ \
          -MMD \
          -MP \
          -MF \
          $(DEPDIR)/$*.Td

CFLAGS+=\
        -Wall \
        -Wextra \
        -Werror \
        -pedantic \
        -std=gnu11 \
        -fPIC

CPPFLAGS+=\
          $(INCLUDE)


SRCDIRS+=\
     $(ROOT)/../3rdparty/log/src \
     $(ROOT)/LTC2947/src \
     $(ROOT)/i2c/src \
     $(ROOT)/spi/src \
     $(ROOT)/sensors/src \
     $(ROOT)/telegraf/src \
     $(ROOT)/uart-packet/src \
     $(ROOT)/STCN75/src \
     $(ROOT)/utils/src

DEPDIRS+=\
         $(SRCDIRS) \
         $(ROOT)/addresses-ports/src

VPATH+=\
       $(SRCDIRS)

SRC+=$(shell find $(SRCDIRS) -type f -name "*\.c")
DEP+=$(shell find $(DEPDIRS) -type f -name "*\.h")

OBJ=$(patsubst %.c, $(OBJDIR)/%.o, $(notdir $(SRC)))
INCLUDE=$(addprefix -I,$(sort $(dir $(DEP))))

POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $@

release: CFLAGS+=-O3
release: all

debug: CFLAGS+=-ggdb
debug: CPPFLAGS+=-DDEBUG
debug: all

all: lib include

lib: $(LIBDIR)/$(LIB).a $(LIBDIR)/$(LIB).so

include: $(INCLUDEDIR)

$(LIBDIR)/$(LIB).a: $(OBJ) | $(LIBDIR)
    $(AR) rcs $@ $^

$(LIBDIR)/$(LIB).so: $(OBJ) | $(LIBDIR)
    $(CC) $(CPPFLAGS) $(CFLAGS) -shared $(LDFLAGS) -lc $^ -o $@

$(INCLUDEDIR): $(DEP)
    if [[ ! -d $@ ]]; then mkdir -p $@; fi
    cp $^ $@
    touch $@

%.o: %.c
$(OBJDIR)/%.o: %.c $(DEPDIR)/%.d | $(DEPDIR) $(OBJDIR)
    $(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
    $(POSTCOMPILE)

$(DEPDIR):
    mkdir -p $@

$(LIBDIR):
    mkdir -p $@

$(OBJDIR):
    mkdir -p $@

.PHONY: clean
clean:
    rm -rf $(BUILDDIR)

$(DEPDIR)/%.d: ;
.PRECIOUS: $(DEPDIR)/%.d

include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC))))

编辑

$(info $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC)))))产生了一个空字符串。 $(info $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC))))生成了正确的依赖项列表

./build/dep/./../3rdparty/log/src/log.d ./build/dep/./uart-packet/src/uart_packet.d ./build/dep/./utils/src/utils.d ./build/dep/./telegraf/src/telegraf.d ./build/dep/./i2c/src/myproject_i2c.d ./build/dep/./spi/src/myproject_spi.d ./build/dep/./LTC2947/src/LTC2947.d ./build/dep/./sensors/src/sensors.d ./build/dep/./STCN75/src/STCN75.d

所以我删除了$(wildcard ...) function

但是那不能解决问题。

为了测试它,我决定运行:

1. make clean
2. make 
3. touch telegraf/src/telegraf.h
4. make build/obj/telegraf.d
5. make build/obj/telegraf.Td
6. make build/obj/telegraf.o

步骤1-3工作正常。但是步骤4-6无效。

步骤4产生以下结果:

make: *** No rule to make target 'buid/dep/telegraf.d'.  Stop.

步骤5产生以下结果:     make:***没有将目标设为“ buid / dep / telegraf.Td”的规则。停止。

第6步根本没有重建目标。

在第2步之后,我查看了build / dep / telegraf.d,这是我所拥有的:

$ cat build/dep/telegraf.d
build/obj/telegraf.o: telegraf/src/telegraf.c ../3rdparty/log/src/log.h \
 telegraf/src/telegraf.h utils/src/utils.h

../3rdparty/log/src/log.h:

telegraf/src/telegraf.h:

utils/src/utils.h:

在我看来,依赖关系是正确生成的。

我还尝试运行make -d build/obj/telegraf.o。不幸的是,我不能为此发布整个输出(stackoverflow不允许它,消息变得很大)。但是,这是输出的结尾。 (对于感兴趣的人,可以看到完整的输出here

  No need to remake target 'telegraf.c'; using VPATH name './telegraf/src/telegraf.c'.
  Considering target file 'build/dep/telegraf.d'.
   Looking for an implicit rule for 'build/dep/telegraf.d'.
   Trying pattern rule with stem 'telegraf'.
   Found an implicit rule for 'build/dep/telegraf.d'.
   Finished prerequisites of target file 'build/dep/telegraf.d'.
  No need to remake target 'build/dep/telegraf.d'.
  Considering target file 'build/dep'.
   Finished prerequisites of target file 'build/dep'.
  No need to remake target 'build/dep'.
  Considering target file 'build/obj'.
   Finished prerequisites of target file 'build/obj'.
  No need to remake target 'build/obj'.
 Finished prerequisites of target file 'build/obj/telegraf.o'.
 Prerequisite './telegraf/src/telegraf.c' is older than target 'build/obj/telegraf.o'.
 Prerequisite 'build/dep/telegraf.d' is older than target 'build/obj/telegraf.o'.
 Prerequisite 'build/dep' is order-only for target 'build/obj/telegraf.o'.
 Prerequisite 'build/obj' is order-only for target 'build/obj/telegraf.o'.
No need to remake target 'build/obj/telegraf.o'.
make: 'build/obj/telegraf.o' is up to date.

看来这是问题,Prerequisite 'build/dep/telegraf.d' is older than target 'build/obj/telegraf.o'.。我需要以某种方式使它更年轻,但是我不确定如何。

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

不幸的是,您在这里跑错了方向:)。

您不应该删除$(wildcard ...);需要/想要的。

它返回空字符串的事实是您遇到的 THE 问题,而不仅仅是删除它,您需要弄清楚原因并修复它。您的.d文件看起来像./build/dep/./../3rdparty/log/src/log.d的事实是问题所在……这不是您要创建的.d文件的路径。您正在创建类似./build/dep/log.d

的文件

问题是这样的:您正在使用此规则在配方中创建.d个文件:

POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $@

在这里,$*是文件的茎,因此对于./build/obj/log.o$*的值为log。因此,您正在创建./build/dep/log.d

但是在包含行中将SRC变量转换为.d文件时,可以使用basename函数。这只是去除路径的后缀,不会删除目录。因此,如果您的源文件是./../3rdparty/log/src/log.c,则basename会产生./../3rdparty/log/src/log,并且您的通配符匹配错误的内容。

您需要像这样计算包含行的通配符:

include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(notdir $(basename $(SRC)))))

也添加notdir以剥离路径,这将为您提供所需的依赖文件:./build/dep/log.d等。