web-dev-qa-db-ja.com

GNU makeの-jオプション

-jについて学んで以来、-j8を気楽に使用してきました。先日、私はアトラスのインストールをコンパイルしていましたが、メイクは失敗しました。最終的には、順不同で作成されているものまで追跡しました。シングルスレッドメイクに戻ってからは正常に機能しました。これは私を緊張させます。 make -jで予期しないことをしないように、独自のmakeファイルを作成するとき、どのような条件に注意する必要がありますか?

53

Make -jは、Makefileで指定した依存関係を尊重すると思います。つまり、objAがobjBとobjCに依存することを指定した場合、objBとobjCが完了するまで、makeはobjAの処理を開始しません。

ほとんどの場合、Makefileは必要な操作の順序を厳密に指定していないため、シングルスレッドの場合に偶然動作するのは幸運です。

40
Jeremy Friesner

要するに-依存関係が正しく完全であることを確認してください。

シングルスレッドメイクを使用している場合、ターゲット間の暗黙的な依存関係を盲目的に無視することができます。並列makeを使用する場合、暗黙的な依存関係に依存することはできません。それらはすべて明示的に作成する必要があります。これはおそらく最も一般的なトラップです。特に、.phonyターゲットを依存関係として使用する場合。

これ リンクは、パラレルmakeのいくつかの問題の良い入門書です。

24

並列ビルドを使い始めたときに遭遇した問題の例を次に示します。ターゲットを最初から再構築するために使用する「フレッシュ」というターゲットがあります(「フレッシュ」ビルド)。以前は、依存関係として「クリーン」と「ビルド」を指定するだけで、「新鮮な」ターゲットをコーディングしていました。

build: ## builds the default target
clean: ## removes generated files
fresh: clean build ## works for -j1 but fails for -j2

並列ビルドを使い始めるまではうまくいきましたが、並列ビルドでは「クリーン」と「ビルド」の両方を同時に実行しようとします。そのため、操作の正しい順序を保証するために、「新鮮」の定義を次のように変更しました。

fresh:
    $(MAKE) clean
    $(MAKE) build

これは基本的に、依存関係を正しく指定するだけの問題です。トリックは、シングルスレッドビルドよりも並列ビルドの方が厳密であることです。私の例では、特定のターゲットの依存関係のリストが必ずしも実行順序を示すとは限らないことを示しています。

9
nobar

再帰的なmakeを使用している場合、事態は非常に簡単に壊れる可能性があります。再帰的なmakeを実行していない場合、依存関係が正しく完全である限り、問題に遭遇することはありません(makeのバグを保存する)。再帰的なmakeの問題のより詳細な説明については、 再帰的なMakeが有害と見なされる を参照してください。

7
Adam Rosenfield

すべてのmakeファイルの-jオプションをテストする自動テストを行うことをお勧めします。最高の開発者でさえ、makeの-jオプションに問題があります。最も一般的な問題は最も単純です。

myrule: subrule1 subrule2
     echo done

subrule1:
     echo hello

subrule2:
     echo world

通常のmakeでは、hello-> world-> doneと表示されます。 make -j 4を使用すると、world-> hello-> doneと表示される場合があります

私がこれを最もよく見ているのは、出力ディレクトリの作成です。例えば:

build: $(DIRS) $(OBJECTS)
     echo done

$(DIRS):
     -@mkdir -p $@

$(OBJECTS):
     $(CC) ...
2
user2714439

効果を明確に示さないため、subsetbrewの答えに追加すると思いました。ただし、いくつかのスリープコマンドを追加するとできます。まあそれはLinux上で動作します。

次に、makeを実行すると、次の点との違いが示されます。

  • make
  • make -j4

all: toprule1

toprule1: botrule2 subrule1 subrule2
    @echo toprule 1 start
    @sleep 0.01
    @echo toprule 1 done

subrule1: botrule1
    @echo subrule 1 start
    @sleep 0.08
    @echo subrule 1 done

subrule2: botrule1
    @echo subrule 2 start
    @sleep 0.05
    @echo subrule 2 done

botrule1:
    @echo botrule 1 start
    @sleep 0.20
    @echo "botrule 1 done (good prerequiste in sub)"

botrule2:
    @echo "botrule 2 start"
    @sleep 0.30
    @echo "botrule 2 done (bad prerequiste in top)"
1
M Hutson