第15章 GCC でのビルドコード
本章では、ソースコードを実行可能なコードに変換する必要のある状況を扱います。
15.1. コード形式間の関係
前提条件/事前作業
- コンパイルとリンクのコンセプトを理解していること
考えられるコード形式
C および C++ 言語を使用する場合は、コード形式が 3 つあります。
C または C++ 言語で記述された ソースコード。プレーンテキストファイルとして公開します。
これらのファイルは通常、
.c、.cc、.cpp、.h、.hpp、.i、.incなどの拡張子を使用します。サポートされる拡張子およびその解釈にかんする全一覧は、gcc の man ページを参照してください。$ man gcc
コンパイラー でソースコードをコンパイルして作成する オブジェクトコード。これは中間形式です。
オブジェクトコードファイルは、
.oの拡張子を使用します。リンカーでオブジェクトコードをリンクして作成する 実行可能なコード
Linux アプリケーションの実行可能なファイルは、ファイル名の拡張子を使用しません。共有オブジェクト (ライブラリー) の実行可能なファイルは、
.soのファイル名の拡張子を使用します。
静的にリンクするためのライブラリーのアーカイブファイルも存在します。これはオブジェクトコードの変形で、.a ファイル名の拡張子を使用します。
GCC でのコード形式の処理
ソースコードから実行可能なコードを生成するには、2 つの手順を実行してください。各手順では、異なるアプリケーションまたはツールが必要です。GCC は、コンパイラーおよびリンカーどちらにも、インテリジェントドライバーとして使用可能です。これにより、必要なアクションに gcc のコマンド 1 つだけで対応できます。GCC は自動的に必要なアクション (コンパイルおよびリンク) とそのシーケンスを選択します。
- ソースファイルは、オブジェクトファイルにコンパイルされます。
- オブジェクトファイルおよびライブラリーはリンクされます (以前にコンパイルしたソールも含む)。
ステップ 1 だけ、ステップ 2 だけ、ステップ 1 と 2 両方というように、GCC を実行することができます。これは、入力タイプや要求する出力タイプにより決定されます。
大規模なプロジェクトには、アクション毎に個別に GCC を実行するビルドシステムが必要なため、GCC が両方同時に実行できる場合でも 2 つの異なるアクションとしてコンパイルとリンクを実行するように検討するほうが良いでしょう。
その他のリソース
15.2. ソースファイルのオブジェクトコードへのコンパイル
実行可能ファイルから直接作成するのではなく、ソースファイルからオブジェクトコードファイルを作成するには、 GCC にオブジェクトコードファイルのみを出力として作成するように指示する必要があります。このアクションは、大規模なプロジェクトのビルドプロセスの基本操作となります。
前提条件/事前作業
- C または C++ のソースコードファイル
- GCC をシステムにインストールしておくこと
手順
- ソースコードファイルが含まれるディレクトリーに移動します。
-cオプションを指定してgccを実行します。$ gcc -c source.c another_source.cオブジェクトファイルは、オリジナルのソースコードファイルを反映したファイル名を使用して作成されます。
source.cはsource.oになります。注記C++ ソースコードの場合は、標準 C++ ライブラリーの依存関係を都合よく処理するために、
gccコマンドをg++に置き換えてください。
その他のリソース
15.3. GCC を使用した C および C++ アプリケーションのデバッグの有効化
デバッグの情報が大きい場合には、デフォルトでは実行可能ファイルは含まれません。GCC を使用した C および C++ アプリケーションのデバッグを有効化するには、コンパイラーに対して、ファイルを作成するように、明示的に指示する必要があります。
GCC を使用したデバッグ情報の作成の有効化
コードのコンパイルおよびリンク時には GCC でデバッグ情報の作成を有効化するには、-g オプションを使用します。
$ gcc ... -g ...
-
コンパイラーとリンカーで最適化を行うと、実行可能なコードを、元のソースコードと関連付けることが難しくなります。変数の最適化、ループのアンロール、周りの操作へのマージなどが行われる可能性があります。デバッグの体験を向上するには、
-Ogオプションを指定して、最適化を設定することを考慮してください。ただし、最適化レベルを変更すると、実行可能なコードが変更され、バグを取り除くための実際の動作が変更される可能性があります。 -
-fcompare-debugGCC オプションでは、GCC でコンパイルしたコードを、デバッグ情報を使用して (または、デバッグ情報を使用せずに) テストします。このテストでは、出力されたバイナリーファイル 2 つが同一であれば合格します。このテストを行うことで、実行可能なコードはデバッグオプションによる影響は受けないようにするだけでなく、デバッグコードにバグが含まれないようにします。-fcompare-debugオプションを使用するとコンピレーションの時間が大幅に伸びます。このオプションに関する詳細情報は、GCC の man ページを参照してください。
その他のリソース
- 「デバッグ情報を使用したデバッグの有効化」
- GNU コンパイラーコレクション (GCC) の使用: 「Options for Debugging Your Program」
- GDB でのデバッグ: 「Debugging Information in Separate Files」
GCC の man ページ:
$ man gcc
15.4. GCC でのコードの最適化
1 つのプログラムは、複数の機械語命令シーケンスに変換可能です。コンパイル時にコード分析用のリソースがより多く割り当てられると、より最適な結果が得られます。
GCC でのコードの最適化
GCC では、-Olevel オプションを使用して最適化レベルを設定できます。このオプションでは、level の部分に各種値を指定することができます。
| レベル | 説明 |
|---|---|
|
|
コンピレーション速度の最適化: コードの最適化なし (デフォルト) |
|
|
コード実行速度を高めるための最適化の作業量増加 |
|
|
作成されるファイルサイズの最適化 |
|
|
レベル 3 以上は、厳密な標準準拠を無視して追加の最適化を可能にします |
|
|
デバッグ作業の最適化 |
リリースビルドの場合の最適化オプションは、-O2 を推奨します。
開発中は、場合によってはプログラムやライブラリーのデバッグを行えるように -Og オプションのほうが便利です。バグによっては、特定の最適化レベルでのみ出現するので、リリースの最適化レベルでプログラムまたはライブラリーをテストするようにしてください。
GCC では、個別の最適化を有効にするオプションが多数含まれています。詳細情報は、以下の追加リソースを参照してください。
その他のリソース
- GNU コンパイラーコレクションの使用: 「3.10 Options That Control Optimization」
GCC の Linux man ページ:
$ man gcc
15.5. GCC でのコードのハード化
コンパイラーで、ソースコードをオブジェクトコードに変換する場合には、さまざまなチェックを追加して、一般的に悪用される状況などを回避し、セキュリティーを強化することができます。適切なコンパイラーオプションセットを選択して、ソースコードを変更せずに、よりセキュアなプログラムやライブラリーを制作することができます。
リリースバージョンのオプション
Red Hat Enterprise Linux を使用する開発者には、以下のオプション一覧が最小限必要なオプションとなります。
$ gcc ... -O2 -g -Wall -Wl,-z,now,-z,relro -fstack-protector-strong -D_FORTIFY_SOURCE=2 ...
-
プログラムには、
-fPIEおよび-pieの位置独立コードオプションを追加します。 -
動的にリンクされたライブラリーには、必須の
-fPIC(位置独立コード) オプションを使用すると間接的にセキュリティーが強化されます。
開発オプション
開発時にセキュリティーの欠陥を検出する場合には、以下のオプションを推奨します。これらのオプションは、リリースバージョンのオプションと合わせて使用してください。
$ gcc ... -Walloc-zero -Walloca-larger-than -Wextra -Wformat-security -Wvla-larger-than ...
その他のリソース
- 『Defensive Coding Guide』
- 『Memory Error Detection Using GCC』: Red Hat 開発者のブログ投稿
15.6. 実行可能なファイルを作成するためのコードのリンク
C または C++ アプリケーション構築の最後の手順は、リンクです。リンクをすることで、オブジェクトファイルやライブラリーをすべて実行可能なファイルに統合します。
前提条件/事前作業
- 1 つまたは複数のオブジェクトファイル
- GCC をシステムにインストールしておくこと
手順
- オブジェクトコードファイルを含むディレクトリーに移動します。
gccを実行します。$ gcc ... objfile.o another_object.o ... -o executable-file
executable-file という名前の実行可能なファイルが、指定したオブジェクトファイルとライブラリーをベースに作成されます。
追加のライブラリーををリンクするには、オブジェクトファイルの一覧の前に、必要なオプションを追加します。「16章GCC でのライブラリーの使用」を参照してください。
注記C++ ソースコードの場合は、標準 C++ ライブラリーの依存関係を都合よく処理するために、
gccコマンドをg++に置き換えてください。
その他のリソース
15.7. 各種 Red Hat 製品との C++ の互換性
Red Hat エコシステムには、Red Hat Enterprise Linux および Red Hat Developer Toolset の複数のバージョンが含まれます。これらのバージョン間の C++ ABI の互換性は以下のとおりです。
-
-std=C++98または-std=gnu++98オプションで明示的に構築された C++98 準拠のバイナリーまたはライブラリーは自由に組み合わせることができます。これは、実稼働のソフトウェア開発で推奨の設定です。 -
Red Hat Enterprise Linux 6 および 7、Red Hat Developer Toolset バージョン 4.1 までのデフォルト設定は、
-std=gnu++98です。Red Hat Developer Toolset 6、6.1 および 7 のデフォルトは、-std=gnu++14です。 - Red Hat Developer Toolset では、同じバージョンの GCC を使用して構築された適切なフラグで、C++ オブジェクトすべてがコンパイルされている場合のみ、C++11 および C++14 言語の使用、併用がサポートされます。
- Red Hat Developer Toolset および Red Hat Enterprise Linux で構築された C++ ファイルをリンクする場合には、Red Hat Developer Toolset バージョンの GCC とリンカーが推奨されます。
その他のリソース
- 「Application Compatibility GUIDE」
- 『Red Hat Developer Toolset User Guide』: 「C++ Compatibility」
15.8. 例: GCC での C プログラムの構築
以下の例では、最小限の C プログラムのサンプルを構築する手順を説明します。
前提条件/事前作業
- GCC の使用方法を理解していること
手順
hello-cディレクトリーを作成して、そのディレクトリーに移動します。$ mkdir hello-c $ cd hello-c
以下の内容を含む
hello.cファイルを作成します。#include <stdio.h> int main(int argc, char *argv[]) { printf("Hello, World!\n"); return 0; }GCC でコードをコンパイルします。
$ gcc -c hello.c
オブジェクトファイル
hello.oが作成されます。オブジェクトファイルから作成した、実行可能なファイル
helloworldをリンクします。$ gcc hello.o -o helloworld
作成された実行可能なファイルを実行します。
$ ./helloworld Hello, World!
その他のリソース
15.9. 例: GCC での C++ プログラムの構築
以下の例では、最小限の C++ プログラムのサンプルを構築する手順を説明します。
前提条件/事前作業
- GCC の使用方法を理解していること
-
gccとg++の相違点を理解していること
手順
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
作成された実行可能なファイルを実行します。
$ ./helloworld Hello, World!

Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.