Red Hat Training

A Red Hat training course is available for RHEL 8

第2章 C または C++ アプリケーションの作成

2.1. GCC でのビルドコード

ソースコードを実行可能コードに変換する必要がある状況について説明します。

2.1.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. オブジェクトファイルおよびライブラリーはリンクされます (以前にコンパイルしたソールも含む)。

GCC を実行して、1 つのステップでコンパイルのみ、リンクのみ、またはコンパイルとリンクの両方を実行できます。これは、入力タイプや必要とされる出力タイプにより決定します。

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

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

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

前提条件

手順

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

    $ gcc -c source.c another_source.c

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

    注記

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

2.1.3. GCC で C および C++ のアプリケーションのデバッグの有効化

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

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

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

関連情報

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

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

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

レベル説明

0

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

123

最適化して、コード実行速度を向上させます (数値が大きいほど、速度は高くなります)。

s

ファイルサイズを最適化します。

fast

レベルを 3 にして、fast にすると、厳密な標準準拠を無視して追加の最適化を可能にします

g

デバッグ作業の最適化

リリースビルドの最適化オプションは -O2 です。

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

GCC では、個別の最適化を有効にするオプションが多数含まれています。詳細情報は、以下の関連資料を参照してください。

関連情報

2.1.5. GCC でコードを強化するオプション

コンパイラーで、ソースコードをオブジェクトコードに変換する場合には、さまざまなチェックを追加して、一般的に悪用される状況などを回避し、セキュリティーを強化できます。適切なコンパイラーオプションセットを選択すると、ソースコードを変更せずに、よりセキュアなプログラムやライブラリーを作成できます。

リリースバージョンのオプション

Red Hat Enterprise Linux を使用する開発者には、以下のオプションリストが推奨される最小限のオプションとなります。

$ gcc ... -O2 -g -Wall -Wl,-z,now,-z,relro -fstack-protector-strong -fstack-clash-protection -D_FORTIFY_SOURCE=2 ...
  • プログラムには、-fPIE および -pie の位置独立実行形式オプションを追加します。
  • 動的にリンクされたライブラリーには、必須の -fPIC (位置独立コード) オプションを使用すると間接的にセキュリティーが強化されます。

開発オプション

開発時にセキュリティーの欠陥を検出する場合は、以下のオプションを使用します。このオプションは、リリースバージョンのオプションと合わせて使用してください。

$ gcc ... -Walloc-zero -Walloca-larger-than -Wextra -Wformat-security -Wvla-larger-than ...

関連情報

2.1.6. 実行ファイルを作成するコードのリンク

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

前提条件

手順

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

    $ gcc ... objfile.o another_object.o ... -o executable-file

    executable-file という名前の実行ファイルが、指定したオブジェクトファイルとライブラリーをベースに作成されます。

    追加のライブラリーをリンクするには、オブジェクトファイルのリストの前に、必要なオプションを追加します。詳細は、「GCC でのライブラリーの使用」 を参照してください。

    注記

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

2.1.7. 例: GCC で C プログラムの構築 (1 つの手順でコンパイルとリンク)

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

この例では、コードをコンパイルおよびリンクする方法を 1 つの手順で行います。

前提条件

  • 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 hello.c -o helloworld

    これにより、コードがコンパイルされ、オブジェクトファイル hello.o が作成され、オブジェクトファイルから実行ファイル helloworld がリンクされます。

  4. 作成された実行可能ファイルを実行します。

    $ ./helloworld
    Hello, World!

2.1.8. 例: GCC を使用した C プログラムの構築 (2 つの手順でコンパイルとリンク)

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

この例では、コードのコンパイルとリンクは、2 つの別個のステップです。

前提条件

  • 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!

2.1.9. 例: GCC で C++ プログラムの構築 (1 つの手順でコンパイルとリンク)

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

この例では、コードをコンパイルおよびリンクする方法を 1 つの手順で行います。

前提条件

  • 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++ hello.cpp -o helloworld

    これにより、コードがコンパイルされ、オブジェクトファイル hello.o が作成され、オブジェクトファイルから実行ファイル helloworld がリンクされます。

  4. 作成された実行可能ファイルを実行します。

    $ ./helloworld
    Hello, World!

2.1.10. 例: GCC を使用した C++ プログラムの構築 (2 つの手順でコンパイルとリンク)

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

この例では、コードのコンパイルとリンクは、2 つの別個のステップです。

前提条件

  • 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!