Sun WorkShop の概要 ホーム目次前ページへ次ページへ索引


付録 C

dmake ユーティリティの使用

この付録では、分散メーク (dmake) ユーティリティで構築プロセスを複数のホストに分散し、複数のワークステーションやマルチプロセッサ上で並列的にプログラムを構築する方法について説明します。dmake(1) のマニュアルページも参照してください。

基本概念

分散メーク (dmake) は、make ユーティリティのスーパーセットです。dmake を使用することにより、多数のプログラムで構成される大規模なプロジェクトの構築プロセスを複数のワークステーション (マルチプロセッサシステムの場合は複数の CPU) に分散して、並列的に作業を進めることができます。

dmake ホスト上で dmake を実行すると、構築サーバーにジョブが分散されます。ジョブは dmake ホストにも割り当てることができ、その場合は、dmake ホストも構築サーバーと見なされます。dmake ユーティリティは、構築が並列可能であると判断した、メークファイル内のターゲットに基づいてジョブを分散します。dmake ホストから、使用する構築サーバーや各構築サーバーに割り当てる dmake ジョブ数を制御できます。また、構築サーバーで実行可能な dmake ジョブ数を制限することもできます。

dmake ジョブの分散は、次の 2 通りの方法で制御されます。

  1. 構築サーバーとして使用するマシンと各構築サーバーに分散するジョブ数: dmake ユーザーが dmake ホストからを指定します。

  2. サーバーに割り当て可能な総 dmake ジョブ数: 構築サーバーの所有者 (構築サーバー構成ファイル /etc/opt/SPROdmake/dmake.conf を編集する権限を持つユーザー) が制御できます。


    注 - 「構築」ウィンドウから dmake を使用する際の構築サーバーとジョブの指定方法については、オンラインヘルプを参照してください。コマンド行から dmake にアクセスする場合は、dmake(1) のマニュアルページを参照してください。

dmake を理解するには、次のことを理解する必要があります。

dmake ホスト

dmake ホストとは、dmake コマンドの発行元のマシンです。dmake ユーティリティは、実行時構成ファイルの内容に基づいて、ジョブをどこに分散するかを決定します。一般に、このファイルは、dmake ホストのホームディレクトリ内に、 .dmakerc という名前で置かれている必要があります。dmake ユーティリティは、以下の順序で実行時構成ファイルを探します。

  1. コマンド行で -c オプションを使用して指定されたパス名

  2. DMAKE_RCFILE という名のメークファイルマクロを使用して指定されたパス名

  3. DMAKE_RCFILE 環境変数を使用して指定されたパス名

  4. $(HOME)/.dmakerc

実行時構成ファイルが見つからない場合、dmake ユーティリティは dmake ホストに 2 つのジョブを割り当てます。

実行時構成ファイルによって、各構築サーバーのリストと各構築サーバーに分散するジョブの数を指定できます。次に、.dmakerc ファイルの例を示します。

コード例 C-1 .dmakerc ファイル

# 自分のマシン。この行により dmake は自分のマシンへジョブを分散する。
falcon			{ jobs = 1 }
hawk
eagle			{ jobs = 3 }
# 上司のマシン。たいてい、会議中。
heron			{ jobs = 4 }
avocet


falconhawkeagleheronavocet は構築サーバー名です。これらの構築サーバーのそれぞれに割り当てるジョブ数を指定できます。デフォルトのジョブ数は 2 つです。# から始まる行はすべてコメントと解釈されます。上記の例の構築サーバーのリストには、dmake ホストでもある falcon が指定されています。dmake ホストを構築サーバーとして指定することもできます。実行時構成ファイルに指定されていないホストに、dmake ジョブが割り当てられることはありません。

実行時構成ファイルで、複数の構築サーバーグループを定義できます。これにより、状況に応じて構築サーバーグループを柔軟に切り換えることができます。たとえば、異なるオペレーティングシステムでの構築処理ごとに、複数の異なる構築サーバーグループを定義できます。また、特殊なソフトウェアがインストールされた複数の異なる構築サーバーグループを定義することもできます。

次に、構築サーバーのグループを定義した実行時構成ファイルの例を示します。

コード例 C-2 構築サーバーグループを定義した .dmakerc ファイル

earth   { jobs = 2 }
mars    { jobs = 3 }
 
group lab1 {
       host falcon  { jobs = 3 }
       host hawk
       host eagle   { jobs = 3 }
}
 
group lab2 {
       host heron
       host avocet  { jobs = 3 }
       host stilt   { jobs = 2 }
}
 
group labs {
       group lab1
       group lab2
}
 
group sunos5.x {
       group labs
       host jupiter
       host venus  { jobs = 2 }
       host pluto  { jobs = 3 }
}


