8.28. GCC-13.2.0

GCC パッケージは C コンパイラーや C++ コンパイラーなどの GNU コンパイラーコレクションを提供します。

概算ビルド時間: 42 SBU (テスト込み)
必要ディスク容量: 5.5 GB

8.28.1. GCC のインストール

x86_64 上でビルドしている場合は、64ビットライブラリのデフォルトディレクトリ名を "lib"にします。

case $(uname -m) in
  x86_64)
    sed -e '/m64=/s/lib64/lib/' \
        -i.orig gcc/config/i386/t-linux64
  ;;
esac

GCC のドキュメントによると GCC のビルドにあたっては、専用のビルドディレクトリを作成することが推奨されています。

mkdir -v build
cd       build

GCC をコンパイルするための準備をします。

../configure --prefix=/usr            \
             LD=ld                    \
             --enable-languages=c,c++ \
             --enable-default-pie     \
             --enable-default-ssp     \
             --disable-multilib       \
             --disable-bootstrap      \
             --disable-fixincludes    \
             --with-system-zlib

GCC では 7 つのコンピューター言語をサポートしていますが、それらのほとんどが必要としている依存パッケージは、まだこの時点でインストールしていません。 GCC がサポートする他のコンピューター言語の構築方法については BLFS ブック の説明を参照してください。

configure パラメーターの意味

LD=ld

本パラメーターは、本章の初期段階でビルドした Binutils の ld プログラムを使うことを configure スクリプトに指示します。 これを指定しなかった場合は、クロスビルド版のものが用いられることになります。

--disable-fixincludes

デフォルトにおいて、GCC のインストール中に GCC が利用するシステムヘッダーが固定される場合があります。 これは最近の Linux システムにおいては不要なことです。 また GCC のインストール後に何かのパッケージをインストールすることを考えると、潜在的な危険を生み出すことになります。 本スイッチは GCC がヘッダーファイルを 固定 (fix) しないようにします。

--with-system-zlib

このオプションはシステムに既にインストールされている Zlib ライブラリをリンクすることを指示するものであり、内部にて作成されるライブラリを用いないようにします。

[注記]

注記

PIE (position independent executable; 位置独立実行形式) とは、メモリ上のどこであっても、実行プログラムをロードできるようにします。 PIE がない場合には ASLR (Address Space Layout Randomization; アドレス空間配置のランダム化) という技術が適用されますが、適用先は共有ライブラリのみであって実行ファイルには適用されません。 共有ライブラリに加えて実行ファイルに対しても、PIE と ASLR を有効にすれば、実行ファイル内にある機密コードやデータが、固定的なアドレスに存在することを前提とした攻撃を軽減できます。

SSP (Stack Smashing Protection) とは、パラメータースタックが破壊されないようにする技術です。 スタック破壊が起きると、たとえばサブルーチンから返されるアドレスが変化してしまいます。 そうなった場合には、危険なコード(プログラムや共有ライブラリに元からあるものや、攻撃者が何らかの方法によって挿入したもの)に制御が移ってしまうことにもなります。

パッケージをコンパイルします。

make
[重要]

重要

本節における GCC のテストスイートは極めて重要なものです。 ただし相当な時間を要します。 初めてビルドを行う方には、必ず実施することをお勧めします。 テスト実行に要する時間は、make -k check コマンドに -jx をつけることで、かなり削減できます。 ここに示す x には、システムの CPU コア数を指定するものです。

GCC テストスイートの中で、デフォルトのスタックを使い果たすものがあります。 そこでテスト実施にあたり、スタックサイズを増やします。

ulimit -s 32768

一般ユーザーにてテストを行います。 ただしエラーがあっても停止しないようにします。

chown -R tester .
su tester -c "PATH=$PATH make -k check"

テスト結果を確認するために以下を実行します。

../contrib/test_summary

テスト結果の概略のみ確認したい場合は、出力結果をパイプ出力して grep -A7 Summ を実行してください。

テスト結果については https://www.linuxfromscratch.org/lfs/build-logs/12.1/https://gcc.gnu.org/ml/gcc-testresults/ にある情報と比較することができます。

(185,000 以上におよぶテストの中から) gcc テストの 8 つ、すなわち pr56837.c、それに analyzer ディレクトリにある 7 つのテストが失敗します。 (15,000 以上の ) libstdc++ テスト copy.cc が 1 つだけ失敗します。 g++ においては (およそ 250,000 のテストのうち) 21 個のテスト、14 個のAddressSanitizer*テスト、7 個の interception-malloc-test-1.C テストが失敗します。 さらに vect ディレクトリ内にあるテストが、AVX に対するハードウェアサポートがないために、いくつか失敗します。

