【问题标题】:Makefile dependency modification detectionMakefile依赖修改检测
【发布时间】:2013-09-22 00:08:01
【问题描述】:

我正在编写一个生成文件来处理构建单元 ONE 和 TWO 的依赖关系 -> 构建单元 LIB。

“构建单元”是指包含目录 src、lib、include 和 bin 的目录,以及用于在 src 中编译源代码的 makefile。库放在“lib”中,库头文件放在“include”中。编译后的二进制文件放在“bin”中。构建单元接受“make”、“make all”、“make lint”和“make clean”。

当 LIB 中的头文件发生更改时,此 makefile 旨在检测它并在编译之前重新编译 + 安装(将 .a+.h 文件复制到 ONE 和 TWO)新版本的 LIB。

.PHONY: ONE TWO CLEAN LINT

ALL: ONE TWO

%.a %.h:
    @echo ---------- Compiling LIB ----------
    @cd LIB && gmake.exe LIB

LIB_HEADERS := $(wildcard LIB/src/*.h)

ONE: ONE/lib/libLIB.a $(subst LIB/src/,ONE/include/,$(LIB_HEADERS))
    @echo ---------- Compiling $@ ----------
    @cd $@ && gmake.exe

TWO: TWO/lib/libLIB.a $(subst LIB/src/,TWO/include/,$(LIB_HEADERS))
    @echo ---------- Compiling $@ ----------
    @cd $@ && gmake.exe

CLEAN LINT:
    @cd ONE && gmake.exe $@
    @cd TWO && gmake.exe $@
    @cd LIB && gmake.exe $@

(假设 LIB 的 makefile 处理复制到 ONE 和 TWO)

  1. 当我对 LIB/src 中的一个头文件进行更改时,为什么 make 不运行规则“%.a %.h:”?
  2. 如何将 ONE 和 TWO 概括为一条规则?我想这样做(但目标不能在依赖项中使用,至少这样):

    ONE TWO: $@/lib/libLIB.a $(subst LIB/src/,$@/include/,$(LIB_HEADERS))
        @echo ---------- Compiling $@ ----------
        @cd $@ && gmake.exe
    

更新:

我通过退后一步、绘制有向无环图并考虑单个文件而不是某种类型的所有文件来找到解决方案。

为了完整起见,这里是(不是很优雅的)解决方案:

.PHONY: ONE TWO CLEAN LINT

ALL: ONE TWO

LIB_HEADERS := $(sort $(subst name.h,,$(wildcard LIB/src/*.h)))

# ------------------------------------------------------------
ONE/include/%.h: LIB/src/%.h
    @echo Copying $< to $@
    @mkdir ONE\\include 2> NUL || :)
    @copy $(subst /,\,$<) ONE\\include\\ 1> NUL

TWO/include/%.h: LIB/src/%.h
    @echo Copying $< to $@
    @mkdir TWO\\include 2> NUL || :)
    @copy $(subst /,\,$<) TWO\\include\\ 1> NUL
# ------------------------------------------------------------
ONE/lib/liblib.a: LIB/bin/liblib.a
    @echo Copying $< to $@
    @mkdir ONE\\lib 2> NUL || :)
    @copy $(subst /,\,$<) ONE\\lib\\ 1> NUL

TWO/lib/liblib.a: LIB/bin/liblib.a
    @echo Copying $< to $@
    @mkdir TWO\\lib 2> NUL || :)
# Windows-equivalent of touch (discarding any output to stdout):
    @copy $(subst /,\,$<) TWO\\lib\\ 1> NUL
# ------------------------------------------------------------
LIB/bin/liblib.a: $(LIB_HEADERS) $(wildcard LIB/src/*.cpp)
    @echo ---------- Looking for changes to liblib ----------
    @cd LIB && gmake.exe LIB
    @copy /b $(subst /,\,$@) +,, 1> NUL || :)
# ------------------------------------------------------------
ONE: ONE/lib/liblib.a $(subst LIB/src/,ONE/include/,$(LIB_HEADERS))
    @echo ---------- Compiling ONE ----------
    @cd ONE && gmake.exe

TWO: TWO/lib/liblib.a $(subst LIB/src/,TWO/include/,$(LIB_HEADERS))
    @echo ---------- Compiling TWO ----------
    @cd TWO && gmake.exe
# ------------------------------------------------------------
CLEAN LINT:
    @cd ONE && gmake.exe $@
    @cd TWO && gmake.exe $@
    @cd LIB && gmake.exe $@

我非常欢迎关于如何进一步概括 ONE 和 TWO 的提示。

【问题讨论】:

    标签: makefile gnu-make


    【解决方案1】:

    对于问题 1:也许您需要将 LIB_HEADERS 定义向上移动并将规则更改为
    %.a %.h: $(LIB_HEADERS) ?

    【讨论】:

      【解决方案2】:

      很抱歉不得不告诉你,但你的构建系统是个怪物。您正试图通过过度使用递归 Make 来进行复杂的依赖处理;递归 Make 有其用途,但其缺点之一是它破坏了 Make 处理依赖项的本机能力。还有其他一些问题表明这个系统的作者并没有真正理解 Make 是如何工作的,或者一个好的 makefile 应该是什么样子。

      当您更改LIB/src/ 中的头文件时,Make 不运行此%.a %.h: 规则的原因是此规则没有依赖关系,并且此makefile 中的任何内容都不依赖于不存在的头文件。如果这对你来说没有意义,那么你就不明白 Make rules 是如何工作的。

      这些规则:

      ONE: ONE/lib/libLIB.a $(subst LIB/src/,ONE/include/,$(LIB_HEADERS))
          @echo ---------- Compiling $@ ----------
          @cd $@ && gmake.exe
      
      TWO: TWO/lib/libLIB.a $(subst LIB/src/,TWO/include/,$(LIB_HEADERS))
          @echo ---------- Compiling $@ ----------
          @cd $@ && gmake.exe
      

      可以组合成一条规则:

      ONE TWO: % : %/lib/libLIB.a $(addprefix %/include/,$(notdir $(LIB_HEADERS)))
          @echo ---------- Compiling $@ ----------
          @cd $@ && gmake.exe
      

      但不要这样做。相反,消除ONE/include/TWO/include/,因为它们只会带来头痛。那么这里的规则可以是

      ONE TWO: % : %/lib/libLIB.a $(LIB_HEADERS)
          @echo ---------- Compiling $@ ----------
          @cd $@ && gmake.exe
      

      ONE/TWO/ 中的makefile 可以参考LIB/src/

      【讨论】:

      • 当然可以吗?我说服自己的方法是认为包含文件夹中的头文件类似于 .o 文件,src 中的头文件类似于 .cpp 文件,而复制命令是编译器。区别在哪里?顺便说一句,是的,我是新手,我还没有声称其他任何东西。虽然我非常感谢这个建议,但听到“你不知道自己在做什么”是非常令人沮丧的。
      • @Chetic:请理解我是想帮忙,而不仅仅是扔石头。如果您编写了这个 makefile,那么您就是在走路之前尝试跑步,而您能做的最好的事情就是 stop 并尝试一些更适度的设计。我很乐意为您提供帮助,但我们必须从简单的开始,到复杂的阶段。我建议我们从LIB/开始。
      • 您能否进一步解释为什么不执行 %.a %.h 规则? ONE & TWO 的依赖关系符合模式,因此据我了解它应该执行。即使我将 $(LIB_HEADERS) 添加为依赖项(这意味着我想在修改它们时检测的头文件被明确列为依赖项),当我更改文件时规则也不会执行。
      • 我告诉过你,该规则不会被执行,因为(即使你添加了$(LIB_HEADERS)ONETWO 的先决条件存在。很抱歉,但我想我无能为力。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-14
      • 1970-01-01
      • 1970-01-01
      • 2017-10-03
      • 2012-03-23
      • 2023-03-13
      相关资源
      最近更新 更多