構築サーバーのグループは group キーワードを使用して指定し、そのメンバーは中括弧 ({}) で区切ります。グループのメンバーとなる構築サーバーは、オプションの host キーワードを使用して指定します。グループを他のグループのメンバーにすることができます。個々の構築サーバーを、構築サーバーのグループを含んでいる実行時構成ファイルに指定することもできます。この場合、構築サーバーは無名のグループのメンバーとみなされます。

dmake ユーティリティは、次の順序で各ジョブを分散させます。

  1. コマンド行で -g オプションを使用して指定されたグループ

  2. DMAKE_GROUP という名のメークファイルマクロで指定されたグループ

  3. DMAKE_GROUP 環境変数を使用して指定されたグループ

  4. 実行時構成ファイルで指定された最初のグループ

dmake ユーティリティを使用すると、構築サーバーごとに異なる実行パスを指定できます。デフォルトでは、dmake は、論理サーバー内の dmake ホストと同じ論理パス上にある dmake サポートバイナリを検索します。構築サーバーの代替パスは、たとえば次のように、ホスト属性として .dmakerc ファイルに指定できます。

コード例 C-3 構築サーバーの代替パスを指定した .dmakerc ファイル

group lab1 {
      host falcon { jobs = 10 , path = "/set/dist/sparc-S2/bin" }
      host hawk { path = "/opt/SUNWspro/bin"                    }
}


.dmakerc ファイル内のグループ名とホスト名は、二重引用符で囲むことができます。二重引用符で囲むことで、グループ名に使用できる文字の種類が増え、英字だけでなく、数字も使用できるようになります。たとえば、次に示すように、グループ名が数字で始まる場合は、二重引用符で囲んでください。

コード例 C-4 特殊文字を使用した .dmakerc

group "123_lab" {
      host "456_hawk" { path = "/opt/SUNWspro/bin"                 }
}


構築サーバー

分散構築に参加する各構築サーバーには、/etc/opt/SPROdmake/dmake.conf というファイルが存在している必要があります。このファイルは、構築サーバー構成ファイルで、特定の構築サーバーに全 dmake ユーザーが分散できる dmake ジョブの最大数を指定します。また、すべての dmake ジョブを実行する際の優先順位 nice を指定できます。


注 - 構築サーバーに /etc/opt/SPROdmake/dmake.conf ファイルがない場合は、そのサーバー上で dmake ジョブを実行することはできません。

コード例 C-5/etc/opt/SPROdmake/dmake.conf ファイルの例を示します。この例では、( dmake ユーザーが全体として) 1 つの構築サーバー上で実行できる dmake ジョブの最大数を 8 個に設定しています。

コード例 C-5 dmake.conf ファイル

max_jobs: 8
nice_prio: 5


構築サーバーとして使用するマシンは、次の条件を満たしている必要があります。

dmake ユーティリティとメークファイル

分散メークを実行するには、標準的な make ユーティリティの代わりに dmake という実行可能ファイルを使用します。したがって、dmake を使用する前に、Solaris の make ユーティリティについて理解しておく必要があります。make ユーティリティの詳細については、Solaris のマニュアル『プログラミングユーティリティ』および make(1) のマニュアルページを参照してください。これまでに make ユーティリティを使用したことがある場合は、ほとんど変更作業を伴わずに、dmake に移行できます。

この節では、dmake でのさまざまな問題の解決に役立つ方法と例を紹介します。必ずしもこれらの方法が最善の解決策であるとは限りませんが、できるだけわかりやすく機能が説明されています。

手順が複雑になるに従って、これを実現するメークファイルも複雑になります。この節では一般的なコード開発の作業を進める上での問題点を取り上げ、dmake による簡単な解決方法について、例を紹介しながら説明します。

プロジェクトの最初の段階からメークファイルテンプレートを利用するようにしてください。メークファイルテンプレートから作成することによって、実際のメークファイルが理解しやすく、統合、保守、再利用が容易になります。

ターゲットの並列構築

大規模なソフトウェア開発プロジェクトは、それぞれ独立した多数のモジュールで構成されるのが一般的です。これらのモジュールを、それぞれ分散させ、並列的に構築できます。こうした並列処理により、大規模な開発プロジェクトを構築するのに必要な時間が大幅に省けます。

dmake は、構築するターゲットが与えられると、そのターゲットに関連する依存関係を調べ、同期の取れていない依存関係も構築します。この依存関係の構築では、依存関係の依存関係の構築を伴うこともあります。ジョブを分散する際、dmake は起動可能なすべてのターゲットを起動します。それらのターゲットが終了すると、dmake はその他のターゲットを起動します。デフォルトでは、入れ子構造になった dmake の呼び出しは同時には実行されません。ただし、この設定は変更可能です (詳細については、「並列処理に対する制限」を参照)。

