web-dev-qa-db-ja.com

並列メイクファイルには依存関係の順序が必要です

私は次の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」を呼び出そうとすると、ファイルのビルド中にクリーンターゲットが実行されることが多く、コンパイルが失敗します。私の質問は、リリースビルドを開始する前にクリーンターゲットが完了したことを確認する方法です。

24
kyku

私の好みは

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

これにより、2つのターゲットは、内部の並列処理(存在する場合)を妨げることなく、連続して作成されます。

32
Neil

実行を非並列(releaseの場合)フェーズと並列(残りのターゲットの場合)フェーズに分割できます。

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

release: clean
    $(MAKE) test1

.NOTPARALLEL targetは、コマンドラインでrelease 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では機能しません。たとえば、リリースされたMinGW /ネイティブビルドのGNU makeバージョン4.0より前では、ジョブサーバーはサポートされていません(Cygwin/MSYSビルドのGNU make do。))以下のコードは .FEATURES variable ジョブサーバーがサポートされているかどうかを検出するためにmake3.81で導入されました。必要なときにこの回避策を使用しない場合の症状は、「並列」ビルドがシリアル化されることです。

# 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
11

リリースの場合、anyコンパイルする前にcleanが完了することを確認する必要があります。したがって、(偽のターゲットではなく)コンパイルルールへの依存関係として(ただ)それを追加します。ターゲット固有の変数など、これを行ういくつかの方法、または:

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

この機能がサポートされているバージョンは正確にはわかりませんが、order-only機能を使用できます。

my_target: dep1 dep2 | must_run_1st must_run_2nd

|文字の左側にあるすべての依存関係は通常どおり処理されます。 |の右側の依存関係は「順序のみ」で実行されます

この機能については、次の場所で説明しています。

https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html

あなたの場合、次のルール定義で十分です。

release: | clean test1
test1: | clean
1
theorifice