この節では、プログラムのコンパイルとリンクについていくつかの側面から説明します。次の例では、CC を使って 3 つのソースファイルをコンパイルし、オブジェクトファイルをリンクして prgrm という実行可能ファイルを作成します。
demo% CC file.cc file2.cc file3.cc -o prgrm
前の例では、コンパイラがオブジェクトファイル (file1.o、file2.o、file3.o) を自動的に生成し、次にシステムリンカーを起動してファイル prgrm の実行可能プログラムを作成します。
オブジェクトファイル (file1.o、file2.o、file3.o) はコンパイルの後も消去されないので、ファイルを簡単に再リンクしたり、再コンパイルすることができます。
ソースファイルが 1 つだけであるプログラムに対してコンパイルとリンクを同時に行なった場合は、対応する.o ファイルが自動的に削除されます。複数のソースファイルをコンパイルする場合を除いて、すべての.o ファイルを残すためにはコンパイルとリンクを別々に行なってください。
コンパイルが失敗すると、エラーごとにメッセージが返されます。エラーがあったソースファイルの .o ファイルは生成されず、実行可能プログラムも作成されません。
コンパイルとリンクは別々に行うことができます。-c オプションを指定すると、ソースファイルがコンパイルされて .o オブジェクトファイルが生成されますが、実行可能ファイルは作成されません。-c オプションを指定しないと、コンパイラはリンカーを起動します。コンパイルとリンクを分離すれば、1 つのファイルを修正するためにすべてのファイルを再コンパイルする必要はありません。次の例では、最初の手順で 1 つのファイルをコンパイルし、次の手順でそれを他のファイルとリンクします。
demo% CC -c file1.cc //新しいオブジェクトファイルを作成する demo% CC -o prgrm file1.o file2.o file3.o //実行可能ファイルを作成する
リンク時には、完全なプログラムを作成するのに必要なすべてのオブジェクトファイルを指定してください。オブジェクトファイルが足りないと、リンクは「undefined external reference (未定義の外部参照がある)」エラー (ルーチンがない) で失敗します。
コンパイルとリンクを別々に実行する場合で、次のコンパイラオプションを使用する場合は、コンパイルとリンクの整合性を保つことが非常に重要です。
-fast
-g
-g0
-library
-misalign
-mt
-p
-xa
-xarch=a
-xcg92 および -xcg89
-xpg
-xprofile
-xtarget=t
これらのオプションのいずれかを使用してサブプログラムをコンパイルした場合は、リンクでも同じオプションを使用してください。
-library、-fast、-xarch オプションの場合、コンパイルとリンクを同時に行なった際に渡されたはずのリンカーオプションも含める必要があります。
-p、-xpg、-xprofile オプションの場合、あるコンパイルではオプションを指定して別のコンパイルでは指定しないと、プログラムの正しさには影響はありませんが、プロファイル処理ができなくなります。
-g、-g0 オプションの場合、あるコンパイルではオプションを指定して別のコンパイルでは指定しないと、プログラムの正しさには影響はありませんが、プログラムを正しくデバッグできなくなります。
次の例では、-xcg92 コンパイラオプションを使用してプログラムをコンパイルしています。このオプションは -xtarget=ss1000 用のマクロであり、 -xarch=v8 -xchip=super -xcache=16/64/4:1024/64/1 と展開されます。
プログラムがテンプレートを使用する場合は、リンク時にその中のいくつかがインスタンス化される可能性があります。その場合、インスタンス化されたテンプレートは最終行 (リンク行) のコマンド行オプションを使用してコンパイルされます。
demo% CC -c -xcg92 sbr.cc demo% CC -c -xcg92 smain.cc demo% CC -xcg92 sbr.o smain.o
C++ 5.0 コンパイラでは、32 ビットと 64 ビットの両方のバイナリを作成できます。
64 ビットオブジェクトのコンパイル、リンク、実行には、V9 SPARC の Solaris 7 環境で 64 ビットカーネルが動作していなければなりません。64 ビット Solaris 7 のコンパイルは、-xarch=v9 オプションまたは -xarch=v9a オプションで指定します。
-verbose オプションを使用すると、プログラムのコンパイル中に役立つ情報を表示できます。このオプションについては、第 3 章「C++ コンパイラオプション」を参照してください。
コマンド行に指定された引数をコンパイラが認識できない場合には、それらはリンカーオプション、オブジェクトプログラムファイル名、ライブラリ名のいずれかとみなされます。
基本的な区別は次のとおりです。
認識できないオプション (先頭にダッシュ (-) かプラス符号 (+) の付いたもの) には、警告が生成されます。
オプション以外のもの (先頭にダッシュ (-) もプラス符号 (+) も付いていないもの)には警告は生成されません (ただし、それらはリンカーに渡されます。リンカーも認識できないと、リンカーからエラーメッセージが生成されます)。
次の例で、-bit は CC によって認識されないため、リンカー (ld) に渡されます。リンカーはこれを解釈しようとします。単一文字の ld オプションは連続して指定できるので、リンカーは -bit を -b、-i、-t とみなします。これらはすべて有効な ld オプションです。しかし、これは本来の意図とは異なります。
demo% CC -bit move.cc <- -bit は CC オプションとして認識されない CC: 警告: ld が起動される場合は、オプション-bit は ld に渡されます。それ以外は無視されます。
次の例では、CC オプション -fast を指定しようとしましたが、先頭のダッシュ (-) を入力しませんでした。コンパイラはこの引数もリンカーに渡します。リンカーはこれをファイル名とみなします。
demo% CC fast move.cc <- -ユーザーは -fast と入力するつもりだった move.C: ld: 重大なエラー: ファイル fast: ファイルをオープンできません: ファイルもディレクトリもありません。 ld: 重大なエラー: ファイル処理エラー。 a.out へ書き込まれる出力がありません。
C++ コンパイラパッケージは、フロントエンド (CC コマンド本体)、オプティマイザ (最適化)、コードジェネレータ (コード生成)、アセンブラ、テンプレートのプリリンカー (リンクの前処理をするプログラム)、リンクエディタから構成されています。CC コマンドは、これらの構成要素をそれぞれ自動的に起動します。ただしユーザーがコマンド行オプションを使用して自動起動以外のことを指定する場合を除きます。図 2-1 に C++ コンパイルの流れを示します。
これらの構成要素はいずれもエラーを生成する可能性があり、構成要素はそれぞれ異なる処理を行うため、エラーを生成した構成要素を識別することがエラーの解決に役立つことがあります。
次の表に示すように、コンパイラの構成要素への入力ファイルには異なるファイル名接尾辞が付いています。どのようなコンパイルを行うかは、この接尾辞で決まります。ファイル接尾辞の意味については、表 2-1を参照してください。
表 2-2 C++ コンパイルシステムの構成要素
構成要素 |
内容 |
使用時の注意 |
---|---|---|
ccfe |
フロントエンド (コンパイラプリプロセッサ (前処理系) とコンパイラ) |
|
iropt |
コードオプティマイザ (最適化) |
(SPARC) -xO[2-5]、-fast |
cg386 |
中間言語トランスレータ |
(x86) 必ず起動 |
inline |
アセンブリ言語テンプレートのインライン展開 |
(SPARC) .il ファイルを指定 |
mwinline |
関数の自動的なインライン展開 |
(x86) -xO4、-xinline |
fbe |
アセンブラ |
|
cg |
コード生成、インライン機能、アセンブラ |
(SPARC) |
codegen |
コード生成 |
(x86) |
cc_link |
テンプレートのリンクの前処理 |
|
ld |
従来のリンクエディタ |
|
ild |
インクリメンタルリンクエディタ |
-g、-xildon |
コンパイルに必要なメモリー量は、次の要素によって異なります。
各手続きのサイズ
最適化のレベル
仮想メモリーに対して設定された限度
ディスク上のスワップファイルのサイズ
SPARC プラットフォームでメモリーが足りなくなると、オプティマイザは最適化レベルを下げて現在の手続きを実行することでメモリー不足を補おうとします。それ以後のルーチンについては、コマンド行の -xOlevel オプションで指定した元のレベルに戻ります。
1 つのファイルに多数のルーチンが入っている場合、それをコンパイルすると、メモリーやスワップ領域が足りなくなることがあります。その場合には、最適化レベルを下げるか、複数ルーチンからなるソースファイルを 1 つのルーチンからなるファイルに分割します。
現在のスワップ領域は swap -s コマンドで表示できます。詳細は、swap(1M) のマニュアルページを参照してください。
demo% swap -s total: 40236k bytes allocated + 7280k reserved = 47516k used, 1058708k available
ワークステーションのスワップ領域を増やすには、mkfile(1M) と swap(1M) コマンドを使用します (そのためには、スーパーユーザーでなければなりません)。mkfile コマンドは特定サイズのファイルを作成し、swap -a はこのファイルをシステムのスワップ領域に追加します。
demo# mkfile -v 90m /home/swapfile /home/swapfile 94317840 bytes demo# /usr/sbin/swap -a /home/swapfile
1 つの手続きが数千行からなるような非常に大きなルーチンを -xO3 以上でコンパイルすると、非常に多くのメモリーが必要になることがあります。このようなときには、システムのパフォーマンスが低下します。これを制御するには、1 つのプロセスで使用できる仮想メモリーの量を制限します。
sh シェルで仮想メモリーを制限するには、ulimit コマンドを使用します。詳細は、sh(1) のマニュアルページを参照してください。
次の例では、仮想メモリーを 16M バイトに制限しています。
demo$ ulimit -d 16000
csh シェルで仮想メモリーを制限するには、limit コマンドを使用します。詳細は、csh(1) のマニュアルページを参照してください。
次の例でも、仮想メモリーを 16M バイトに制限しています。
demo% limit datasize 16M
どちらの例でも、オプティマイザは データ空間が 16M バイトになった時点でメモリー不足が発生しないような手段をとります。
仮想メモリーの限度は、システムの合計スワップ領域の範囲内でなければなりません。さらに実際は、大きなコンパイルが行われているときにシステムが正常に動作できるだけの小さい値でなければなりません。
スワップ領域の半分以上がコンパイルによって使用されることがないようにしてください。
スワップ領域が 32M バイトなら次のコマンドを使用します。
demo$ ulimit -d 16000
demo% limit datasize 16M
最適な設定は、必要な最適化レベルと使用可能な実メモリーと仮想メモリーの量によって異なります。
メモリー条件については『Sun WorkShop クイックインストール』をご覧ください。