dmake では複数のターゲットが並列に構築されるため、各構築プロセスの出力は同時に生成されます。各コマンドからの出力が混ざらないよう、dmake では各構築の出力を個別に収集します。また dmake は、コマンドを実行する前に、そのコマンドの内容を表示します。実行したコマンドによって出力、警告、またはエラーが生成されると、dmake ユーティリティは該当するコマンドの出力全体を表示します。後から開始したコマンドが先行するコマンドよりも先に終了することもあるので、出力の順序が予想と異なる場合があります。

メークファイルに対する制限事項

複数のターゲットを同時に構築する場合は、メークファイルに多少の制限が伴います。たとえば、暗黙の依存関係の順序に依存しているメークファイルは、並列構築を行なったとき正しく機能しないことがあります。また同じファイルの修正を行うターゲットがあり、これらファイルが 2 つの異なるターゲットで同時に変更されると、メークファイル中のターゲットで問題が起きることがあります。この節では、こうした問題の例を取り上げます。

依存関係リスト

ターゲットの並列構築をするときは、依存関係リストが正確であることが重要なポイントになります。たとえば、 2 つの実行可能ファイルが同じオブジェクトファイルを共有しているときに、一方のファイルでしか依存関係が指定されていないと、並列構築がエラーになる可能性があります。次のメークファイルの例を考えてみます。

all: prog1 prog2 
prog1: prog1.o aux.o 
    $(LINK.c) prog1.o aux.o -o prog1
prog2: prog2.o 
    $(LINK.c) prog2.o aux.o -o prog2 

逐次構築では、ターゲット aux.oprog1 に依存するファイルとして構築され、prog2 の構築時に利用されます。これに対し、並列構築では、prog2 のリンクが、aux.o の構築前に開始されることがあり、その場合は、不正になります。make.KEEP_STATE 機能で検出できる依存関係も一部ありますが、上記のような関係はその対象にはなりません。

依存関係リストにおける依存関係の順序指定

次に、暗黙の順序にもとづく依存関係がある場合は、問題がさらに複雑になるという例を示します。たとえば、あるシステムのヘッダーをすべて作成してから構築を開始する場合は、すべての要素がこの構築に依存していなければなりません。このため、メークファイルがさらに複雑になり、新しいターゲットをメークファイルに追加した場合などにエラーが起きる可能性が高くなります。この場合は、メークファイルの中で特殊な .WAIT ターゲットを指定して、暗黙の依存関係があることを明示できます。dmake により依存関係リストの中に .WAIT ターゲットが検出されると、これまでの依存関係の処理を一時停止してから、以降の依存関係の処理を実行するようになります。 1 つの依存関係リストに、複数の .WAIT ターゲットを入れることもできます。次に、.WAIT を使用して、まずヘッダーを作成してから、以降の処理を続行する例を示します。

all: hdrs .WAIT libs functions

.WAIT ターゲットに適用する空の規則をメークファイルに追加することによって、make ユーティリティでも、このメークファイルを使用できます。

ファイルの同時修正

ターゲットの構築プロセスでは、同時に同じファイルを修正しないように注意する必要があります。この問題は、さまざまな形で起きる可能性があります。一時ファイルを使用する新しい接尾辞の規則を定義する場合、一時ファイルの名前は、ターゲットごとに異なっていなければなりません。この場合は、$@$* の動的マクロを利用できます。たとえば、ソースファイルをコンパイルする前に .c ファイルに修正を加える場合、.c.o の規則は次のように定義できます。

.c.o:
    awk -f modify.awk $*.c > $*.mod.c
    $(COMPILE.c) $*.mod.c -o $*.o
    $(RM) $*.mod.c

ライブラリの同時更新

並列処理でもう 1 つの問題になる可能性があるのは、ライブラリを作成するときのデフォルトの規則です。すなわち、ライブラリという固定ファイルが変更される場合があるということです。本来適用されるべきでない .c.a 規則によって、dmake がそれぞれのオブジェクトファイルを構築し、このオブジェクトファイルをアーカイブする可能性があります。dmake が 2 つのオブジェクトファイルを同時にアーカイブすると、並列的に更新が行われてアーカイブファイルが壊れることがあります。

.c.a:
    $(COMPILE.c) -o $% $<
    $(AR) $(ARFLAGS) $@ $%
    $(RM) $

この場合は、各オブジェクトファイルを構築し、その構築が完了した後、すべてのオブジェクトファイルをアーカイブするようにします。正しい接尾辞の規則と対応するライブラリの規則は次のとおりです。