テスト失敗は回避することができません。 GCC の開発者はこの問題を認識していますが、まだ解決していない状況です。 上記の URL に示されている結果と大きく異なっていなかったら、問題はありませんので先に進んでください。

パッケージをインストールします。

make install

GCC のビルドディレクトリの所有者は tester であるため、ヘッダーがインストールされるディレクトリ(とその内容)に対する所有権が不適切です。 そこでその所有権を root ユーザーとグループに変更します。

chown -v -R root:root \
    /usr/lib/gcc/$(gcc -dumpmachine)/13.2.0/include{,-fixed}

FHS の求めるところに応じてシンボリックリンクを作成します。 これは慣例によるものです

ln -svr /usr/bin/cpp /usr/lib

各種パッケージは C コンパイラーとして cc を呼び出しているものが数多くあります。 GCC 2回め においては、シンボリックリンクとして cc をすでに生成しています。 同様にしてその man ページについてもシンボリックリンクとして生成することにします。

ln -sv gcc.1 /usr/share/man/man1/cc.1

リンク時の最適化 (Link Time Optimization; LTO) によりプログラム構築できるように、シンボリックリンクを作ります。

ln -sfv ../../libexec/gcc/$(gcc -dumpmachine)/13.2.0/liblto_plugin.so \
        /usr/lib/bfd-plugins/

最終的なツールチェーンが出来上がりました。 ここで再びコンパイルとリンクが正しく動作することを確認することが必要です。 そこで健全性テストをここで実施します。

echo 'int main(){}' > dummy.c
cc dummy.c -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'

問題なく動作するはずで、最後のコマンドから出力される結果は以下のようになるはずです。 (ダイナミックリンカーの名前はプラットフォームによって違っているかもしれません。)

