GCC のアップグレード
この文書では、GCC のアップグレード手順を案内しています。
GCC のダウングレードには望まない副作用があるかもしれないことに注意してください。よく報告される問題についてはトラブルシューティングの節を参照してください。
ショートバージョン
このセクションは、GCCのアップグレード(とそれらがいかに簡単か)への迅速なプライマーです。より詳しい説明は次のGCC アップグレードの詳説節にあります。
たいていのGCCのアップグレードは、コンパイラのバージョンを(ここでは5.4.0から6.4.0に)変更することと、libtoolを再ビルドするだけで済みます:
root #
emerge --ask --oneshot sys-devel/gcc
root #
gcc-config --list-profiles
[1] x86_64-pc-linux-gnu-5.4.0 * [2] x86_64-pc-linux-gnu-6.4.0
root #
gcc-config 2
root #
source /etc/profile
root #
emerge --ask --oneshot --usepkg=n sys-devel/libtool
gcc 4.x から gcc 5.x 以降にアップグレードする場合は、追加の説明があてはまります; 分離されている Upgrading from gcc-4.x to gcc-5.x のページを見てください。
現在のバージョン番号を確認してから、旧バージョンをアンインストールしましょう:
root #
gcc --version
root #
emerge --ask --depclean =sys-devel/gcc-5.4.0
それから、revdep-rebuildを実行してシステムの整合性を検証します:
root #
revdep-rebuild
新しいコンパイラを楽しんでください!
GCC アップグレードの詳説
GCC のアップグレードはいつも謎めかされてきました。というのも、「ほかには何もしなくていいよ」というものから、「システム全体の再ビルドを2度しなければならないよ」というものまで、言われることに幅があるからです。こうした疑念のおおよそは、今日ではめったに起こらない(そして起こったときにはそれが発表される) ABI の非互換にまつわる混乱からきています。しかしまずは、libtool にまつわることについて軽く指摘しておきます。
libtool
ではなぜ、 gcc のバージョンをアップグレードした後には libtool を再ビルドする必要があるのでしょうか? それは、libtool は、プラットフォーム特有のコードを一般化したインターフェイスに集約することで、アプリケーションソフトがプラットフォーム特有の側面を意識することなく共用ライブラリを利用可能にするものだからです。この機能を適切に実現するには、libtool のスクリプトは、様々な場所にある共用ライブラリを見つけ出して、その中にハードコーディングされた gcc のバージョン情報を得なければなりません。
ABI の変化
ABI、あるいはApplication Binary Interfaceは、コンパイラ、アセンブラ、リンカ、そして言語ランタイムサポート(情報源: GCC Binary Compatibility)を含む、プログラムのバイナリ表現を扱うすべてのツールによって使用される規則の集まりです。バイナリアプリケーションやライブラリに使用されているABIが変更されると、C++のコードを用いているすべてのライブラリをビルドしなおすまで、リンカのエラーやプログラムの誤動作が発生する危険性があります。
そう、C++です、ほとんどの非互換はC++ ABIの中で生じるためです。もしあなたがGCC 4.1やGCC 5.1へアップグレードした場合、おそらくABIの問題に直面することになるでしょう。これを防ぐには、GCC 3からGCC 4.1へのアップグレードの場合はlibstdc++.so.5に、GCC 4からGCC 5.1へのアップグレードの場合はlibstdc++.so.6に対してrevdep-rebuildコマンドを実行する必要があります。
root #
revdep-rebuild --library 'libstdc++.so.6' -- --exclude gcc
では、なぜこれはGCC 4.1/5.1までにおいてのみ必要とされるのでしょうか? それは、それらのバージョン以降、GCCがアプリケーションやライブラリの再ビルドの必要性をなくす前方互換のABIを採用しているからです。もちろん保証は無期限に与えられるものではありえませんが、非互換が再び生じたら、私たちはそれをここへ確実に文書化し、またニュース項目をリリースします。その場合、おそらくlibstdc++.soライブラリのバージョンは増加していることでしょう。
C++11 (および C++14) 特有の事象
GCC(より具体的には、libstdc++)は、ABIの安定性を保証するために労を惜しみませんが、この保証はlibstdc++の中のC++のすべての部分に及ぶわけではありません。公式には、3.4以降のバージョンにおいて、GCC/libstdc++はC++98/C++03 ABIの安定性のみを保証し、それ以上ではありません。このことはC++11に依存するパッケージに関しては重大です。GCCはC++11 ABIの安定性の保証をバージョン5.1以降でのみ提供しています。これは、gccのバージョン(マイナーバージョンであっても)の変更(4.7.3 -> 4.7.4など)はC++11のコードからビルドされたバイナリにABI破壊をもたらす、ということを意味しています。
さらなる情報や実例は、以下を見てください:
- bug #513386
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61758
- https://blogs.gentoo.org/blueness/2015/03/10/the-c11-abi-incompatibility-problem-in-gentoo/
- https://stackoverflow.com/questions/16190269/g-always-backward-compatible-with-older-static-libraries/16196475#16196475
どのパッケージで再ビルドが必要とされているか?
以下の表は、インストールされていれば再ビルドが必要なパッケージとその理由を表したものです。
パッケージ | 再ビルドが必要な理由 ... |
---|---|
sys-devel/libtool | libtoolアプリケーションは、GCCの内部ライブラリへのパスをハードコードしています。 |
sys-devel/llvm | 再ビルドしないと、gccの厳密なバージョンによって、LLVMを利用する他のebuild(例えば media-libs/mesa)でリンクエラーに遭遇することがあります。 |
sys-devel/clang | gcc の厳密なバージョンに依存しており、sys-devel/llvmの影響を受ける可能性があります。 |
root #
emerge --ask --oneshot --usepkg=n --verbose sys-devel/libtool sys-devel/llvm sys-devel/clang
いくつかのパッケージ群は同じコンパイラを用いてビルドする必要があります(たとえば、さまざまなqt-*パッケージ)。こうしたパッケージについては通常パッケージメンテナが同時にbumpを行っているため、常に同じバージョンのGCCでビルドされるようになっています。これらのパッケージからの「つまみ食い」的な再インストールはトラブルを引き起こすことがしばしばです。
すべてをリビルドする
「GCC の新たなバージョンを入れたときには、各パッケージのすべてを再ビルドせねばならない」と心に誓っている人もいます。もちろん、そうする意味はありません。なぜなら、ビルドやインストールに GCC を一切使わないアプリケーションソフトもたくさんあり、そうしたソフトウェアには影響がないからです。
そうはいっても、彼らが完全に間違っているかというと、そうでもありません: 新しいバージョンの GCC ではしばしば、プロセッサの命令セットのサポートが向上していることがあります。そうすると、より良い性能が得られるアプリケーションソフトもあるかもしれません。
そうした"穏健な"利点とは別に、場合によっては明確な原因がわからない問題を解決するためにすべてを1からリビルドすることが必要になることがあるかもしれません。
いくつかのソフトウェアの問題は本質的に診断が困難ですが、それでも単に1つまたは複数の適切なパッケージをリビルドすることで解決できることがあります。そのような問題がGCCのアップグレード後に起こり、前に説明したrevdep-rebuildを使ったアプローチ(と他の明らかに関係のあるパッケージのリビルド)の後にも続いている場合、システムの完全なリビルドが答えかもしれません。
これを実現する"最も安全な"(ただし最も時間がかかる)方法はemergeの--emptytree
(-e
)オプションをsystem セット、そしてworld セットのリビルドに使うことです:
root #
emerge --ask --emptytree --usepkg=n @system
root #
emerge --ask --emptytree --usepkg=n @world
ユーザーは、GCCのアップグレードによって引き起こされたかもしれないバグを報告する前に、このアプローチを試してみることが推奨されます。
(上のコマンドでは"system"セットのパッケージが2回リビルドされることに留意してください。これは、すべてのパッケージが絶対確実に同じ[おそらくは]"問題のない"環境でビルドされるようにするために必要なことです。これを実行した後に残った問題はすべて、報告されるべき"正真正銘のバグ"か、あるいはまずいシステム設定によるものです。)
トラブルシューティング
boost のリビルド
以下のエラーメッセージが出た場合、dev-libs/boostをリビルドする必要があります:
root #
emerge ...
checking for the Boost _____ library... no configure: error: cannot find the flags to link with Boost _____
以下のようにしてリビルドできます:
root #
emerge --ask --oneshot --usepkg=n --verbose dev-libs/boost
libstdc++.so.6: version `GLIBCXX_3.4.15' not found
アップデートの途中、以下のようなエラーに遭遇することがあります:
cmake_bootstrap_28021_test: /usr/lib/gcc/i486-pc-linux-gnu/4.1.2/libstdc++.so.6: version `GLIBCXX_3.4.11' not found
これは、依存しているライブラリをビルドしたものよりも古いバージョンのGCCでパッケージをビルドしようとしていることを表しています。C++ ABIは前方互換であると述べたことを思い出しましたか? 確かにそれは事実なのですが、そのことは、アプリケーションのビルドやライブラリのリンクにあたって、(そのライブラリをビルドしたものに比べて)より高い(または同じ)バージョンのGCCが使用できる、ということを保証するに過ぎません。
libstdc++に依存しているすべてのパッケージを再ビルドするには、上のrevdep-rebuildの説明を参照してください。