第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 だけ、ステップ 1 と 2 の両方というように、GCC を実行することができます。これは、入力タイプや要求する出力タイプにより決定されます。

大規模なプロジェクトには、アクションごとに個別に GCC を実行するビルドシステムが必要なため、GCC が両方同時に実行できる場合でも 2 つの異なるアクションとしてコンパイルとリンクを実行するように検討する方が有用です。

関連資料

15.2. ソースファイルのオブジェクトコードへのコンパイル

オブジェクトコードファイルを、実行可能ファイルから直接作成するのではなく、ソースファイルから作成するには、GCC で、オブジェクトコードファイルのみを出力として作成するように必要があります。このアクションは、大規模なプロジェクトのビルドプロセスの基本操作となります。

前提条件

手順

  1. ソースコードファイルが含まれるディレクトリーに移動します。
  2. -c オプションを指定して、gcc を実行します。

    $ gcc -c source.c another_source.c

    オブジェクトファイルは、オリジナルのソースコードファイルを反映したファイル名を使用して作成されます。source.csource.o になります。

    注記

    C++ ソースコードの場合は、標準 C++ ライブラリーの依存関係を処理しやすくするために、gcc コマンドを g++ に置き換えます。

関連資料

15.3. GCC を使用した C および C++ アプリケーションのデバッグの有効化

デバッグ情報のサイズが大きい場合、その情報はデフォルトで実行可能ファイルに含まれません。GCC を使用した C および C++ のアプリケーションのデバッグを有効にするには、コンパイラーに対して、デバッグ情報を作成するように、明示的に指示する必要があります。

GCC を使用したデバッグ情報の作成の有効化

コードのコンパイルおよびリンク時に GCC でデバッグ情報の作成を有効にするには、-g オプションを使用します。

$ gcc ... -g ...
  • コンパイラーとリンカーで最適化を行うと、実行可能なコードを、元のソースコードと関連付けることが難しくなります。変数の最適化、ループのアンロール、周りの操作へのマージなどが行われる可能性があります。これにより、デバッグに負の影響が及ぶ可能性があります。デバッグの体験を向上するには、-Og オプションを指定して、最適化を設定することを考慮してください。ただし、最適化レベルを変更すると、実行可能なコードが変更され、バグを取り除くための実際の動作が変更される可能性があります。
  • -fcompare-debug GCC オプションでは、GCC でコンパイルしたコードを、デバッグ情報を使用して (または、デバッグ情報を使用せずに) テストします。このテストでは、出力されたバイナリーファイルの 2 つが同一であれば合格します。このテストを行うことで、実行可能なコードがデバッグオプションによる影響は受けないようにするだけでなく、デバッグコードにバグが含まれないようにします。-fcompare-debug オプションを使用するとコンパイルの時間が大幅に伸びることに留意してください。このオプションに関する詳細は、GCC の man ページを参照してください。

関連資料

15.4. GCC でのコードの最適化

1 つのプログラムは、複数の機械語命令シーケンスに変換できます。コンパイル時にコード分析用のリソースがより多く割り当てられると、最適な結果が得られます。

GCC でのコードの最適化

GCC では、-Olevel オプションを使用して最適化レベルを設定できます。このオプションでは、level の部分に値のセットを指定できます。

レベル詳細

0

コンピレーション速度の最適化: コードの最適化なし (デフォルト)

1, 2, 3

コード実行速度を高めるための最適化の作業量増加

s

作成されるファイルサイズの最適化

fast

レベル 3 以上は、厳密な標準への準拠を無視して追加の最適化を可能にします

g

デバッグ作業の最適化

リリースビルドの場合の最適化オプションとして、-O2 を推奨します。

開発中は、場合によってはプログラムやライブラリーのデバッグに -Og オプションを使用する方が便利です。バグによっては、特定の最適化レベルでのみ出現するので、リリースの最適化レベルでプログラムまたはライブラリーをテストするようにしてください。

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 ...

