我怎么能告诉gnu不要并行构建一些配方。假设我有以下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 $@ $<
但是,my-pre-processor
命令会创建具有固定名称的临时文件(我无法更改)。如果我只使用不带-j
参数的make,这工作正常。但是,如果使用-j
选项,则构建有时会失败,因为my-pre-processor
的两个并发调用会覆盖其临时文件。
我想知道是否有办法告诉make它不能构建试图并行化%.cpp : %.xxx
食谱的执行。
答案 0 :(得分:14)
GNU Make包含特殊的内置伪目标.NOTPARALLEL
示例:
.PHONY: all clean
.NOTPARALLEL:
anotherTarget: dependency1
您还可以在命令行中使用-j <n>
,--jobs[=<n>]
标志,其中n
是允许并行运行的收件人数。
使用方法:
make -j <n>
或make --jobs=<n>
实施例:
make -j 1
或make --jobs=1
注意:省略<n>
将允许执行任意数量的食谱,仅受系统可用资源的限制
最后,您可以将解决方案2中的命令行标志分配给Makefile中的MAKEFLAGS
变量
实施例:
MAKEFLAGS := -j 1
要么
MAKEFLAGS := --jobs=1
答案 1 :(得分:8)
相关的解决方案是指定您想要构建的确切顺序(而不是说“不要并行构建”)。
要指定确切的顺序,您可以使用 order-only prerequisites 。这是GNU make的手册页:
但是,有时你会想要强加一个 在不强制执行的情况下调用规则的特定顺序 如果执行其中一个规则,则更新目标。在这种情况下, 您想要定义仅订单的先决条件。仅限订单的先决条件 可以通过在先决条件中放置管道符号(|)来指定 list:管道符号左侧的任何先决条件都是正常的;任何 右边的先决条件是仅限订单:
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)
由于竞争条件,我不得不在make dist
规则上使用仅限订单的先决条件。 dist
配方取决于distclean
和diff
规则,diff
规则执行了svn diff -r XXX
以显示确切的更改。有时,make会删除它刚刚创建的diff,因为clean规则将在diff规则之后运行。
答案 2 :(得分:6)
如果在当前工作目录中创建临时文件,您可以使用子目录(不是很漂亮,但很少见):
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
mkdir $@.d
s=`realpath $<` && cd $@.d && my-pre-processor -o ../$@ "$${s}" || { $(RM) -r $@.d && false; }
$(RM) -r $@.d
此外,由于您使用的是语法但不是GNU make专用的功能,请注意以下等效的Makefile应该更具可移植性
sources = a.xxx b.xxx c.xxx
target = program
all : $(target)
$(target) : $(sources:.xxx=.o)
$(CXX) -o $@ $<
.cpp.o:
$(CXX) -c -o $@ $<
.xxx.cpp:
mkdir $@.d
s=`realpath $<` && cd $@.d && my-pre-processor -o ../$@ "$${s}" || { $(RM) -r $@.d && false; }
$(RM) -r $@.d
.PHONY: all
.SUFFIXES: .xxx .cpp .o
另请注意,GNU make的内在.cpp.o:
规则允许用户在命令行上指定标志,(类似于)
.cpp.o:
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
您的用户在需要通过-L...
答案 3 :(得分:6)
这是一个可怕的kludge,但它将完成这项工作:
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,我不了解其他版本。)
答案 4 :(得分:3)
您最好研究ylwrap
附带的automake
工具的操作:它解决了旧版lex
和yacc
的大部分相同问题:
http://git.savannah.gnu.org/cgit/automake.git/tree/lib/ylwrap
答案 5 :(得分:0)
我遇到了同样的问题(我的sw签名服务未接受多个并发请求)。我的解决方案是在Recepie中添加互斥锁:
%.cpp : %.xxx
@ until mkdir /tmp/make.lock 2>/dev/null ; do sleep 2 ; done
my-pre-processor -o $@ $<
@ rmdir /tmp/make.lock
这允许makefile的所有其他部分并行运行,但是此时只有一个“ my-pre-processor”正在运行。