【问题标题】:Makefile doesn't permit incremental buildMakefile 不允许增量构建
【发布时间】:2014-09-18 21:02:20
【问题描述】:

我有一个来自示例项目的 makefile,不幸的是,当项目中的任何单个文件发生更改时,它会强制重新构建。我对makefile没有很多经验,所以我不知道如何解决这个问题。

makefile 将要编译的文件定义为单个变量SRCS,如下所示。当然,这个列表中有大约 40 个文件,分布在很多不同的目录中。

SRCS = \
  ../../src/file1.c \
  ../../src/file2.c

然后它为每个.o 文件定义每个.c 文件生成的构建规则。

$(OBJ_PATH)/%.o: $(SRCS)
    $(CC) $(FLAGS) $(filter %/$(subst .o,.c,$(notdir $@)), $(SRCS)) -o $@

根据使用 -d 选项的 make run,当单个 .c 文件发生更改时,必须重新编译所有目标文件,因为 $(SRCS) 被定义为上面的依赖项。

如果单个文件更改只有 1 .o 文件必须重新编译,我该如何更改?

【问题讨论】:

  • 那么,我们的目标是将给定的源代码树扁平化为包含目标文件的单个输出目录(暗示文件名不能重复使用)?

标签: c makefile


【解决方案1】:

另一种解决方案是使用vpath。示例代码:

OBJ_PATH := build

SRCS := \
    src/foodir/foo.c \
    src/bardir/bar.c

OBJS := $(addprefix $(OBJ_PATH)/,$(notdir $(SRCS:%.c=%.o)))

vpath %.c $(dir $(SRCS))

all: $(OBJS)

$(OBJ_PATH)/%.o: %.c
    $(CC) $(FLAGS) $< -o $@

【讨论】:

    【解决方案2】:

    您的食谱是由熟悉 makefile 的人编写的;这几乎是正确的。一项更正是将$(filter) 语句移动到先决条件行。在这种情况下,这就是它需要的地方。

    设置完成后,您需要进行一些额外的调整,您可以在手册中阅读相关内容。所以,像这样:

    PERCENT := %
    .SECONDEXPANSION:
    $(OBJ_PATH)/%.o: $$(filter $$(PERCENT)/$$(subst .o,.c,$$(notdir $$@)), $(SRCS))
        $(CC) $(FLAGS) $< -o $@
    

    【讨论】:

      【解决方案3】:

      类似的方法也可以。

      SRCS = \
        ../../src/file1.c \
        ../../src/file2.c
      
      # Set prerequisites for each output .o file from the matching .c file
      $(foreach src,$(SRCS),$(eval $(OBJ_PATH)/$(notdir $(src:.c=.o)): $(src)))
      
      # Create pattern rule with no additional prerequisites.
      $(OBJ_PATH)/%.o:
          $(CC) $(FLAGS) $< -o $@
      

      所以我突然想到,从某种意义上说,更微小的变化将是:

      $(OBJ_PATH)/%.o: $(SRCS)
          file='$(filter %/$(subst .o,.c,$(notdir $@)), $?)'; [ "$$file" ] && \
          $(CC) $(FLAGS) "$$file" -o $@
      

      【讨论】:

      • 如果您想做出重大改变,那么是的,我比我更喜欢您的解决方案。我试图做尽可能少的改变,因为我认为意图是好的,只是执​​行有点南。
      • @MarkGaleck 确实,您的解决方案肯定比我的更改更小。我只是有点不合理地希望不惜一切代价避免 .SECONDEPANSION。 =)
      • 好吧,实际上,我所拥有的.SECONDEXPANSION 的用法是未记录的。如果您仔细阅读文档,则并不意味着您可以完全按照我正在做的事情做。但它应该是这样的,事实上,MadScientist 证实它“有效”。我同意,如果可以不用,最好不用。
      • @MarkGaleck 你的使用没有记录怎么办?
      • 好吧,手册上说的是“读取”makefile,然后构建依赖关系树,然后执行配方。诸如 $@ 之类的变量的值是在构建依赖树期间设置的,对于隐式规则,这会发生多次(树中的每个节点一次)。现在出现了“二次扩张”。手册只说,它发生在第一个之后。很明显,它将从普通变量的值开始,就像它们在第一阶段结束时一样。但是 $@ 呢?是否会发生第二次扩展...
      【解决方案4】:

      通常在 Makefile 中,您不会将特定的 .c 文件作为依赖项。

      通常,您将 .o 文件列为主要可执行文件的依赖项。

      Make 有确定如何从 .c 文件构建 .o 文件的内部规则, 你可以用你自己的特殊规则覆盖这些,或者通常只是改变一些 配置变量就足够了。

      关于制作的完整教程比我想在这个框中输入的要长,但是通过快速网络搜索可以找到其中的很多。

      【讨论】:

      • 这是不正确的,在 makefiles 中通常你会列出“特定的 .c 文件”作为先决条件(这是正确的词)。
      • make 可以(有时会有一些刺激)正确地将 .c 文件构建成类似命名的 .o 文件。如果该内置有效,则没有理由将其列为先决条件(但这样做并没有什么坏处)。您确实需要列出.h 文件/等。虽然(或使用自动依赖生成来为您执行此操作)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-09
      • 2021-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多