関連資料

15.6. 実行可能ファイルを作成するためのコードのリンク

C または C++ のアプリケーション構築の最後の手順は、リンクです。リンクにより、オブジェクトファイルやライブラリーがすべて実行可能ファイルに統合されます。

前提条件

手順

  1. オブジェクトコードファイルを含むディレクトリーに移動します。
  2. gcc を実行します。

    $ gcc ... objectfile.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 で提供される、GCC コンパイラーおよびリンカーのバージョンが複数含まれます。これらのバージョン間の C++ ABI の互換性は以下のとおりです。

  • GCC 4.8 がベースになり、Red Hat Enterprise Linux 7 の一部として直接提供されている システムコンパイラー は、C++98 標準仕様 (C++03 としても知られています)、およびそのバリアント (GNU 拡張あり) へのコンパイルおよびリンクのみをサポートします。
  • -std=c++98 または -std=gnu++98 オプションで明示的に構築された C++98 準拠のバイナリーまたはライブラリーは、使用するコンパイラーのバージョンにかかわらず、自由に組み合わせることができます。
  • C++11 および C++14 言語のバージョンの使用および併用は、Red Hat Developer Toolset のコンパイラーを使用しており、それぞれのフラグを使用してコンパイルされたすべての C++ オブジェクトが同じメジャーバージョンの GCC を使用して構築されている場合にのみサポートされます。
  • Red Hat Developer Toolset および Red Hat Enterprise Linux ツールチェーンで構築された C++ ファイルをリンクする場合には、Red Hat Developer Toolset バージョンのコンパイラーとリンカーが推奨されます。
  • Red Hat Enterprise Linux 6 および 7、および Red Hat Developer Toolset (バージョン 4.1 まで) のコンパイラーにおけるデフォルト設定は -std=gnu++98 です。つまり、C++98 と GNU 拡張です。
  • Red Hat Developer Toolset 6、6.1、7、7.1、8.0、8.1、9.0、9.1 および 10 のコンパイラーのデフォルト設定は -std=gnu++14 です。つまり、C++14 と GNU 拡張です。

関連資料

15.8. 例: GCC での C プログラムの構築

以下の例では、最小限の C プログラムのサンプルを構築する手順を説明します。

前提条件

  • GCC の使用方法を理解していること

手順

  1. hello-c ディレクトリーを作成して、その場所に移動します。

    $ mkdir hello-c
    $ cd hello-c
  2. 以下の内容で hello.c ファイルを作成します。

    #include <stdio.h>
    
    int main() {
      printf("Hello, World!\n");
      return 0;
    }
  3. GCC でコードをコンパイルします。

    $ gcc -c hello.c

    オブジェクトファイル hello.o が作成されます。

  4. オブジェクトファイル helloworld から作成した実行可能ファイルをリンクします。

    $ gcc hello.o -o helloworld
  5. 作成された実行可能ファイルを実行します。

    $ ./helloworld
    Hello, World!

関連資料

15.9. 例: GCC での C++ プログラムの構築

以下の例では、最小限の C++ プログラムのサンプルを構築する手順を説明します。

前提条件

  • GCC の使用方法を理解していること
  • gccg++ の相違点を理解していること

手順

  1. hello-cpp ディレクトリーを作成して、その場所に移動します。

    $ mkdir hello-cpp
    $ cd hello-cpp
  2. 以下の内容で hello.cpp ファイルを作成します。

    #include <iostream>
    
    int main() {
      std::cout << "Hello, World!\n";
      return 0;
    }
  3. g++ でコードをコンパイルします。

    $ g++ -c hello.cpp

    オブジェクトファイル hello.o が作成されます。

  4. オブジェクトファイル helloworld から作成した実行可能ファイルをリンクします。

    $ g++ hello.o -o helloworld
  5. 作成された実行可能ファイルを実行します。

    $ ./helloworld
    Hello, World!

このページには機械翻訳が使用されている場合があります (詳細はこちら)。