C++コンパイル済みヘッダー(Precompiled header(.gch))でコンパイル時間短縮

## 前置き

[江添亮のC++入門](https://ezoeryou.github.io/cpp-intro/)を参考に、コンパイル済みヘッダー(precompiled header)を使用すると、コンパイル時間にどの程度差が出るか確認する。


https://ezoeryou.github.io/cpp-intro/



## コンパイル済みヘッダーとは

- 事前にコンパイルしたヘッダー

- 拡張子は`.gch`



## Sample source

*all.h*

```c++
#include <cstddef>
#include <limits>
#include <climits>
#include <cfloat>
#include <cstdint>
#include <cstdlib>
#include <new>
#include <typeinfo>
#include <exception>
#include <initializer_list>
#include <cstdalign>
#include <stdexcept>
#include <cassert>
#include <cerrno>
#include <system_error>
#include <string>

#if __has_include(<string_view>)
#   include <string_view>
#endif

#include <array>
#include <deque>
#include <forward_list>
#include <list>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <stack>
#include <iterator>
#include <algorithm>
#include <cfenv>
#include <random>
#include <numeric>
#include <cmath>
#include <iosfwd>
#include <iostream>
#include <ios>
#include <streambuf>
#include <istream>
#include <ostream>
#include <iomanip>
#include <sstream>
#include <fstream>

#if __has_include(<filesystem>)
#   include <filesystem>
#endif

#include <cstdio>
#include <cinttypes>


#include <regex>
#include <atomic>
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <condition_variable>
#include <future>

using namespace std::literals ;
```

*main.cpp*

```c++
int main()
{
    std::cout << "hello" ;
}
```



## コンパイル済みヘッダー未使用でのコンパイル

まずはコンパイル済みヘッダーを使用せずにコンパイルする。

コンパイル時間は以下のとおりである。

```
$ time g++ -std=c++20 -Wall -pedantic-errors -include ./all.h -o program ./main.cpp

real    0m1.691s
user    0m0.000s
sys     0m0.015s
```



## コンパイル済みヘッダー使用でのコンパイル



### コンパイル済みヘッダーの作成



使用するオプションは`-x c++-header`と`-o <ヘッダーファイル名>.gch`だ。

- `-x c++-header`オプションでC++ヘッダーとして扱うことをコンパイラーに強制する。
- `-o <ヘッダーファイル名>.gch`で出力ファイルの拡張子をgchにする。



その他一般的なコンパイル時に必要なオプションを追加したコマンドが下記となる。

今回はついでにコンパイル時間も計測している。不要な場合は`time`を削除して使用してください。

```
$ time g++ -std=c++20 -Wall -pedantic-errors -x c++-header -o all.h.gch ./all.h

real    0m3.313s
user    0m0.000s
sys     0m0.015s
```



### -xオプションについて

`-x`オプションの引数は他にも色々ある。たとえばC言語で同じ事がしたければ、`c-header`を使用すれば良い。

>c
>c-header: precompiled header file
>cpp-output
>c++
>**c++-header**
>c++-cpp-output
>objective-c
>objective-c-header
>objective-c-cpp-output
>objective-c++
>objective-c++-header
>objective-c++-cpp-output
>assembler
>assembler-with-cpp
>ada
>f77
>f77-cpp-input
>f95
>f95-cpp-input
>go
>brig
>
>参照：[gcc -x](https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/GCC/options/x/index)

https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/GCC/options/x/index



### コンパイル

実際にコンパイル済みヘッダーを使用してコンパイルしてみる。

gccはヘッダーファイルを使う時、同名の`.gch`ファイルが存在する時、そちらをコンパイル済みヘッダーとして使用することでヘッダーファイルの処理を省略する。実行結果は下記となる。確かに少し早い。

```
$ time g++ -std=c++20 -Wall -pedantic-errors -include ./all.h -o program ./main.cpp

real    0m0.515s
user    0m0.000s
sys     0m0.015s
```



## コンパイル時間比較

コンパイル時間を比較してみる。このプログラムだとコンパイル時間が3分の1ほどになっている。

| コンパイル済みヘッダー未使用 | コンパイル済みヘッダー使用 |
| ---------------------------- | -------------------------- |
| real    0m1.691s             | real    0m0.515s           |



## まとめ

勉強するにあたって、コンパイルの度に時間をかけるのは非効率だと思う。

そういう意味ではコンパイル済みヘッダーはどんどん使っていくのが良いだろう。