【问题标题】:makefile dependency doesn't trigger rebuildmakefile 依赖项不会触发重建
【发布时间】:2018-11-08 05:58:22
【问题描述】:

我希望将 .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'.。不知何故,我需要让它更年轻,但我不知道如何。

感谢任何帮助。

【问题讨论】:

  • 是否构建了相应的.d 文件? (实际名称会有所帮助。)
  • 如果您将$(info $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC))))) 添加到您的makefile 中,它会显示所有.d 文件吗?如果您查看build/dep/myfile.d 文件的内容,您是否看到列出了正确的先决条件?如果您运行make -d build/obj/myfile.o,您是否看到它正在查看您的头文件?仅仅基于这个makefile很难知道问题是什么:你需要调试它。由于您没有从 make 中得到错误,可能是根本找不到您的 .d 文件,或者 .d 文件的内容不正确。
  • @MadScientist 我添加了额外的信息。我认为这个错误是在 .h 文件被更改/触摸后重新生成 .d 文件。
  • @Beta 是的,它确实构建了一个相应的 .d 文件。我添加了额外的信息。

标签: makefile dependencies


【解决方案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 等。

【讨论】:

    猜你喜欢
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 2012-09-28
    • 2018-04-05
    • 1970-01-01
    • 2016-09-14
    • 2011-12-18
    • 1970-01-01
    相关资源
    最近更新 更多