本稿について
Linux ディストリビューションで C++17(C++1z) に対応し始めた GCC 6.1 を野良ビルドしてインストールするための手順です.
「std::invoke 使わせろ」とか「もういちいち -std=gnu++14 するの面倒なんだけど」とか,新しいコンパイラを使いたいんだけど root のパスワード知らないし...という人もどうぞ.
インストール先ディレクトリ
今回ビルドするファイル全てを /opt/gcc/6.1 にまとめて入れることとします.
よって,ビルド後のライブラリ一式は /opt/gcc/6.1/lib に,GCC の実行ファイルは /opt/gcc/6.1/bin に入ります.
root になれない人は適当なディレクトリで構いませんが,ldconfig が使えないので環境変数 LD_LIBRARY_PATH
などで lib
や lib64
ディレクトリを指定する必要があります.~/.zshrc
などに書いておきましょう.(具体的な設定は後述)
準備するもの
Prerequisites for GCC を見てもらえれば良いのですが,一般的な Linux のシステムでは大半がすでに入っています.
追加で必要なモノは大体以下のものでしょう.
- C++98 が使えるビルドチェイン
- GNU Multiple Precision Library(GMP) 4.3.2+
- MPFR Library 2.4.2+
- MPC Library 0.8.1+
- isl Library 0.14+(0.15+ が良い)
必要なアーカイブ
- GCC
- https://gcc.gnu.org/
- 今回使用するのは GCC 6.1.0
- GMP
- https://gmplib.org/
- 今回使用するのは GMP 6.1.1
- MPFR
- http://www.mpfr.org/
- 今回使用するのは MPFR 3.1.4
- MPC
- http://www.multiprecision.org/
- 今回使用するのは MPC 1.0.3
- isl
- http://isl.gforge.inria.fr/
- 今回使用するのは isl 0.17
インストールの流れ
- ldconfig の設定
- ライブラリのビルド&インストール
- GCC のビルド&インストール
今回は 16 個の論理プロセッサを積んだマシンを使っているので -j16
していますが,ここは環境に合わせてください.
ldconfig の設定
各種ライブラリをインストールするにあたり,ldconfig から共有ライブラリを見つけてもらえるようにする必要があります.
/etc/ld.so.conf.d/ 内にディレクトリエントリを作り,これからインストールするライブラリ一式を入れるディレクトリが ldconfig から見えるようにしましょう.
root になれない方は ldconfig の設定ができないので,本手順の代わりにこれから configure で指定する --prefix
に指定するディレクトリ内の lib
と lib64
ディレクトリを環境変数 LD_LIBRARY_PATH
に設定してください.
$ sudo vi /etc/ld.so.conf.d/gcc61.conf
/opt/gcc/6.1/lib
/opt/gcc/6.1/lib64
GCC61_HOME=/path/to/prefix
export LD_LIBRARY_PATH=${GCC61_HOME}/lib:${GCC61_HOME}/lib64
まだ ldconfig しなくても良いです.
各種ライブラリのビルドとインストール
依存関係があるので順番を守りましょう.
また,各ライブラリのインストール後には ldconfig
を実行しましょう.
root 持っていない方は --prefix
に自分が書き込めるディレクトリを指定してください.この場合はもちろん sudo
は不要です.
GMP
$ tar --lzip -xf gmp-6.1.1.tar.lz
$ cd gmp-6.1.1
$ ./configure --prefix=/opt/gcc/6.1
$ make -j16
$ sudo make install
$ sudo ldconfig
$ make clean
MPFR
$ tar Jxf mpfr-3.1.4.tar.xz
$ cd mpfr-3.1.4
$ ./configure --prefix=/opt/gcc/6.1 --with-gmp=/opt/gcc/6.1
$ make -j16
$ sudo make install
$ sudo ldconfig
$ make clean
MPC
$ tar zxf mpc-1.0.3.tar.gz
$ cd mpc-1.0.3
$ ./configure --prefix=/opt/gcc/6.1 --with-gmp=/opt/gcc/6.1 --with-mpfr=/opt/gcc/6.1
$ make -j16
$ sudo make install
$ sudo ldconfig
$ make clean
isl
$ tar Jxf isl-0.17.tar.xz
$ cd isl-0.17
$ ./configure --prefix=/opt/gcc/6.1 --with-gmp-prefix=/opt/gcc/6.1
$ make -j16
$ sudo make install
$ sudo ldconfig
$ make clean
isl のインストール後に ldconfig で下記のようなメッセージが出ますが,無視して良いです.
/sbin/ldconfig.real: /opt/gcc/6.1/lib/libisl.so.15.2.0-gdb.py is not an ELF file - it has the wrong magic bytes at the start.
GCC のビルドとインストール
C++17 を使うためには C++ があれば良いのですが,僕は C と Fortran,ついでに LTO サポートも欲しいので --enable-languages
でこれらを指定します.
$ tar jxf gcc-6.1.0.tar.bz2
$ cd gcc-6.1.0
$ ./configure --prefix=/opt/gcc/6.1 --with-gmp=/opt/gcc/6.1 --with-mpc=/opt/gcc/6.1 --with-mpfr=/opt/gcc/6.1 --with-isl=/opt/gcc/6.1 --disable-multilib --enable-languages=c,c++,fortran,lto
$ make -j16
$ sudo make install
$ sudo ldconfig
$ make clean
ここでも ldconfig 時に下記のようなメッセージが出ますが,無視して良いです.
/sbin/ldconfig.real: /opt/gcc/6.1/lib64/libstdc++.so.6.0.22-gdb.py is not an ELF file - it has the wrong magic bytes at the start.
【参考】GCC のビルドって時間がかかるんだけど...
ビルド時間を短縮するとかいう理由のためだけに --disable-bootstrap
を付けることを勧める記事をよく見ますが,メジャーバージョン(4.x → 4.y など)が上がるときは bootstrap ビルドをしておいた方が安全です.ABI の変更など致命的な問題が影響することがあります.
マイナバージョンを上げるとき(4.6.x → 4.6.y など)はまぁ bootstrap による確認は不要でしょう.
さぁできた
サンプルコードを書いて,std::invoke
できるか確認してみましょう.
(std::invoke
を叩きたいだけなので,色々手抜きしています)
#include <iostream>
#include <functional>
class Hoge
{
private:
int base;
public:
Hoge(int x)
{
this->base = x;
}
int count_up()
{
return ++this->base;
}
void change_base(int x)
{
this->base = x;
}
};
int count_up()
{
int base = 100;
return ++base;
}
int main(int argc, char **argv)
{
Hoge h(0);
std::cout << h.count_up() << std::endl;
std::cout << std::invoke(&count_up) << std::endl;
Hoge h1(100);
std::cout << std::invoke(&Hoge::count_up, h1) << std::endl;
Hoge h2(200);
std::cout << std::invoke(&Hoge::count_up, h2) << std::endl;
auto &h3 = h1;
h3.change_base(300);
std::cout << std::invoke(&Hoge::count_up, h1) << std::endl;
std::cout << std::invoke(&Hoge::count_up, h3) << std::endl;
auto h4 = h1;
h4.change_base(400);
std::cout << std::invoke(&Hoge::count_up, h1) << std::endl;
std::cout << std::invoke(&Hoge::count_up, h4) << std::endl;
return 0;
}
$ /opt/gcc/6.1/bin/g++ sample.cpp --std=gnu++17
$ ./a.out
1
101
101
201
301
302
303
401
まとめ
新しいコンパイラや実行環境は気軽に試すことができるので,どんどん使って筋トレしましょう.