首页 文章

Makefile依赖修改检测

提问于
浏览
1

我正在编写一个makefile来处理构建单元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)

  • 当我对LIB / src中的一个头文件进行更改时,make怎么没有运行规则"%.a %.h:"?

  • 如何将ONE和TWO概括为单个规则?我想这样做(但目标不能在依赖项中使用,至少这种方式):

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

UPDATE:

我找到了解决方案,退一步,绘制有向无环图,并考虑单个文件,而不是某种类型的所有文件 .

以下是(非常优雅)解决方案,为了完整性:

.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的提示 .

2 回答

  • 0

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

  • 0

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

    当您在 LIB/src/ 中更改头文件时Make不运行此 %.a %.h: 规则的原因是此规则没有依赖关系,并且此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
    

    But don't do this. 相反,消除 ONE/include/TWO/include/ ,因为它们只带来头痛 . 然后这里的规则可以

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

    ONE/TWO/ 中的makefile可以引用 LIB/src/ .

相关问题