我正在编写一个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)
如何将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的提示。
答案 0 :(得分:0)
对于问题1:可能需要移动LIB_HEADERS定义并将规则更改为
%.a%.h:$(LIB_HEADERS)
?
答案 1 :(得分: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/
和TWO/include/
,因为它们只带来头痛。那么这里的规则可以是
ONE TWO: % : %/lib/libLIB.a $(LIB_HEADERS)
@echo ---------- Compiling $@ ----------
@cd $@ && gmake.exe
并且ONE/
和TWO/
中的makefile可以引用LIB/src/
。