.c.a:
    $(COMPILE.c) -o $% $<
 
lib.a: lib.a($(OBJECTS))
    $(AR) $(ARFLAGS) $(OBJECTS)
    $(RM) $(OBJECTS) 

複数のターゲット

ファイルの同時更新の問題は、同じ規則を複数のターゲットに対して定義した場合にも起きます。たとえば、lex(1) で使用できるプログラムとヘッダーの両方を構築する yacc(1) というプログラムがあります。 1 つの規則にもとづいて複数のターゲットファイルを構築する場合は、+ 記号を使用して各ファイルを 1 つのグループとして指定する必要があります。特に、並列構築の場合に、このことが重要になります。

y.tab.c y.tab.h: parser.y 
    $(YACC.y) parser.y

この規則は、次のように 2 つの規則が指定された場合と同等になります。

y.tab.c: parser.y
    $(YACC.y) parser.y
y.tab.h: parser.y
    $(YACC.y) parser.y

逐次処理の make は、最初の規則に基づいて y.tab.c を作成してから、y.tab.h が最新であり、構築の必要がないと判断します。これに対し、並列構築では、 yaccy.tab.c の構築を完了する前に y.tab.h を調べるため、y.tab.h の構築が必要であると判断し、最初の yacc と並行して別の yacc を起動します。両方の yacc が同じファイル (y.tab.cy.tab.h) に書き込みを行うため、これらのファイルが壊れ、不正になる可能性があります。正しい規則では、次の例に示すように、+ 構文を使用して、両方のターゲットを同じ規則に従って同時に作成するように指示します。

y.tab.c + y.tab.h: parser.y
    $(YACC.y) parser.y

並列処理に対する制限

メークファイルでファイルの衝突が避けられない場合があります。その 1 つの例が、C プログラムから文字列を抽出して共有文字列を生成する xstr(1) コマンドです。xstr コマンドでは、変更した C プログラムを x.c という固定したファイルに書き出し、抽出した文字列は xs.c という固定ファイルに書き出します。xstr は C ファイル単位で実行する必要があるため、次の新しい .c.o 規則がよく定義されます。

 .c.o:
    $(CC) $(CPPFLAGS) -E $*.c | xstr -c -
    $(CC) $(CFLAGS) $(TARGET_ARCH) -c x.c
    mv x.o $*.o

この場合、各ターゲットを作成するごとに、x.cxs.c という同じファイルに書き出しを行うので、dmake ユーティリティは上の規則に基づいてターゲットを同時に構築することはできません。また、使用するファイルを変更することもできません。この場合は、.NO_PARALLEL: という特殊なターゲットを使用して、dmake に各ターゲットを同時に構築しないように指示できます。たとえば、.c.o 規則を使用して構築するオブジェクトを OBJECTS マクロで定義している場合は、次のようにして、各ターゲットを逐次構築するよう dmake に指示します。

.NO_PARALLEL: $(OBJECTS)

大部分のオブジェクトを逐次構築する必要がある場合は、依存関係のない .NO_PARALLEL: ターゲットを含めることによって、全オブジェクトをデフォルトで強制的に逐次処理するようにした方が、安全で簡単です。並列構築できるターゲットは、次のように .PARALLEL: ターゲットに依存するファイルとして記述できます。

.NO_PARALLEL:
.PARALLEL: $(LIB_OBJECT)

dmake が、さらに別の dmake コマンドを呼び出すターゲットを検出すると、並列ではなく、逐次にターゲットが作成されます。これにより、 2 つの異なる dmake によって、同じディレクトリ中の同じターゲットが構築されなくなります。このような問題は、 2 つの異なるプログラムを並列構築して、両方が同じライブラリにアクセスする場合などに起きます。それぞれの dmake の呼び出しで、必ず最新のライブラリを適用するには、dmake を再帰的に呼び出して、ライブラリを構築する必要があります。dmake ユーティリティは、コマンド行から $(MAKE) マクロが使用されている場合にのみ、入れ子になった呼び出しを認識します。

コマンドを入れ子にしても、衝突することがない確信がある場合は、.PARALLEL: 構文を使用して並列処理できます。

メークファイルの中に、並列的に同時に動作する入れ子のコマンドが多数含まれている場合は、負荷均衡アルゴリズムによって、多数の構築ジョブがローカルのマシンに割り当てられることがあります。この結果、スワップ空間の不足といった別の問題が生じたり、負荷が大きくなったりすることも考えられます。こうした問題が起きた場合は、入れ子にしたコマンドをすべて逐次実行されるようにしてください。


サン・マイクロシステムズ株式会社
Copyright information. All rights reserved.
ホーム   |   目次   |   前ページへ   |   次ページへ   |   索引