并行makefile需要依赖顺序

时间:2011-12-13 21:02:57

标签: makefile gnu-make

我有以下makefile:

CXXFLAGS = -std=c++0x -Wall
SRCS     = test1.cpp test2.cpp
OBJDIR   = object
OBJS     = $(SRCS:%.cpp=$(OBJDIR)/%.o)

all: test1 
release: clean test1

test1: $(OBJS)
    $(CXX) -o $@ $(OBJS)

$(OBJDIR)/%.o: %.cpp
    $(CXX) $(CXXFLAGS) -MD -c -o $@ $<

-include $(SRCS:.cpp=.d)

clean:
    rm -rf $(OBJDIR)/*

.PHONY: all clean release 

现在,如果我尝试调用“make -j4 release”,那么干净的目标通常会在构建文件的过程中执行,从而导致编译失败。我的问题是如何在开始发布版本之前确保干净的目标已经完成。

5 个答案:

答案 0 :(得分:28)

我的偏好是

release:
    $(MAKE) clean
    $(MAKE) test1

这会迫使两个目标连续发生而不会打扰它们的内部平行度(如果有的话)。

答案 1 :(得分:10)

您可以将执行分为非并行(对于release)和并行(对于其余目标)阶段。

ifneq ($(filter release,$(MAKECMDGOALS)),)
.NOTPARALLEL:
endif

release: clean
    $(MAKE) test1
如果在命令行中提到release目标,

.NOTPARALLEL target将禁止并行执行。 release目标本身将在清理后重新运行Make并行构建test1

UPD。

如果在命令行上有多个目标,那么更聪明的解决方案也会重新调用每个单个目标的Make,以便release目标的存在不会强制其余目标执行非也是平行的。

ifneq ($(words $(MAKECMDGOALS)),1)
.NOTPARALLEL:
$(sort all $(MAKECMDGOALS)):
    @$(MAKE) -f $(firstword $(MAKEFILE_LIST)) $@
else
# ...
endif

James Johnston

更新

上面的巧妙解决方案不适用于不支持作业服务器的GNU make版本。例如,在版本4.0之前发布的GNU make的MinGW /本机版本不支持作业服务器。 (GNU make的Cygwin / MSYS版本。)下面的代码使用make 3.81中引入的.FEATURES variable来检测是否支持作业服务器。在需要时不使用此解决方法的症状是您的“并行”构建将被序列化。

# Check if job server supported:
ifeq ($(filter jobserver, $(.FEATURES)),)
# Job server not supported: sub-makes will only start one job unless
# you specify a higher number here.  Here we use a MS Windows environment
# variable specifying number of processors.
JOBSARG := -j $(NUMBER_OF_PROCESSORS)
else
# Job server is supported; let GNU Make work as normal.
JOBSARG :=
endif

# .FEATURES only works in GNU Make 3.81+.
# If GNU make is older, assume job server support.
ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))),3.81)
# If you are using GNU Make < 3.81 that does not support job servers, you
# might want to specify -jN parameter here instead.
JOBSARG :=
endif

ifneq ($(words $(MAKECMDGOALS)),1)
.NOTPARALLEL:
# The "all" target is required in the list,
# in case user invokes make with no targets.
$(sort all $(MAKECMDGOALS)):
    @$(MAKE) $(JOBSARG) -f $(firstword $(MAKEFILE_LIST)) $@
else

# Put remainder of your makefile here.

endif

答案 2 :(得分:1)

在发布案例中,您需要确保在任何编译之前完成clean。因此,您(只)将其作为依赖项添加到编译规则(而不是虚假目标)。有几种方法可以做到这一点,比如特定于目标的变量,或者:

$(OBJDIR)/%.o: %.cpp $(if $(filter release,${MAKECMDGOALS}),clean)
    ...

答案 3 :(得分:0)

我不确定支持此功能的版本,但您可以使用order-only功能:

my_target: dep1 dep2 | must_run_1st must_run_2nd

正常处理|字符左侧的所有依赖项。 |右侧的依赖关系运行'仅限订单'

此功能描述于:

this other POI FAQ

在您的情况下,以下规则定义就足够了:

release: | clean test1
test1: | clean

答案 4 :(得分:-1)

对于没有make的递归调用的解决方案,你可以试试这个。

ifneq ($(filter release,$(MAKECMDGOALS)),)
test1: clean
endif