I have the following piece of makefile:
CXXFLAGS = -std=c++0x -Wall
SRCS = test1.cpp test2.cpp
OBJDIR = object
OBJS = $(SRCS:%.cpp=$(OBJDIR)/%.o)
all:
You may split the execution into non-parallel (for release
) and parallel (for the rest targets) phases.
ifneq ($(filter release,$(MAKECMDGOALS)),)
.NOTPARALLEL:
endif
release: clean
$(MAKE) test1
.NOTPARALLEL target will suppress parallel execution if release
target is mentioned in the command line. The release
target itself will rerun Make after cleaning and build test1
in parallel.
More clever solution would also reinvoke Make for each single target in case if there are more than one targets given on the command-line, so that a presence of release
target would not force the rest to execute non-parallel too.
ifneq ($(words $(MAKECMDGOALS)),1)
.NOTPARALLEL:
$(sort all $(MAKECMDGOALS)):
@$(MAKE) -f $(firstword $(MAKEFILE_LIST)) $@
else
# ...
endif
The clever solution above doesn't work on versions of GNU make that don't support job servers. For example, released MinGW/native builds of GNU make prior to version 4.0 do not support job servers. (Cygwin/MSYS builds of GNU make do.) The code below uses the .FEATURES variable introduced in make 3.81 to detect if job servers are supported. The symptom of not using this workaround when it's needed is that your "parallel" build will be serialized.
# 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