Makefile 如何强制gnu make不并行构建配方?
我如何告诉gnu make不要并行地构建一些配方。假设我有以下makefile:Makefile 如何强制gnu make不并行构建配方?,makefile,parallel-processing,gnu-make,Makefile,Parallel Processing,Gnu Make,我如何告诉gnu make不要并行地构建一些配方。假设我有以下makefile: sources = a.xxx b.xxx c.xxx target = program all : $(target) $(target) : $(patsubst %.xxx,%.o,$(sources)) $(CXX) -o $@ $< %.o : %.cpp $(CXX) -c -o $@ $< %.cpp : %.xxx my-pre-processor -o
sources = a.xxx b.xxx c.xxx
target = program
all : $(target)
$(target) : $(patsubst %.xxx,%.o,$(sources))
$(CXX) -o $@ $<
%.o : %.cpp
$(CXX) -c -o $@ $<
%.cpp : %.xxx
my-pre-processor -o $@ $<
sources=a.xxx b.xxx c.xxx
目标=程序
全部:$(目标)
$(目标):$(patsubst%.xxx,%.o,$(来源))
$(CXX)-o$@$<
%.o:%.cpp
$(CXX)-c-o$@$<
%.cpp:%.xxx
我的预处理器-o$@$<
但是,my pre-processor
命令使用固定名称创建临时文件(我无法更改此名称)。如果我只使用make而不使用-j
参数,那么这工作正常。但是,如果使用了-j
选项,构建有时会失败,因为对my pre-processor
的两次并发调用会覆盖它们的临时文件
我想知道是否有一种方法可以告诉make,它不能构建并尝试并行执行
%.cpp:%.xxx
配方。如果临时文件是在当前工作目录中创建的,您可以使用子目录(不漂亮,但很少):
当您的用户需要通过
-L>提供自定义包含目录时,他们可能会喜欢它。
这是一个可怕的难题,但它可以完成以下任务:
b.cpp: a.cpp
c.cpp: b.cpp
或者,如果确实有很多,你可以喝几杯烈性饮料,然后这样做:
c-sources = $(sources:.xxx=.cpp)
ALLBUTFIRST = $(filter-out $(firstword $(c-sources)), $(c-sources))
ALLBUTLAST = $(filter-out $(lastword $(c-sources)), $(c-sources))
PAIRS = $(join $(ALLBUTLAST),$(addprefix :,$(ALLBUTFIRST)))
$(foreach pair,$(PAIRS),$(eval $(pair)))
(这在GNUMake中有效,我不知道其他版本。)您最好研究一下
automake
附带的ylwrap
工具的操作:它解决了lex
和yacc
旧版本的大多数相同问题:
解决方案1
GNU Make包含特殊的内置伪目标。NOTPARALLEL
例如:
.PHONY: all clean
.NOTPARALLEL:
anotherTarget: dependency1
解决方案2 您还可以在命令行上使用
-j
,--jobs[=]
标志,其中n
是允许并行运行的往复次数
用法:
make-j
或make-jobs=
例如:
make-j1
或make--jobs=1
注意:忽略
将允许执行任意数量的配方,仅受系统可用资源的限制
解决方案3 最后,您可以从Makefile中将解决方案2中的命令行标志指定给
MAKEFLAGS
变量
例如:
MAKEFLAGS:=-j1
或
MAKEFLAGS:=--jobs=1
一个相关的解决方案是指定构建事物的确切顺序(而不是说“不要并行构建”)
要指定确切的顺序,可以使用。以下是GNU make的手册页:
然而,有时候,您会遇到想要强制执行
在不强制
如果执行其中一个规则,则要更新的目标。那么,,
您希望定义仅限订单的先决条件。仅订购先决条件
可以通过在必备项中放置管道符号(|)来指定
列表:管道符号左侧的任何先决条件都是正常的;任何
右侧的先决条件仅适用于订单:
targets : normal-prerequisites | order-only-prerequisites
下面是他们提供的示例:
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)
OBJDIR:=OBJDIR
OBJS:=$(addprefix$(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o:%.c
$(COMPILE.c)$(输出选项)$<
全部:$(OBJS)
$(OBJS):|$(OBJDIR)
$(OBJDIR):
mkdir$(OBJDIR)
由于比赛条件,我不得不在
make dist
规则中使用仅限订单的先决条件。dist
配方取决于distclean
和diff
规则,而diff
规则执行一个svn diff-r XXX
来显示确切的变化。有时,make会删除它刚刚创建的差异,因为清除规则将在差异规则之后运行。我遇到了相同的问题(我的软件签名服务不接受多个并发请求)。我的解决方案是在recepie中添加互斥:
%.cpp : %.xxx
@ until mkdir /tmp/make.lock 2>/dev/null ; do sleep 2 ; done
my-pre-processor -o $@ $<
@ rmdir /tmp/make.lock
%.cpp:%.xxx
@直到mkdir/tmp/make.lock 2>/dev/null;做睡眠2;完成
我的预处理器-o$@$<
@rmdir/tmp/make.lock
这允许makefile的所有其他部分并行运行,但此时只有一个“我的预处理器”在运行。考虑为预处理器创建一个包装器脚本,在临时目录中完成所有工作。这将使
Makefile
更整洁。五年前的问题和正确答案在我需要它的同一天出现。谢谢不幸的是,所有这些解决方案都强制在整个Makefile上进行完全顺序的构建。然而,问题是关于仅停用单个配方的并行性。对于这个特定问题(运行程序的多个副本会覆盖临时文件),另一个解决方案可能是创建一个带有随机名称的临时目录(例如,使用mktemp-d
)并从其中运行该工具。然后,您可以并行运行该工具的多个副本,从而加快构建速度,并假设它将其文件写入当前目录,它们将不会被覆盖。
targets : normal-prerequisites | order-only-prerequisites
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)
%.cpp : %.xxx
@ until mkdir /tmp/make.lock 2>/dev/null ; do sleep 2 ; done
my-pre-processor -o $@ $<
@ rmdir /tmp/make.lock