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

Parallel processing 如何强制某些目标组始终按顺序运行?,parallel-processing,makefile,gnu-make,ghc,Parallel Processing,Makefile,Gnu Make,Ghc,有没有办法让gmake永远不要在一个集合中同时运行两个目标 我不想使用.NOTPARALLEL,因为它强制整个Makefile按顺序运行,而不仅仅是必需的部分 我还可以添加依赖项,以便一个依赖于另一个,但是(除了丑陋之外)我需要构建所有依赖项,以便构建最后一个,这是不必要的 我之所以需要它,是因为(只有一部分)我的Makefile调用了ghc--make,它自己处理它的依赖关系。而且不可能在两个不同的目标上并行运行它,因为如果两个目标共享一些依赖关系,它们可以重写彼此的.o文件。(但是按顺序调

有没有办法让gmake永远不要在一个集合中同时运行两个目标

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

我还可以添加依赖项,以便一个依赖于另一个,但是(除了丑陋之外)我需要构建所有依赖项,以便构建最后一个,这是不必要的


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

更新:以给出具体示例。假设我需要在Makefile中编译两个程序:

  • prog1
    取决于
    prog1.hs
    mylib.hs
  • prog2
    取决于
    prog2.hs
    mylib.hs
现在,如果我调用,它将检查其依赖项,将
prog1.hs
mylib.hs
编译到各自的对象和接口文件中,并链接
prog1
。调用
ghc--makeprog2.hs
时也会发生同样的情况。因此,如果这两个命令并行运行,其中一个将覆盖另一个命令的
mylib.o
,导致它严重失败


但是,我需要
prog1
既不依赖于
prog2
,也不依赖于
prog2
,因为它们应该可以单独编译。(实际上,它们非常大,有很多模块,需要编译它们,这大大降低了开发速度。)

Hmmm,可能需要更多的信息,所以这只是一个暗中操作

Make并不真正支持这一点,但您可以通过几种方式实现两个目标。首先,递归make的真正用途是:

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

both-targets:
    ${MAKE} targ1
    ${MAKE} targ2
因此,在这里,您只需
使-j成为两个目标
,一切都很好。但是很脆弱,因为
make-jtarg1targ2
仍然并行运行。您可以改为使用依赖项:

targ1: ; recipe1...
targ2: | targ1 ; recipe2...
现在
make-jtarg1targ2
做你想做的事。劣势<代码>生成targ2将始终尝试先(按顺序)生成
targ1
。这可能(也可能不是)会阻碍你的表演

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

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

$(and $(filter targ1,${MAKECMDGOALS)),$(filter targ2,${MAKECMDGOALS}),$(eval targ1: | targ2))
乌尔克!这是怎么回事

  • Make评估
    $(和)
  • 它首先必须展开
    $(过滤器arg1,${MAKECMDGOALS})
  • 如果指定了
    targ1
    ,它将继续展开
    $(过滤器targ2,${MAKECMDGOALS})
  • 如果还指定了
    targ2
    ,它将继续扩展
    $(eval)
    ,强制序列化
    targ1
    targ2
    • 请注意,
      $(eval)
      扩展为零(其所有工作都是作为副作用完成的),因此原始的
      $(and)
      始终扩展为零,不会导致语法错误

[现在我已经输入了,非常简单的
prog2:|$(filter prog1,${MAKECMDGOALS})
我想到了。哦,好吧

YMMV等等


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

由于我遇到了相同的问题,这里有另一个指向
make
不提供您描述的功能的方向的指针:

从:

在使用并行执行(-j开关;请参阅并行执行)和归档时,务必小心。如果在同一存档文件上同时运行多个ar命令,它们将互不了解,并可能损坏文件

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


您正在尝试的和我正在尝试的(使用make在SQLite3数据库中插入数据)都遇到了完全相同的问题。

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

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

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

  • settings.mk:包含所有变量和标志定义
  • makefile:具有除编译目标以外的所有目标(它具有.NOTPARALLEL指令)。它使用-j标志调用compile.mk
  • compile.mk:仅包含编译操作(不含.NOTPARALLEL)
设置.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)
include.makefile/settings.mk
#脱脂
全部:$(对象)
#编撰
$(BUILDDIR)/%.$(OBJEXT):$(SRCDIR)/%.$(SRCE)