この章では、C++ コンパイラの使用方法を説明します。
コンパイラの主な目的は、C++ などの高水準言語で書かれたプログラムをコンピュータハードウェアで実行できるデータファイルに変換することです。C++ コンパイラでは次のことができます。
ソースファイルを再配置可能なバイナリ (.o) ファイルに変換する。これらのファイルはそのあと、実行可能ファイル、(-xar オプションで) 静的 (アーカイブ) ライブラリ (.a) ファイル、動的 (共有) ライブラリ (.so) ファイルなどにリンクされる。
オブジェクトファイルとライブラリファイルのどちらか (または両方) をリンク (または再リンク) して実行可能ファイルを作成する。
実行時デバッグを (-g オプションで) 有効にして、実行可能ファイルをコンパイルする。
文レベルや手続きレベルの実行時プロファイルを (-pg オプションで) 有効にして、実行可能ファイルをコンパイルする。
この節では、C++ コンパイラを使って C++ プログラムのコンパイルと実行をどのように行うかを簡単に説明します。コマンド行オプションの詳しい説明については、「16.8 dlopen を使って C プログラムから C++ ライブラリにアクセスする」を参照してください。
この章のコマンド行の例は、CC の使用方法を示すためのものです。実際に出力される内容はこれと多少異なる場合があります。
C++ アプリケーションを構築して実行するには、基本的に次の手順が必要です。
エディタを使用して、表 2–1 に一覧表示されている有効な接尾辞の 1 つを指定し、C++ ソースファイルを作成する。
コンパイラを起動して実行可能ファイルを作成する。
実行可能ファイルの名前を入力してプログラムを実行する。
次のプログラムは、メッセージを画面に表示する例です。
example% cat greetings.cc #include <iostream> int main() { std::cout << “Real programmers write C++!” << std::endl; return 0; } example% CC greetings.cc example% ./a.out Real programmers write C++! example% |
この例では、ソースファイル greetings.cc を CC でコンパイルしています。デフォルトでは、実行可能ファイルがファイル a.out として作成されます。プログラムを起動するには、コマンドプロンプトで実行可能ファイル名 a.out を入力します。
従来、UNIX コンパイラは実行可能ファイルに a.out という名前を付けていました。しかし、すべてのコンパイルで同じファイルを使用するのは不都合な場合があります。そのファイルがすでにあれば、コンパイラを実行したときに上書きされてしまうからです。次の例のように、コンパイラオプションに -o を使用すれば、実行可能出力ファイルの名前を指定できます。
example% CC– o greetings greetings.cc |
この例では、-o オプションを指定することによって、実行可能なコードがファイル greetings に書き込まれます。プログラムにソースファイルが 1 つだけしかない場合は、ソースファイル名から接尾辞を除いたものをそのプログラム名にすることが一般的です。
あるいは、コンパイルのあとに mv コマンドを使って、デフォルトの a.out ファイルを別の名前に変更することもできます。いずれの場合も、実行可能ファイルの名前を入力して、プログラムを実行します。
example% ./greetings Real programmers write C++! example% |
このあとの節では、CC コマンドで使用する規約、コンパイラのソース行指令など、コンパイラの使用に関連する内容について説明します。
CC [options] [source-files] [object-files] [libraries] |
options は、先頭にダッシュ (-) またはプラス記号 (+) の付いたキーワード (オプション) です。このオプションには、引数をとるものがあります。
通常, コンパイラオプションの処理は、左から右へと行われ、マクロオプション (ほかのオプションを含むオプション) は、条件に応じて内容が変更されます。ほとんどの場合、同じオプションを 2 回以上指定すると、最後に指定したものだけが有効になり、オプションの累積は行われません。次の点に注意してください。
すべてのリンカーオプション、ならびに -features、-I、l、L、-library、-pti、-R、-staticlib、-U、-verbose および -xprefetch オプションで指定した内容は蓄積され、上書きはされません。
-U オプションは、すべて -D オプションのあとに処理されます。
ソースファイル、オブジェクトファイル、およびライブラリは、コマンド行に指定した順にコンパイルとリンクが行われます。
次の例では、CC を使って 2 つのソースファイル (growth.C と fft.C) をコンパイルし、実行時デバッグを有効にして growth という名前の実行可能ファイルを作成します。
example% CC -g -o growth growth.C fft.C |
コンパイラがコマンド行に指定されたファイルをどのように処理するかは、ファイル名に付加された接尾辞で決まります。次の表以外の接尾辞を持つファイルや、接尾辞がないファイルはリンカーに渡されます。
表 2–1 C++ コンパイラが認識できるファイル名接尾辞
接尾辞 |
言語 |
処理 |
---|---|---|
C++ |
C++ ソースファイルとしてコンパイルし、オブジェクトファイルを現在のディレクトリに入れる。オブジェクトファイルのデフォルト名は、ソースファイル名に .o 接尾辞が付いたものになる。 |
|
C++ |
.c 接尾辞と同じ処理。 |
|
C++ |
.c 接尾辞と同じ処理。 |
|
C++ |
.c 接尾辞と同じ処理。 |
|
C++ |
.c 接尾辞と同じ処理。 |
|
C++ |
.c 接尾辞と同じ処理。 |
|
C++ |
C++ ソースファイルとして扱われるプリプロセッサ出力ファイル。.c 接尾辞と同じ処理。 |
|
アセンブラ |
ソースファイルをアセンブラを使ってアセンブルする。 |
|
アセンブラ |
C 言語プリプロセッサとアセンブラを使ってソースファイルをアセンブルする。 |
|
インライン展開 |
アセンブリ用のインラインテンプレートファイルを使ってインライン展開を行う。コンパイラはテンプレートを使って、選択されたルーチンのインライン呼び出しを展開します(インラインテンプレートファイルは、特殊なアセンブラファイルです。inline(1) のマニュアルページを参照してください)。 |
|
オブジェクトファイル |
オブジェクトファイルをリンカーに渡す |
|
静的 (アーカイブ) ライブラリ |
オブジェクトライブラリの名前をリンカーに渡す。 |
|
動的 (共有) ライブラリ |
共有オブジェクトの名前をリンカーに渡す。 |
C++ コンパイラでは、複数のソースファイルをコマンド行に指定できます。コンパイラが直接または間接的にサポートするファイルも含めて、コンパイラによってコンパイルされる 1 つのソースファイルを「コンパイル単位」といいます。C++ では、それぞれのソースが別個のコンパイル単位として扱われます。
このコンパイラは、デフォルトではキャッシュを使用しません。キャッシュを使用するのは、-instances=extern が指定されているときだけです。キャッシュを使用する場合、コンパイラはキャッシュディレクトリのバージョンを調べ、その結果キャッシュバージョンに問題があることがわかると、エラーメッセージを出力します。将来の C++ コンパイラもキャッシュのバージョンを調べます。たとえば、将来のコンパイラは異なるテンプレートキャッシュのバージョン識別子を持っているため、現在のリリースで作成されたキャッシュディレクトリを処理しようとすると、次のようなエラーを出力します。
Template Database at ./SunWS_cache is incompatible with this compiler |
同様に、現在のリリースのコンパイラで以降のバージョンのコンパイラで作成されたキャッシュディレクトリを処理しようとすると、エラーが発行されます。
コンパイラをアップグレードする際には、必ずキャッシュを消去するようにするとよいでしょう。テンプレートキャッシュディレクトリ (ほとんどの場合、テンプレートキャッシュディレクトリの名前は SunWS_cache) が入っているディレクトリすべてに対し、CCadmin -clean を実行します。CCadmin -clean の代わりに、rm -rf SunWS_cache と指定しても同様の結果が得られます。
この節では、プログラムのコンパイルとリンクについていくつかの側面から説明します。次の例では、CC を使って 3 つのソースファイルをコンパイルし、オブジェクトファイルをリンクして prgrm という実行可能ファイルを作成します。
example% CC file1.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 つのファイルをコンパイルし、次の手順でそれをほかのファイルとリンクします。
example% CC -c file1.cc Make new object file example% CC -o prgrm file1.o file2.o file3.o Make executable file |
リンク時には (2 行目)、完全なプログラムを作成するのに必要なすべてのオブジェクトファイルを必ず 指定してください。オブジェクトファイルが足りないと、リンクは「undefined external reference (未定義の外部参照がある)」エラーで、ルーチンがないために失敗します。
コンパイルとリンクを別々に実行する場合で、「3.3.3 コンパイル時とリンク時のオプション」に示すコンパイラオプションを使用する場合は、コンパイルとリンクの整合性を保つことが非常に重要です。
これらのオプションのいずれかを使用してサブプログラムをコンパイルした場合は、リンクでも同じオプションを使用してください。
-library、-fast、-xtarget、-xarch オプションの場合、コンパイルとリンクを同時に行えば渡されるはずのリンカーオプションも含める必要があります。—dryrun を使用してこれらのオプションの展開を調べ、リンク手順で必要なオプションを判断してください。
-p、-xpg、-xprofile オプションの場合、ある段階ではオプションを指定して別の段階では指定しないと、プログラムの正しさには影響はありませんが、プロファイル処理ができなくなります。
-g、-g0 オプションの場合、ある段階ではオプションを指定して別の段階では指定しないと、プログラムの正しさには影響はありませんが、プログラムを正しくデバッグできなくなります。これらのオプションでコンパイルされず、-g または -g0 でリンクされるいずれのモジュールも、デバッグには使用できません。--g オプション (または -g0 オプション)付きの main 関数があるモジュールをコンパイルするには、通常デバッグする必要があります。
次の例では、-library=stlport4 コンパイラオプションを使用してプログラムをコンパイルしています。
example% CC -library=stlport4 sbr.cc -c example% CC -library=stlport4 main.cc -c example% CC -library=stlport4 sbr.o main.o -o myprogram |
-library=stlport4 を一貫して使用しない場合は、プログラムの特定の部分はデフォルトの libCstd を使用し、ほかの部分はオプションの置換である STlport ライブラリを使用します。結果として得られたプログラムは正常にリンクできず、どのような状況でも正常に動作しません。
プログラムがテンプレートを使用する場合は、リンク時にその中のいくつかがインスタンス化される可能性があります。その場合、インスタンス化されたテンプレートは最終行 (リンク行) のコマンド行オプションを使用してコンパイルされます。
新しい -m64 オプションを使用して、対象コンパイルのメモリーモデルを指定します。結果の実行可能ファイルは、64 ビットカーネルを実行する Solaris OS または Linux OS の配下にある、64 ビットの UltraSPARC または x86 プロセッサでのみ動作します。コンパイルリンク、および 64 ビットオブジェクトの実行は、64 ビット実行をサポートする Solaris または Linux OS でのみ行うことができます。
-V オプションを指定すると、CC によって起動された各プログラムの名前とバージョン番号が表示されます。-v オプションを指定すると、CC によって起動されたコマンド行全体が表示されます。
—verbose=%all を指定すると、コンパイラに関する追加情報が表示されます。
コマンド行に指定された引数をコンパイラが認識できない場合には、それらはリンカーオプション、オブジェクトプログラムファイル名、ライブラリ名のいずれかとみなされます。
基本的には次のように区別されます。
認識できない非オプション (先頭にダッシュかプラス符号 (+) が付いていないもの)には、警告が生成されません。ただし、リンカーへの引き渡しは行われます。リンカーが認識しない場合、リンカーからエラーメッセージが生成されます。
次の例で、-bit は CC によって認識されないため、リンカー (ld) に渡されます。リンカーはこれを解釈しようとします。単一文字の ld オプションは連続して指定できるので、リンカーは -bit を -b、-i、-t とみなします。これらはすべて有効な ld オプションです。しかし、これは本来の意図とは異なります。
example% CC -bit move.cc < - -bit is not a recognized CC option CC: Warning: Option -bit passed to ld, if ld is invoked, ignored otherwise |
次の例では、CC オプション -fast を指定しようとしましたが、先頭のダッシュ (-) を入力しませんでした。コンパイラはこの引数もリンカーに渡します。リンカーはこれをファイル名とみなします。
example% CC fast move.cc < - The user meant to type -fast move.CC: ld: fatal: file fast: cannot open file; errno=2 ld: fatal: File processing errors. No output written to a.out |
C++ コンパイラパッケージは、フロントエンド (CC コマンド本体)、オプティマイザ (最適化)、コードジェネレータ (コード生成)、アセンブラ、テンプレートのプリリンカー (リンクの前処理をするプログラム)、リンクエディタから構成されています。コマンド行オプションでほかの指定を行わないかぎり、CC コマンドはこれらの構成要素をそれぞれ起動します。
これらの構成要素はいずれもエラーを生成する可能性があり、構成要素はそれぞれ異なる処理を行うため、エラーを生成した構成要素を識別することがエラーの解決に役立つことがあります。それには、-v オプションと -dryrun オプションを使用します。
次の表に示すように、コンパイラの構成要素への入力ファイルには異なるファイル名接尾辞が付いています。どのようなコンパイルを行うかは、この接尾辞で決まります。ファイル名接尾辞の意味については、表 2–1 を参照してください。
表 2–2 C++ コンパイルシステムの構成要素
コンポーネント |
内容の説明 |
使用時の注意 |
---|---|---|
フロントエンド (コンパイラプリプロセッサ (前処理系) とコンパイラ) | ||
コードオプティマイザ |
-xO[2-5]、-fast |
|
x86: 中間言語トランスレータ |
-xO[2-5]、-fast |
|
SPARC: アセンブリ言語テンプレートのインライン展開 |
.il ファイルを指定 |
|
アセンブラ | ||
SPARC: コード生成、インライン機能、アセンブラ |
|
|
ube |
x86: コードジェネレータ |
-xO[2-5]、-fast |
テンプレートのプリリンカー |
-instances=extern オプションのみで使用します。 |
|
リンクエディタ |
この節では、C++ コンパイラ特有の前処理の指示について説明します。
プリプロセッサ指令 pragma は C++ 標準の一部ですが、書式、内容、および意味はコンパイラごとに異なります。C++ コンパイラが認識するプラグマ (指令) の詳細は、付録 B プラグマを参照してください。
Sun C++ は、C99 のキーワードである _Pragma もサポートしています。これら 2 つの呼び出し
#pragma dumpmacros(defs) _Pragma("dumpmacros(defs)") |
は同等です。_Pragma の代わりに _Pragma を使用するには、プラグマテキストをリテラル文字列として記述し、_Pragma キーワードの 1 つの引数として括弧で囲みます。
C++ コンパイラでは次の書式の #define プリプロセッサの指示を受け入れます。
#define identifier (...) replacement_list #define identifier (identifier_list, ...) replacement_list |
マクロパラメータリストの終わりが省略符号である場合、マクロパラメータより多くの引数をマクロの呼び出しで使用できます。追加の引数は、マクロ交換リストにおいて __VA_ARGS__ という名前で参照できる、コンマを含んだ単一文字列にまとめられます。次の例は、変更可能な引数リストマクロの使い方を示しています。
#define debug(...) fprintf(stderr, __VA_ARGS__) #define showlist(...) puts(#__VA_ARGS__) #define report(test, ...) ((test)?puts(#test):\ printf(__VA_ARGS__)) debug(“Flag”); debug(“X = %d\n”,x); showlist(The first, second, and third items.); report(x>y, “x is %d but y is %d”, x, y); |
この結果は、次のようになります。
fprintf(stderr, “Flag”); fprintf(stderr, “X = %d\n”, x); puts(“The first, second, and third items.”); ((x>y)?puts(“x>y”):printf(“x is %d but y is %d”, x, y)); |
付録の表 A–2 は、事前に定義されているマクロを示しています。これらの値は、#ifdef のようなプリプロセッサに対する条件式の中で使用できます。+p オプションを指定すると、sun、unix、sparc、および i386 の事前定義マクロは自動的に定義されません。
#error 指令は、警告生成後にコンパイルを続行しなくなりました。以前の #error 指令は、警告を生成してコンパイルを続行していました。新しい #error では、ほかのコンパイラとの整合性が確保され、エラーメッセージを生成してコンパイルをすぐに停止するようになりました。コンパイラは終了して障害をレポートします。
コンパイルに必要なメモリー量は、次の要素によって異なります。
各手続きのサイズ
最適化のレベル
仮想メモリーに対して設定された限度
ディスク上のスワップファイルのサイズ
SPARC プラットフォームでメモリーが足りなくなると、オプティマイザは最適化レベルを下げて現在の手続きを実行することでメモリー不足を補おうとします。それ以後のルーチンについては、コマンド行の -xOlevel オプションで指定した元のレベルに戻ります。
1 つのファイルに多数のルーチンが入っている場合、それをコンパイルすると、メモリーやスワップ領域が足りなくなることがあります。最適化のレベルを下げてみてください。代わりに、最大のプロシージャを、個別のファイルに分割してください。
現在のスワップ領域は swap -s コマンドで表示できます。詳細は、swap(1M) のマニュアルページを参照してください。
swap コマンドを使った例を次に示します。
example% swap -s total: 40236k bytes allocated + 7280k reserved = 47516k used, 1058708k available |
ワークステーションのスワップ領域を増やすには、mkfile(1M) と swap(1M) コマンドを使用します。そのためには、スーパーユーザーである必要があります。mkfile コマンドは特定サイズのファイルを作成し、swap -a はこのファイルをシステムのスワップ領域に追加します。
example# mkfile -v 90m /home/swapfile /home/swapfile 94317840 bytes example# /usr/sbin/swap -a /home/swapfile |
1 つの手続きが数千行からなるような非常に大きなルーチンを -xO3 以上でコンパイルすると、大容量のメモリーが必要になることがあります。このようなときには、システムのパフォーマンスが低下します。これを制御するには、1 つのプロセスで使用できる仮想メモリーの量を制限します。
sh シェルで仮想メモリーを制限するには、ulimit コマンドを使用します。詳細は、sh(1) のマニュアルページを参照してください。
次の例では、仮想メモリーを 4G バイトに制限しています。
example$ ulimit -d 4000000 |
csh シェルで仮想メモリーを制限するには、limit コマンドを使用します。 詳細は、csh(1) のマニュアルページを参照してください。
次の例でも、仮想メモリーを 4G バイトに制限しています。
example% limit datasize 4G |
どちらの例でも、オプティマイザは データ空間が 4G バイトになった時点でメモリー不足が発生しないような手段をとります。
仮想メモリーの限度は、システムの合計スワップ領域の範囲内です。さらに実際は、大きなコンパイルが行われているときにシステムが正常に動作できるだけの小さい値である必要があります。
スワップ領域の半分以上がコンパイルによって使用されることがないようにしてください。
8G バイトのスワップ領域のあるマシンでは、次のコマンドを使用します。
sh シェルの場合
example$ ulimit -d 4000000 |
csh の場合
example% limit datasize 4G |
最適な設定は、必要な最適化レベルと使用可能な実メモリーと仮想メモリーの量によって異なります。
ワークステーションには、少なくとも 1G バイトのメモリーを実装するべきです。2G バイトをお勧めします。要件の詳細は、製品リリースの Readme (http://developers.sun.com/sunstudio/documentation/ ) を参照してください。
Unix の strip コマンドは、C++ のオブジェクトファイルに対して使用すべきではありません。それらのオブジェクトファイルが使用不可能になることがあります。
CCFLAGS 環境変数で特別なシェル別名を定義するか make を使用すれば、複雑なコンパイラコマンドを簡略化できます。
次の例では、頻繁に使用するオプションをコマンドの別名として定義します。
example% alias CCfx "CC -fast -xnolibmil" |
次に、この別名 CCfx を使用します。
example% CCfx any.C |
前述のコマンド CCfx は、次のコマンドを実行するのと同じことです。
example% CC -fast -xnolibmil any.C |
CCFLAGS 環境変数を設定すると、一度に特定のオプションを指定できます。
CCFLAGS 変数は、コマンド行に明示的に指定できます。次の例は、CCFLAGS の設定方法を示したものです (C シェル)。
example% setenv CCFLAGS ’-xO2 -m64’ |
次の例では、CCFLAGS を明示的に使用しています。
example% CC $CCFLAGS any.cc |
make を使用する場合、CCFLAGS 変数が前述の例のように設定され、メイクファイルのコンパイル規則が暗黙的に使用された状態で make を呼び出すと、次と同じコンパイルが行われます。
CC -xO2 -m64 files...
make ユーティリティーは、Sun のすべてのコンパイラで簡単に使用できる非常に強力なプログラム開発ツールです。詳細については make(1S) のマニュアルページを参照してください。
メイクファイルの暗黙のコンパイラ規則を使用する、つまり、C++ コンパイルがない場合は、make プログラムによって CCFLAGS が自動的に使用されます。