1

我正在编写一个生成文件来处理构建单元 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 的提示。

4

2 回答 2

0

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

于 2013-09-17T15:32:36.287 回答
0

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

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

这些规则:

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/and TWO/include/,因为它们只会带来头痛。那么这里的规则可以是

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

ONE/和中的makefileTWO/可以参考LIB/src/

于 2013-09-17T16:34:10.227 回答