web-dev-qa-db-ja.com

GNU Makeを使用してビルドを自動検出および並列化するmakefileを作成するにはどうすればよいですか?

これが1つのMakefileだけで可能かどうかはわかりませんが、ファイル内にターゲットを構築しようとすると、現在のシステム上のプロセッサの数が自動的に検出され、ターゲットが並行して構築されるような方法でMakefileを作成したいと考えていました。プロセッサの数。

以下の「擬似コード」の例のようなものですが、はるかにクリーンですか?

all:
    @make -j$(NUM_PROCESSORS) all

または:

all: .inparallel
    ... build all here ...

.inparallel:
    @make -j$(NUM_PROCESSORS) $(ORIGINAL_TARGET)

どちらの場合も、入力する必要があるのは次のとおりです。

% make all

うまくいけば、それは理にかなっています。

更新:上記のMakefileの例をまだ期待しています。プロセスの数を見つけることにはあまり興味がありませんが、-jコマンドラインオプションを使用せずに並行してビルドするmakefileを作成する方法には興味があります。

28
dlamotte

LDD3の第2章を少し調べて、dmckeeの回答を読んだ後、2つのmakefileを使用するというそれほど優れた回答を思いつきませんでした(1つだけをお勧めします)。

_$ cat Makefile
MAKEFLAGS += -rR --no-print-directory

NPROCS := 1
OS := $(Shell uname)
export NPROCS

ifeq ($J,)

ifeq ($(OS),Linux)
  NPROCS := $(Shell grep -c ^processor /proc/cpuinfo)
else ifeq ($(OS),Darwin)
  NPROCS := $(Shell system_profiler | awk '/Number of CPUs/ {print $$4}{next;}')
endif # $(OS)

else
  NPROCS := $J
endif # $J

all:
    @echo "running $(NPROCS) jobs..."
    @$(MAKE) -j$(NPROCS) -f Makefile.goals $@

%:
    @echo "building in $(NPROCS) jobs..."
    @$(MAKE) -j$(NPROCS) -f Makefile.goals $@
$ cat Makefile.goals
MAKEFLAGS += -rR --no-print-directory
NPROCS ?= 1

all: subgoal
    @echo "$(MAKELEVEL) nprocs = $(NPROCS)"

subgoal:
    @echo "$(MAKELEVEL) subgoal"
_

このソリューションについてどう思いますか?

私が見る利点は、人々がまだmakeと入力してビルドすることです。したがって、makeと入力する代わりに、人々が知っておく必要のあるNPROCSおよびmake -j$(NPROCS)の作業を実行する「ドライバー」スクリプトはありません。

欠点は、シリアルビルドを実行するために明示的に_make -f Makefile.goals_を使用する必要があることです。そして、私はこの問題を解決する方法がわかりません...

更新:上記のコードセグメントに$ Jを追加しました。うまくいくようです。 1つではなく2つのmakefileですが、それでも非常にシームレスで便利です。

6
dlamotte

検出部分はOSに依存します。 LinuxおよびMacOSXで動作するフラグメントは次のとおりです。

NPROCS:=1
OS:=$(Shell uname -s)

ifeq($(OS),Linux)
  NPROCS:=$(Shell grep -c ^processor /proc/cpuinfo)
endif
ifeq($(OS),Darwin) # Assume Mac OS X
  NPROCS:=$(Shell system_profiler | awk '/Number Of CPUs/{print $4}{next;}')
endif

それを機能させるには、おそらくmakeを再度呼び出す必要があります。次に、問題は無限再帰の防止です。 2つのmakefile(最初は-j値をリセットするだけ)を使用することでそれを管理できますが、おそらくそれを微調整することは可能です。

23
dmckee

これをMakefileの先頭に追加しました。これにより、makeは任意の数のジョブを作成できますが、負荷平均をCPUコアの数より低く維持しようとします。

MAKEFLAGS+="-j -l $(Shell grep -c ^processor /proc/cpuinfo) "

これはLinux固有であることに注意してください。

7
TedKotz

これが私が行ったものです:

ifeq ($(OS),Linux)
        NUMPROC := $(Shell grep -c ^processor /proc/cpuinfo)
else ifeq ($(OS),Darwin)
        NUMPROC := $(Shell sysctl hw.ncpu | awk '{print $$2}')
endif

# Only take half as many processors as available
NUMPROC := $(Shell echo "$(NUMPROC)/2"|bc)

ifeq ($(NUMPROC),0)
        NUMPROC = 1
endif 
6
amos

$(NPROCS)の検出についてはスキップしますが、これを1つのMakefileで実行する方法は次のとおりです(これはおそらくGNU具体的にしますが、実行しているバリアントのように見えます):

ifeq ($(NPROCS),)
# Code to set NPROCS...
%:
    $(MAKE) -j$(NPROCS) NPROCS=$(NPROCS)
else
# All of your targets...
endif

GNU Make ManualDefining Last-Resort Default Rules および Overriding Part of Another Makefile を参照してください。

5
Jack Kelly

自動化する場合は、通常のmakeコマンドをオーバーライドして、ホームディレクトリの.bashrc内のそれ自体のエイリアスにすることができます。

例:

alias make="make -j"

または、次のようなことを行うことができます。

alias jmake="make -j"

それをオーバーライドしたくないが、makeを並行して実行するための迅速で簡単な(そして記憶に残る)方法が必要な場合。

2
bean

質問を正しく読んだ場合、目標はビルドプロセスを可能な限り並列化することです。 makeのマニュアルページには、次のように記載されています。

-jオプションを引数なしで指定した場合、makeは同時に実行できるジョブの数を制限しません。

これは基本的にあなたが望む解決策ではありませんか? Makefileに十分な並列ターゲットがある場合は、すべてのCPUを使用し、ターゲットが並列でない場合は、その-jオプションは何の助けにもなりません。

1
grundprinzip