2.2. GCC でのコードのビルド
ソースコードを実行可能コードに変換する必要がある状況を説明します。
2.2.1. コード形式間の関係 リンクのコピーリンクがクリップボードにコピーされました!
C 言語と C++ 言語には、ビルドプロセスの各段階で作成される 3 つの形式のコードがあります。これらの関係を理解すると、GCC を効果的に使用できるようになります。
C 言語および C++ 言語には、以下の 3 つのコード形式があります。
C 言語または C++ 言語で記述された ソースコード。プレーンテキストファイルとして表示されます。
このファイルは通常、
.c、.cc、.cpp、.h、.hpp、.i、.incなどの拡張子を使用します。サポートされる拡張子およびその解釈のリストは、gcc の man ページを参照してください。$ man gccコンパイラー でソースコードを コンパイル して作成する オブジェクトコード。これは中間形式です。
オブジェクトコードファイルは、拡張子
.oを使用します。リンカー でオブジェクトコードを リンク して作成する 実行可能なコード。
Linux アプリケーションの実行可能ファイルは、ファイル名の拡張子を使用しません。共有オブジェクト (ライブラリー) の実行可能ファイルは、
.soのファイル名の拡張子を使用します。
静的リンク用のライブラリーアーカイブファイルも存在します。これは、ファイル名拡張子 .a を使用するオブジェクトコードのバリアントです。静的リンクは推奨されません。静的リンクおよび動的リンク を参照してください。
ソースコードから実行可能コードを生成するには、次の 2 つのステップを実行します。それぞれ異なるアプリケーションまたはツールが必要です。
- ソースファイルをオブジェクトファイルにコンパイルします。
- オブジェクトファイルとライブラリーをリンクします (以前にコンパイルしたソースを含む)。
GCC は、コンパイラーとリンカーのどちらにも、インテリジェントドライバーとして使用できます。これにより、必要なアクション (コンパイルおよびリンク) に gcc コマンドを 1 つ使用できます。GCC はアクションとそのシーケンスを自動的に選択します。
GCC では、コンパイルのみ、リンクのみ、または両方のステップを実行できます。これは、入力タイプや必要とされる出力タイプにより決定されます。
大規模なプロジェクトには、アクションごとに個別に GCC を実行するビルドシステムが必要なため、GCC が両方同時に実行できる場合でも 2 つの異なるアクションとしてコンパイルとリンクを実行することを検討することが推奨されます。
2.2.2. オブジェクトコードへのソースファイルのコンパイル リンクのコピーリンクがクリップボードにコピーされました!
オブジェクトコードファイルを、実行ファイルから直接作成するのではなく、ソースファイルから作成するには、GCC で、オブジェクトコードファイルのみを出力として作成するように必要があります。このアクションは、大規模なプロジェクトのビルドプロセスの基本操作となります。
前提条件
- C または C++ のソースコードファイルがある
- GCC がシステムにインストールされている
手順
- ターミナルで、ソースコードファイルが含まれているディレクトリーを開きます。
-cオプションを指定してgccを実行します。$ gcc -c source.c another_source.cオブジェクトファイルは、オリジナルのソースコードファイルを反映したファイル名を使用して作成されます。
source.cはsource.oになります。注記C++ ソースコードの場合は、標準 C++ ライブラリーの依存関係を処理しやすくするために、
gccコマンドをg++に置き換えます。
2.2.3. GCC で C および C++ のアプリケーションのデバッグの有効化 リンクのコピーリンクがクリップボードにコピーされました!
コンパイラーはバイナリーのサイズを抑えるために、デフォルトでデバッグ情報を省略します。GCC を使用した C および C++ のアプリケーションのデバッグを有効にするには、コンパイラーに対して、デバッグデータを作成するように、明示的に指示する必要があります。
手順
GCC を使用して C または C++ アプリケーションをコンパイルおよびリンクするときにデバッグ情報を生成するには、コンパイルコマンドに
-gオプションを追加します。$ gcc ... -g ...このオプションは、出力のバイナリーにデバッグ情報を含めるように GCC に指示します。
-gオプションと追加のデバッグオプションの詳細は、GCC の man ページを参照してください。デバッグ情報にマクロの定義を含めるには、
-gの代わりに-g3オプションを使用します。$ gcc ... -g3 ...デバッグオプションが実行可能コードに影響を与えないことをテストするには、
-fcompare-debugGCC オプションを使用します。このオプションは以下を実行します。- コードを 2 回コンパイルします。1 回はデバッグ情報あり、もう 1 回はデバッグ情報なしでコンパイルします。
- 結果のバイナリーファイルを比較します。
両方のバイナリーが同一であればテスト合格とします。
このテストは、デバッグオプションによってコードに隠れたバグが混入するのを防ぐものです。
-fcompare-debugを使用すると、コンパイル時間が大幅に長くなることに注意してください。詳細は、GCC の man ページを参照してください。重要コンパイラーとリンカーを最適化すると、次の要因によってデバッグが困難になる場合があります。* 使用されていないように見える変数の削除 * ループの展開 * 操作のマージ * ソースコードと実行可能コードの関係の変更
デバッグエクスペリエンスを向上させるには、
-Ogオプションの使用を検討してください。ただし、最適化レベルを変更すると、実行可能コードの動作が変わり、バグが隠れてしまう可能性があります。
2.2.4. GCC でのコードの最適化 リンクのコピーリンクがクリップボードにコピーされました!
1 つのプログラムは、複数の機械語命令シーケンスに変換できます。コンパイル時にコードを分析するためにより多くのリソースを割り当てると、より最適な結果が得られます。
GCC では、-Olevel オプションを使用して最適化レベルを設定できます。このオプションでは、level の部分に値を指定できます。
| レベル | 説明 |
|---|---|
|
| コンピレーション速度の最適化 - コードの最適化なし (デフォルト) |
|
| 最適化して、コード実行速度を向上させます (数値が大きいほど、速度は高くなります)。 |
|
| ファイルサイズを最適化します。 |
|
|
レベルを |
|
| デバッグ作業の最適化 |
リリースビルドの場合は、最適化オプション -O2 を使用します。
開発中は、-Og オプションは、状況によってはプログラムまたはライブラリーをデバッグするのに役立ちます。バグによっては、特定の最適化レベルでのみ出現するため、リリースの最適化レベルでプログラムまたはライブラリーをテストしてください。
GCC では、個別の最適化を有効にするオプションが多数含まれています。詳細は、gcc man ページを参照してください。
2.2.5. GCC でコードを強化するオプション リンクのコピーリンクがクリップボードにコピーされました!
コンパイラーで、ソースコードをオブジェクトコードに変換する場合には、さまざまなチェックを追加して、一般的に悪用される状況などを回避し、セキュリティーを強化できます。適切なコンパイラーオプションセットを選択すると、ソースコードを変更せずに、よりセキュアなプログラムやライブラリーを作成できます。
- リリースバージョンのオプション
Red Hat Enterprise Linux を使用する開発者には、以下のオプションリストが推奨される最小限のオプションとなります。
$ gcc ... -O2 -g -Wall -Wl,-z,now,-z,relro -fstack-protector-strong -fstack-clash-protection -D_FORTIFY_SOURCE=3 ...-
プログラムの場合は、
-fPIEおよび-pieの位置独立実行可能オプションを追加します。 -
動的にリンクされたライブラリーの場合は、必須の
-fPIC(位置独立コード) オプションを使用すると間接的にセキュリティーが強化されます。
-
プログラムの場合は、
- 開発オプション
開発時にセキュリティーの欠陥を検出する場合は、以下のオプションを使用します。これらのオプションは、リリースバージョンのオプションと併せて使用してください。
$ gcc ... -Walloc-zero -Walloca-larger-than -Wextra -Wformat-security -Wvla-larger-than ...- -
fhardened -
GCC 14 では新しいフラグ
-fhardenedが提供され、これにより他の多くのフラグが有効になり、ABI に影響を与えずに生成されたコードのセキュリティーが向上します。 - -
fanalyzer -
GCC には、セキュリティー関連の問題を含む、ソースコード内の潜在的な問題に関する警告をトリガーするフラグ
-fanalyzerが用意されています。-fanalyzerでは誤検出や検出漏れが頻繁に発生するため、正式な解析ツールとしてではなく、詳細な調査が必要な潜在的なバグを見つけるための参考ツールとして使用する必要があります。このフラグにより、コンパイル中に使用される時間とメモリーが大幅に増加します。C コードでのみ使用してください。
2.2.6. 実行ファイルを作成するコードのリンク リンクのコピーリンクがクリップボードにコピーされました!
C または C++ のアプリケーション構築の最後の手順は、リンクです。リンクにより、オブジェクトファイルやライブラリーがすべて実行可能ファイルに統合されます。
前提条件
- オブジェクトファイルが 1 つまたは複数ある。
- GCC がシステムにインストールされている。
手順
- オブジェクトコードファイルを含むディレクトリーに移動します。
gccを実行します。$ gcc ... objfile.o another_object.o ... -o executable-fileexecutable-file という名前の実行ファイルが、指定したオブジェクトファイルとライブラリーをベースに作成されます。追加のライブラリーをリンクするには、オブジェクトファイルのリストの後に必要なオプションを追加します。
詳細は、GCC でのライブラリーの使用 を参照してください。
注記C++ ソースコードの場合は、標準 C++ ライブラリーの依存関係を処理しやすくするために、
gccコマンドをg++に置き換えます。
2.2.7. 例: GCC で C プログラムの構築 (1 つの手順でコンパイルとリンク) リンクのコピーリンクがクリップボードにコピーされました!
以下の例では、簡単な C のサンプルプログラムを構築する手順を説明します。
この例では、コードをコンパイルおよびリンクする方法を 1 つの手順で行います。
手順
ディレクトリー
hello-cを作成します。$ mkdir hello-c作成されたディレクトリーに変更します。
$ cd hello-c以下の内容を含む
hello.cファイルを作成します。#include <stdio.h> int main() { printf("Hello, World!\n"); return 0; }GCC でコードをコンパイルし、リンクします。
$ gcc hello.c -o helloworldこれにより、コードがコンパイルされ、オブジェクトファイル
hello.oが作成され、オブジェクトファイルから実行ファイルhelloworldがリンクされます。作成された実行可能ファイルを実行します。
$ ./helloworldHello, World!
2.2.8. 例: GCC を使用した C プログラムの構築 (2 つの手順でコンパイルとリンク) リンクのコピーリンクがクリップボードにコピーされました!
以下の例では、簡単な C のサンプルプログラムを構築する手順を説明します。
この例では、コードのコンパイルとリンクは、2 つの別個のステップです。
手順
ディレクトリー
hello-cを作成します。$ mkdir hello-c作成されたディレクトリーに変更します。
$ cd hello-c以下の内容を含む
hello.cファイルを作成します。#include <stdio.h> int main() { printf("Hello, World!\n"); return 0; }GCC でコードをコンパイルします。
$ gcc -c hello.cオブジェクトファイル
hello.oが作成されます。オブジェクトファイルから実行可能ファイル
helloworldをリンクします。$ gcc hello.o -o helloworld作成された実行可能ファイルを実行します。
$ ./helloworld Hello, World!オプション: 親ディレクトリーに戻ります。
$ cd ..オプション:
hello-cディレクトリーを削除します。$ rm -r hello-c
2.2.9. 例: GCC で C++ プログラムの構築 (1 つの手順でコンパイルとリンク) リンクのコピーリンクがクリップボードにコピーされました!
以下の例では、最小限の C++ プログラムのサンプルを構築する手順を説明します。
この例では、コードをコンパイルおよびリンクする方法を 1 つの手順で行います。
手順
hello-cppディレクトリーを作成します。$ mkdir hello-cpp作成されたディレクトリーに変更します。
$ cd hello-cpp以下の内容を含む
hello.cppファイルを作成します。#include <iostream> int main() { std::cout << "Hello, World!\n"; return 0; }g++でコードをコンパイルし、リンクします。$ g++ hello.cpp -o helloworldこれにより、コードがコンパイルされ、オブジェクトファイル
hello.oが作成され、オブジェクトファイルから実行ファイルhelloworldがリンクされます。作成された実行可能ファイルを実行します。
$ ./helloworldHello, World!オプション: 親ディレクトリーに戻ります。
$ cd ..オプション:
hello-cppディレクトリーを削除します。$ rm -r hello-cpp
2.2.10. 例: GCC を使用した C++ プログラムの構築 (2 つの手順でコンパイルとリンク) リンクのコピーリンクがクリップボードにコピーされました!
以下の例では、最小限の C++ プログラムのサンプルを構築する手順を説明します。
この例では、コードのコンパイルとリンクは、2 つの別個のステップです。
手順
hello-cppディレクトリーを作成します。$ mkdir hello-cpp作成されたディレクトリーに変更します。
$ cd hello-cpp以下の内容を含む
hello.cppファイルを作成します。#include <iostream> int main() { std::cout << "Hello, World!\n"; return 0; }g++でコードをコンパイルします。$ g++ -c hello.cppオブジェクトファイル
hello.oが作成されます。オブジェクトファイルから実行可能ファイル
helloworldをリンクします。$ g++ hello.o -o helloworld作成された実行可能ファイルを実行します。
$ ./helloworldHello, World!オプション: 親ディレクトリーに戻ります。
$ cd ..オプション:
hello-cppディレクトリーを削除します。$ rm -r hello-cpp