[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

ここで起動ファイルが正しく用いられていることを確認します。

grep -E -o '/usr/lib.*/S?crt[1in].*succeeded' dummy.log

上のコマンドの出力は以下のようになるはずです。

/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.0/../../../../lib/Scrt1.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.0/../../../../lib/crti.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.0/../../../../lib/crtn.o succeeded

作業しているマシンアーキテクチャーによっては、上の結果が微妙に異なるかもしれません。 その違いは、たいていは /usr/lib/gcc の次のディレクトリ名にあります。 注意すべき重要な点は gcccrt*.o という 3 つのファイルを /usr/lib 配下から探し出しているということです。

コンパイラーが正しいヘッダーファイルを読み取っているかどうかを検査します。

grep -B4 '^ /usr/include' dummy.log

上のコマンドは以下の出力を返します。

#include <...> search starts here:
 /usr/lib/gcc/x86_64-pc-linux-gnu/13.2.0/include
 /usr/local/include
 /usr/lib/gcc/x86_64-pc-linux-gnu/13.2.0/include-fixed
 /usr/include

もう一度触れておきますが、プラットフォームの三つの組 (target triplet)の次にくるディレクトリ名は CPU アーキテクチャーにより異なる点に注意してください。

次に、新たなリンカーが正しいパスを検索して用いられているかどうかを検査します。

grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'

'-linux-gnu' を含んだパスは無視すれば、最後のコマンドの出力は以下となるはずです。

SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64")
SEARCH_DIR("/usr/local/lib64")
SEARCH_DIR("/lib64")
SEARCH_DIR("/usr/lib64")
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");

32ビットシステムではディレクトリが多少異なります。 以下は i686 マシンでの出力例です。

SEARCH_DIR("/usr/i686-pc-linux-gnu/lib32")
SEARCH_DIR("/usr/local/lib32")
SEARCH_DIR("/lib32")
SEARCH_DIR("/usr/lib32")
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");

次に libc が正しく用いられていることを確認します。

grep "/lib.*/libc.so.6 " dummy.log

最後のコマンドの出力は以下のようになるはずです。

attempt to open /usr/lib/libc.so.6 succeeded

GCC が正しくダイナミックリンカーを用いているかを確認します。

grep found dummy.log

上のコマンドの出力は以下のようになるはずです。 (ダイナミックリンカーの名前はプラットフォームによって違っているかもしれません。)

found ld-linux-x86-64.so.2 at /usr/lib/ld-linux-x86-64.so.2

出力結果が上と異なっていたり、出力が全く得られなかったりした場合は、何かが根本的に間違っているということです。 どこに問題があるのか調査、再試行を行って解消してください。 問題を残したままこの先には進まないでください。

すべてが正しく動作したら、テストに用いたファイルを削除します。

rm -v dummy.c a.out dummy.log

最後に誤ったディレクトリにあるファイルを移動します。

mkdir -pv /usr/share/gdb/auto-load/usr/lib
mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib

8.28.2. GCC の構成

インストールプログラム: c++, cc (gcc へのリンク), cpp, g++, gcc, gcc-ar, gcc-nm, gcc-ranlib, gcov, gcov-dump, gcov-tool, lto-dump
インストールライブラリ: libasan.{a,so}, libatomic.{a,so}, libcc1.so, libgcc.a, libgcc_eh.a, libgcc_s.so, libgcov.a, libgomp.{a,so}, libhwasan.{a,so}, libitm.{a,so}, liblsan.{a,so}, liblto_plugin.so, libquadmath.{a,so}, libssp.{a,so}, libssp_nonshared.a, libstdc++.{a,so}, libstdc++exp.a, libstdc++fs.a, libsupc++.a, libtsan.{a,so}, libubsan.{a,so}
インストールディレクトリ: /usr/include/c++, /usr/lib/gcc, /usr/libexec/gcc, /usr/share/gcc-13.2.0

概略説明

c++

C++ コンパイラー

cc

C コンパイラー

cpp

C プリプロセッサー。 コンパイラーがこれを利用して、ソース内に記述された #include、#define や同じようなディレクティブを展開します。

g++

C++ コンパイラー

gcc

C コンパイラー

gcc-ar

ar に関連するラッパーであり、コマンドラインへのプラグインを追加します。 このプログラムは「リンク時の最適化 (link time optimization)」機能を付与する場合にのみ利用されます。 デフォルトのビルドオプションでは有効にはなりません。

gcc-nm

nm に関連するラッパーであり、コマンドラインへのプラグインを追加します。 このプログラムは「リンク時の最適化 (link time optimization)」機能を付与する場合にのみ利用されます。 デフォルトのビルドオプションでは有効にはなりません。

gcc-ranlib

ranlib に関連するラッパーであり、コマンドラインへのプラグインを追加します。 このプログラムは「リンク時の最適化 (link time optimization)」機能を付与する場合にのみ利用されます。 デフォルトのビルドオプションでは有効にはなりません。

gcov

カバレッジテストツール。 プログラムを解析して、最適化が最も効果的となるのはどこかを特定します。

gcov-dump

オフラインの gcda および gcno プロファイルダンプツール。

gcov-tool

オフラインの gcda プロファイル処理ツール。

lto-dump

LTO が有効にした GCC によって生成されるオブジェクトファイルをダンプするためのツール。

libasan

アドレスサニタイザー (Address Sanitizer) のランタイムライブラリ。

libatomic

GCC 不可分 (アトミック) ビルトインランタイムライブラリ。

libcc1

GDB が GCC を利用可能とするためのライブラリ。

libgcc

gcc のランタイムサポートを提供します。

libgcov

GCC のプロファイリングを有効にした場合にこのライブラリがリンクされます。

libgomp

C/C++ や Fortran においてマルチプラットフォームでの共有メモリ並行プログラミング (multi-platform shared-memory parallel programming) を行うための GNU による OpenMP API インプリメンテーションです。

libhwasan

ハードウェアをアシストする Address Sanitizer ランタイムライブラリ。

libitm

GNU のトランザクショナル(transactional)メモリーライブラリ。

liblsan

リークサニタイザー (Leak Sanitizer) のランタイムライブラリ。

liblto_plugin

GCC の LTO プラグインは、LTO を有効にした GCC から生成されたオブジェクトファイルを Binnutils が処理できるようにします。

libquadmath

GCC の4倍精度数値演算 (Quad Precision Math) ライブラリ API

libssp

GCC のスタック破壊を防止する (stack-smashing protection) 機能をサポートするルーチンを提供します。 Glibc から同じルーチンが提供されているため、通常は用いられません。

libstdc++

標準 C++ ライブラリ

libstdc++exp

試験的な C++ Contract ライブラリ。

libstdc++fs

ISO/IEC TS 18822:2015 ファイルシステムライブラリ。

libsupc++

C++ プログラミング言語のためのサポートルーチンを提供します。

libtsan

スレッドサニタイザー (Thread Sanitizer) のランタイムライブラリ。

libubsan

Undefined Behavior Sanitizer ランタイムライブラリ。