如何强制某些目标组始终按顺序运行?

时间:2014-02-17 14:45:57

标签: parallel-processing makefile gnu-make ghc

有没有办法让gmake永远不会从一个集合并行运行两个目标?

我不想使用.NOTPARALLEL,因为它强制整个Makefile按顺序运行,而不仅仅是所需的部分。

我还可以添加依赖项,以便一个依赖于另一个,但随后(除了uglu)我需要构建所有它们以构建最后一个,这是不必要的。


我需要这个的原因是我的Makefile的一部分(只有一部分)调用了ghc --make,它会自己处理它的依赖关系。并且不可能在两个不同的目标上并行运行它,因为如果两个目标共享一些依赖关系,它们可以重写彼此的.o文件。 (但ghc可以按顺序调用。)

更新:举一个具体的例子。假设我需要在Makefile中编译两个程序:

  • prog1取决于prog1.hsmylib.hs;
  • prog2取决于prog2.hsmylib.hs

现在,如果我调用ghc --make prog1.hs,它会检查其依赖关系,将prog1.hsmylib.hs编译到各自的对象和接口文件中,并链接prog1。当我打电话给ghc --make prog2.hs时也是如此。因此,如果两个命令并行运行,则会覆盖另一个命令mylib.o,导致其失败。

但是,我需要prog1取决于prog2,反之亦然,因为它们应该单独编译。 (实际上它们非常庞大,有很多模块,需要编译它们都会大大减慢开发速度。)

4 个答案:

答案 0 :(得分:5)

嗯,可以做更多的信息,所以这只是在黑暗中刺伤。

Make并不真正支持这一点,但你可以通过几种方式顺序推出两个目标。首先,真正用于递归make:

targ1: ; recipe1...
targ2: ; recipe2...

both-targets:
    ${MAKE} targ1
    ${MAKE} targ2

所以在这里你可以make -j both-targets,一切都很好。但是很脆弱,因为make -j targ1 targ2仍然并行运行。您可以改为使用依赖项:

targ1: ; recipe1...
targ2: | targ1 ; recipe2...

现在make -j targ1 targ2可以满足您的需求。坏处? make targ2将始终首先尝试构建targ1(按顺序)。这可能(或可能不是)对你来说是一个阻碍。

修改

另一个不令人满意的策略是明确查看$MAKECMDGOALS,其中列出了您在命令行中指定的目标。仍然是一个脆弱的解决方案,因为当有人在 Makefile 中使用依赖项来构建内容时(这是一种非无理的操作)它会被破坏。

假设您的makefile包含两个独立目标targ1targ2。基本上它们保持独立,直到有人在命令行上指定它们必须构建。在这种特殊情况下,你打破了这种独立性请考虑以下代码段:

$(and $(filter targ1,${MAKECMDGOALS)),$(filter targ2,${MAKECMDGOALS}),$(eval targ1: | targ2))

的Urk!这是怎么回事?

  • 制作评估$(and)
  • 首先必须展开$(filter targ1,${MAKECMDGOALS})
  • Iff targ1 指定,继续展开$(filter targ2,${MAKECMDGOALS})
  • Iff targ2指定 ,继续展开$(eval),强制targ1targ2的序列化。
    • 请注意,$(eval)扩展为空(所有工作都是作为副作用完成的),因此原始$(and)总是扩展为空,不会导致语法错误。

唉!

[现在我输入了这个,相当简单prog2: | $(filter prog1,${MAKECMDGOALS}) 发生在我身上。哦,好吧。]

YMMV以及所有这些。

我不熟悉 ghc ,但正确的解决方案是让ghc的两次运行使用不同的构建文件夹,然后他们可以愉快地并行运行。

答案 1 :(得分:3)

由于我遇到了同样的问题,这里有另一个指针make没有提供你描述的功能:

来自GNU Make Manual

  

使用并行执行(-j开关;请参阅并行执行)和存档时要小心。如果多个ar命令同时在同一个存档文件上运行,则它们不会彼此了解并且可能损坏该文件。

     

未来的make版本可能会提供一种机制来通过序列化在同一个存档文件上运行的所有配方来规避这个问题。但是暂时,您必须编写makefile以避免以其他方式出现此问题,或者不要使用-j。

您正在尝试的内容以及我尝试的内容(使用make在SQLite3数据库中插入数据)会遇到完全相同的问题。

答案 2 :(得分:0)

我需要将编译与其他步骤(清理,构建目录和链接)分开,因为我想使用更多核心进程和-j标志运行编译。

我设法用不同的makefile来解决这个问题,包括相互调用。只有“ compile” make文件与所有内核并行运行,其余过程是同步的。

我将我的makefile分为3个单独的脚本:

  • settings.mk :包含所有变量和标志定义
  • makefile :具有除编译目标(具有.NOTPARALLEL指令)之外的所有目标。它使用-j标志调用compile.mk
  • compile.mk :仅包含编译操作(不包含.NOTPARALLEL)

settings.mk 中,我有:

CC = g++
DB = gdb
RM = rm
MD = mkdir
CP = cp
MAKE = mingw32-make
BUILD = Debug
DEBUG = true

[... all other variables and flags needed, directories etc ...]

makefile 中,我具有以下链接和编译目标:

include .makefiles/settings.mk

[... OTHER TARGETS (clean, directories etc)]

compilation:
    @echo Compilation
    @$(MAKE) -f .makefiles/compile.mk --silent -j 8 -Oline

#Link
$(TARGET): compilation
    @echo -e Linking $(TARGET)
    @$(CC) $(LNKFLAGS) -o $(TARGETDIR)/$(TARGET) $(OBJECTS) $(LIBDIRS) $(LIB)

#Non-File Targets
.PHONY: all prebuild release rebuild clean resources directories run debug

.NOTPARALLEL: all

 # include dependency files (*.d) if available
 -include $(DEPENDS)

这是我的 compile.mk

include .makefiles/settings.mk

#Defauilt
all: $(OBJECTS)

#Compile
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
    @echo -e Compiling: $<
    @$(MD) -p $(dir $@)
    @$(CC) $(COMFLAGS) $(INCDIRS) -c $< -o $@

#Non-File Targets
.PHONY: all

# include dependency files (*.d) if available
-include $(DEPENDS)

直到现在,它一直在工作。

请注意,我正在使用-j标志和-Oline调用compile.mk,以便并行处理不会弄乱输出。

由于-O标志使转义颜色代码无效,因此可以在makefile主脚本中设置任何语法颜色。

我希望它能提供帮助。

答案 3 :(得分:0)

我遇到了类似的问题,所以最终在命令行上解决了它,如下所示:

make target1; make target2

强制它按顺序执行目标。