Ubuntuでc++17のために最新版のg++, boost, cmakeを自然に使う

2019年12月23日 追記
この記事の内容を汎化して、間違いなく継続的アップデートが可能なアップデート方法を記事にし直しました。この内容を修正したものとなっているので、そちらをご覧ください
https://qiita.com/forno/items/11c4a0f8169d987f232b

# c++17を使いたい！

c++17もほとんど決まり、どんどん使い始めて良いかと思っている人は多いと思います。
しかし、最新のUbuntu LTSである16.04ではデフォルトでc++17に完全に対応した環境になりません。

自然とc++17が使える環境を目指して、最新版のソフトウェアを入手しましょう。

## 目標
- CmakeLists.txtではCheckCXXCompilerFlag Moduleによる`-std=c++1z`の検出か、`CXX_STANDARD` による17の指定でc++17を有効にする。
- CmakeLists.txtで`find_package(Boost)`と指定することで導入した(最新の)Boostを探し当てる。
- cmake コマンドを普通に実行して最新の機能を使う。
- コンパイラは環境変数CXX,CCあるいはcmake実行時に渡してもらう前提で、g++を最新版に置き換えはしない。
- 既存の環境を覆い隠すが、そのまま残すことでいつでも戻せる状態にしておく。(/usr/localを用いる)
- 継続的にアップデートするために、メジャーアップデートを追いかけられるppaかGit repositoryのみを使用する。
- システムインストールなのでソースコードのディレクトリ位置には依存しない。

## gcc 最新版を入手
最新のgccは単一のppaで追いかけることができる。
本当はtest版では無い方を用いたほうがstableだと思うが、c++17を利用するにはgcc 7以降が欲しい。
よってtest用ppaを使用する。ちなみに依存関係で自動的にc++17用標準ライブラリも手に入る。

```bash
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt update
sudo apt install -y g++-7
```

### gcc 環境設定
環境変数CXXとCCを定義して、g++-7をデフォルトで使ってもらいやすくしておきます。

```bash
echo "export CXX='g++-7'" >> ~/.bashrc
echo "export CC='gcc-7'" >> ~/.bashrc
```

ここまでできたら一度端末をすべて閉じて開きなおすと良いです。

### gcc インストール確認方法
`g++-7 --version` で何か表示される。失敗しているとコマンドが見つからないと言われます。

## boost リリース最新をインストール
Boostを継続して追いかけられるppaどころか、最新のBoostを提供するppaも見つからなかった。
仕方がないのでGit repositoryからコンパイルして用いる。
先に言っておくとダウンロードにもコンパイルにも相当時間がかかる。

```bash
git clone --recursive git@github.com:boostorg/boost.git
cd boost
./bootstrap.sh
./b2 toolset=gcc-7 --prefix=/usr/local -j5
sudo ./b2 install toolset=gcc-7 --prefix=/usr/local -j5
```

コンパイル時には`toolset=gcc-7`を指定して、最新のコンパイラで処理しましょう。
途中warningが大量に出ますが、std::auto_ptrやunused valueが騒いでいるだけです。
Boostはc++17へ移行中のものもあるので、大目に見ておきましょう。

j オプションの引数5は並列処理数です。CPUの論理コア数+1にして全く他の仕事をしなければ全力でコンパイルしてくれます。速度が段違いなので論理コア数をきちんと調べて指定すると良いです。

なおBoostに特別な環境設定はいりません。

### Note: reason of without develop branch
Boostをソースからコンパイルする手順を見ているとdevelopブランチをコンパイルさせて来ますが、Cmakeから見つけてもらうためにはmaster(default branch)をコンパイルする必要があります。

### Boost インストール確認方法
Cmakeを入れた後で確かめます。

## Cmake 最新版をインストール
Cmakeも追いかけるどころか最新のppaが見つかりませんでした。
さらにGit repositoryもgithubはミラーで、 `https://gitlab.kitware.com/cmake/cmake` が真の本体です。
せっかくなのでオリジナルを利用しましょう。

```bash
git clone https://gitlab.kitware.com/cmake/cmake.git
cd cmake
./bootstrap --prefix=/usr/local
make -j5
sudo make install
```

こちらではCXXとCCを判別するようなのでコンパイラの指定はいりません。
自動でc++17を用いてコンパイルが進むはずです。

### Cmake 環境設定

```bash
echo "export CMAKE_ROOT='/usr/local/share/cmake-3.9'" >> ~/.bashrc
```

9月2日現在はCmakeのGit repositoryのmasterのヴァージョンは3.9なのでこの指定ですが、
実際のディレクトリを調べるために`ls /usr/local/share`を実行してパスを調べてください。

### Cmake インストールチェック

```bash
cmake --version
```

まずは上のコマンドが正しく動作することを確認してください。
CMAKE_ROOTに関してエラーが出た場合はパスの指定が間違っている可能性があります。.bashrcとパスの指定を確認してください。

次に適当なディレクトリを作って、コンパイルを試します。
まずはディレクトリにCMakeLists.txtとmain.cppを作成します。

```
- CMakeLists.txt
- main.cpp
```

```cmake:CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(test)

find_package(Boost REQUIRED COMPONENTS system)
find_package(Threads REQUIRED)

include_directories(Boost::boost)

add_executable(main main.cpp)
target_link_libraries(main Boost::system Threads::Threads)

set(TARGETS main)

set_property(TARGET ${TARGETS} PROPERTY CXX_STANDARD 17)
set_property(TARGET ${TARGETS} PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET ${TARGETS} PROPERTY CXX_EXTENSION OFF)
```

```cpp:main.cpp
#include <iostream>
#include <string_view>

#include <boost/asio.hpp>

int main(int argc, char** argv)
{
  namespace asio = boost::asio;
  using asio::ip::tcp;

  asio::io_service io_service;
  tcp::socket socket(io_service);

  boost::system::error_code error;
  socket.connect(tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 31400), error);

  if (error)
    std::cout << "connect failed : " << error.message() << std::endl;
  else
    std::cout << "connected" << std::endl;
}
```

ファイルを準備したらcmakeでコンパイルします。

```bash
cmake .
make
```

無事コンパイルできれば全てのインストールと設定は終了です。

`#include <string_view>`がエラーを吐いた場合はg++-7の設定がおかしいです。

Cmakeがboostライブラリを見つけたが、warnを吐いている場合はCmakeのバージョンが(Boostに比べて)低いです。
Boostのバージョンを下げて再インストールすることで対応しましょう。

以上で全てのインストール作業は終わりです。

## Uninstall method
アンインストールするには、次のようにrmで削除してしまいます。

```bash
cd /usr/local
sudo rm -f bin/cmake bin/cpack bin/ctest
sudo rm -rf share/cmake-3.9
sudo rm -f lib/libboost*
sudo rm -rf include/boost
sudo apt remove g++-7
```

また、 .bashrc に設定が3つあるので、テキストファイルで開いて最後の方を見て、

```bash
export CXX='g++-7'
export CC='gcc-7'
export CMAKE_ROOT='/usr/local/share/cmake-3.9'
```

この三行をまるまる削除すればアンインストール完了です。
元の環境に戻っています。