$WEAKPACKAGEUNIT 指令の使用
パッケージのコンパイル への移動
弱いユニット(弱くパッケージ化されたユニット)は、パッケージ(つまりパッケージ プロジェクト)内で定義されたユニットです。ただし、動的にリンクされたパッケージの場合はリンク方法が異なります。
通常、ユニットはパッケージ自体に存在します。BPI ファイル(パッケージ インポート ライブラリ)にリンクされると、パッケージへの参照が生成されます。
対照的に、弱くパッケージ化されたユニットは BPI 自体に存在します。つまり、動的にリンクされたパッケージであっても、弱くパッケージ化されたユニットはパッケージ コンシューマ モジュールに直接リンクされます。重要なのは、BPL ファイルを更新することと、BPL を使用してソフトウェアを再コンパイルすることを別々に行うことで、BPL に含まれているはずの弱くパッケージ化されたユニットは、それを使用するソフトウェアでは更新されないということです。これは、ユニットが実際にはインポートライブラリ(BPI)内にあり、パッケージ コンシューマにリンクされているためです。
パッケージ内の弱いユニットのみを使用する場合、アプリケーションはそのパッケージに依存しません(つまり、BPL ファイルへの依存関係はありません)。インポート オブジェクトの代わりに、BPI にはユニットのオブジェクトファイル(静的パッケージの場合と同様に)が含まれており、そのオブジェクト ファイルがリンクされているため、パッケージ自体への依存関係はなくなります。言い換えれば、弱くリンクされたユニットは動的と静的が混在し、弱いユニットは静的なものと言えます。
以下では、例を使用してDelphi と C++Builder の場合について、この動作を説明していきます。
Delphi
$WEAKPACKAGEUNIT 指令は、.dcu ファイルがパッケージの .dcp および .bpl ファイルに格納される方法について作用します。
{$WEAKPACKAGEUNIT ON} がユニット ファイルで検出された場合、コンパイラはそのユニットを BPL から除外し(可能な場合)、別のアプリケーションやパッケージで必要になったときには、そのユニットのパッケージ化されていないローカル コピーを作成します。 この指令を付けてコンパイルされたユニットは、弱くパッケージ化されていると言います。
たとえば、unit1 というユニットを 1 つ格納している、pack1 というパッケージを生成するとします。unit1 は別のユニットをさらに使うことはないとしますが、rare.dll への呼び出しは行います。パッケージのコンパイル時に、{$WEAKPACKAGEUNIT ON} 指令を unit1.pas (Delphi) または unit1.cpp (C++) に置くと、unit1 は pack1.bpl には含まれません。このため、rare.dll のコピーを pack1 と一緒に配布する必要はありません。しかしながら、unit1 はそれでもなお pack1.dcp に含まれています。unit1 が、pack1 を使用する別のパッケージやアプリケーションから参照されている場合、それは pack1.dcp からコピーされ、プロジェクト内部に直接コンパイルされます。
{$WEAKPACKAGEUNIT ON} を指定したとしても、コンパイラは、unit1 を pack1.bpl に含めます。しかし、unit1 を参照している他のパッケージやアプリケーションでは、(パッケージ化されていない)コピーを pack1.dcp から取得して使用します。{$WEAKPACKAGEUNIT ON} 指令が含まれているユニット ファイルには、グローバル変数、initialization セクション、finalization セクションが存在してはいけません。{$WEAKPACKAGEUNIT ON} 指令は、他のプログラマにパッケージを配布する開発者向けの高度な機能です。 この機能は、使用頻度の低い DLL の配布を避け、また、同じ外部ライブラリに依存する可能性のあるパッケージ間で競合を解消するのに役立ちます。
たとえば、PenWin ユニットは PenWin.dll を参照します。ほとんどのプロジェクトでは PenWin を使用せず、また、ほとんどのコンピュータにも PenWin.dll はインストールされていません。このような理由から、PenWin ユニットは、vcl に弱くパッケージ化されています。PenWin と vcl パッケージを使用するプロジェクトをコンパイルすると、PenWin が vcl70.dcp からコピーされ、プロジェクトに直接バインドされます。結果として生成される実行可能ファイルは PenWin.dll に静的にリンクされています。
PenWin が弱くパッケージ化されなかった場合は、2 つの問題が発生します。 第 1 に、vcl 自身が PenWin.dll に静的にリンクされてしまうので、PenWin.dll がインストールされていないコンピュータには vcl を読み込むことができなくなってしまいます。 第 2 に、PenWin を含んだパッケージを作成しようとした場合、そのパッケージと vcl の両方に PenWin ユニットが含まれてしまうため、コンパイル エラーが発生します。 このように、弱いパッケージ化がなければ、PenWin を vcl の標準配布物に含めることはできません。
C++Builder
#pragma package(smart_init, weak) 指令は、パッケージの .bpi ファイルおよび .bpl ファイルへの .obj ファイルの格納方法に影響を及します (コンパイラとリンカで生成されるファイルについては、「パッケージと標準 DLL」を参照)。 #pragma package(smart_init, weak) がユニット ファイルで検出された場合、リンカはそのユニットを bpl からできるだけ除外し、別のアプリケーションやパッケージで必要になったときには、そのユニットのパッケージ化されていないローカル コピーを作成します。 この指令を付けてコンパイルされたユニットは、弱くパッケージ化されていると言われます。
たとえば、ユニットが 1 つだけ(UNIT1)含まれている PACK というパッケージを作成したとしましょう。UNIT1 ではもう他のユニットを使用することはなく、RARE.dll を呼び出すと想定します。パッケージをビルドする際に UNIT1.cpp に #pragma package(smart_init, weak) 指令が記述されていると、UNIT1 は PACK.bpl には含まれません。このため、RARE.dll のコピーを PACK と一緒に配布しなくてもよくなります。ただし、UNIT1 は依然として PACK.bpi に含まれています。PACK を使用する別のパッケージやアプリケーションから UNIT1 が参照されている場合は、それが PACK.bpi からコピーされ、プロジェクトに直接リンクされます。
ここで、2 つ目のユニット UNIT2 を PACK に追加するとしましょう。 unit2 は unit1 を使用するものとします。 今度は、PACK のコンパイル時に UNIT1.cpp に #pragma package(smart_init, weak) を指定したとしても、リンカは UNIT1 を PACK.bpl にふくめます 。しかし、unit1 を参照している他のパッケージやアプリケーションでは、(パッケージ化されていない)コピーを PACK.bpi から取得して使用します。
#pragma package(smart_init, weak) 指令が含まれたユニット ファイルには、グローバル変数を定義しないでください。#pragma package(smart_init, weak) 指令は、他の C++Builder プログラマに bpl を配布する開発者向けの高度な機能です。 この機能は、使用頻度の低い DLL の配布を避け、また、同じ外部ライブラリに依存する可能性のあるパッケージ間で競合を解消するのに役立ちます。
たとえば、PenWin ユニットは PenWin.dll を参照します。ほとんどのプロジェクトでは PenWin を使用せず、また、ほとんどのコンピュータにも PenWin.dll はインストールされていません。このような理由から、PenWin ユニットは、vcl に弱くパッケージ化されています。PenWin と vcl パッケージを使用するプロジェクトをリンクすると、PenWin が vcl60.bpi からコピーされ、プロジェクトに直接バインドされます。結果として生成される実行可能ファイルは PenWin.dll に静的にリンクされています。
PenWin が弱くパッケージ化されなかった場合は、2 つの問題が発生します。第 1 に、vcl 自身が PenWin.dll に静的にリンクされてしまうので、PenWin.dll がインストールされていないコンピュータには vcl を読み込むことができなくなってしまいます。第 2 に、PenWin を含んだパッケージを作成しようとした場合、そのパッケージと vcl の両方に PenWin ユニットが含まれてしまうため、ビルド エラーが発生します。このように、弱いパッケージ化がなければ、PenWin を vcl の標準配布物に含めることはできません。
詳細については、#pragma package(smart_init, weak) ついては C++ ドキュメントを、弱いパッケージ化や弱いパッケージ化の指令については Delphi ドキュメントを参照してください。