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

问题描述 投票:11回答:3

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

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

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


我需要这个的原因是我的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,反之亦然,因为它们应该单独编译。 (实际上它们非常庞大,有很多模块,需要编译它们都会大大减慢开发速度。)

parallel-processing makefile gnu-make ghc
3个回答
6
投票

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

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))

乌尔克!这里发生了什么?

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

啊!

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

YMMV等等。

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


3
投票

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

来自GNU Make Manual

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

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

你正在尝试什么,我正在尝试(使用make在SQLite3数据库中插入数据)遭受完全相同的问题。


1
投票

我需要将编译与其他步骤(清理,构建目录和链接)分开,因为我想使用更多核心进程和-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标志AND -Oline调用compile.mk,以便并行处理不会弄乱输出。

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

我希望它可以提供帮助。

© www.soinside.com 2019 - 2024. All rights reserved.