ccache on Ubuntu — C/C++コンパイルを最大10倍高速化する方法

開発環境

この記事のポイント

  • sudo apt install ccache だけで導入でき、Ubuntu 24.04 では ccache 4.9.1 が入ります
  • CMake プロジェクトで ccache を使うと、2回目以降のビルドが 実測で2.1倍速(359ms → 172ms)になりました
  • ccache の正しい使い方は「PATH に /usr/lib/ccache を追加する方法」と「CMake の RULE_LAUNCH_COMPILE を使う方法」の2通りあります
  • キャッシュ上限はデフォルト 5 GiB、CCACHE_MAXSIZE で変更できます
  • Linux カーネルやChromiumのような大規模プロジェクトでは 10倍以上の高速化事例もあります

C/C++ のコードを書いていると、ビルドを繰り返すたびに待たされるのが地味にきついですよね。ちょっとした修正のたびに数分待つ、というのは開発のリズムを壊します。

ccache(Compiler Cache)はコンパイル結果をキャッシュしておくツールで、同じソースを再コンパイルするとき、前回の出力をそのまま使い回します。Ubuntu には apt 一発で入り、設定なしでもすぐに効果が出ます。

この記事では Ubuntu 24.04 LTS で実際に ccache を動かし、ビルド時間を計測しました。使い方は「PATH 経由」と「CMake 統合」の2パターンを紹介します。

目次

  1. ccache とは何か
  2. インストールと確認
  3. セットアップ①:PATH 経由(最もシンプル)
  4. セットアップ②:CMake プロジェクトへの統合
  5. 実測:ビルド時間はどれくらい変わるか
  6. 統計確認と設定チューニング
  7. Ubuntu 22.04 vs 24.04 のバージョン差
  8. 運用上のヒント
  9. まとめ

ccache とは何か

ccache は「コンパイラの前に挟まるプロキシ」です。ソースコードのハッシュ値を計算し、同じハッシュの出力(オブジェクトファイル)がキャッシュにあればそれを返し、なければ実際のコンパイラを呼び出します。

特徴は次の3点です。

  • コンパイラ本体を一切書き換えない。PATH を変えるか、CMake に設定するだけ
  • ヘッダーファイルが変わればキャッシュが無効になる(偽陽性なし)
  • git stash popgit bisect で以前の状態に戻したとき、コードが同じならキャッシュが使われる

注意

この記事のコマンドは Ubuntu 24.04 LTS で検証しています。22.04 では ccache のバージョンが 4.5.1 と古く、一部のオプション名が異なります(後述)。

インストールと確認

Ubuntu 24.04 なら apt から直接インストールできます。




ubuntu@linuxlab: ~
$ sudo apt update && sudo apt install ccache
Reading package lists… Done
The following NEW packages will be installed:
ccache
After this operation, 1,897 kB of additional disk space will be used.
Setting up ccache (4.9.1-1) …
Updating symlinks in /usr/lib/ccache …

インストールが終わったら、バージョンを確認します。




ubuntu@linuxlab: ~
$ ccache –version
ccache version 4.9.1

Copyright (C) 2002-2007 Andrew Tridgell
Copyright (C) 2009-2024 Joel Rosdahl and other contributors
ccache インストール実ログ(Ubuntu 24.04)
ccache インストール実ログ(Ubuntu 24.04)

apt install ccache を実行すると、/usr/lib/ccache/ ディレクトリに gccg++ といった名前のシンボリックリンクが自動で作られます。これが ccache の「コンパイラに成りすます」仕組みの核心です。




ubuntu@linuxlab: ~
$ ls -la /usr/lib/ccache/
total 0
lrwxrwxrwx 1 root root 16 … c89-gcc -> ../../bin/ccache
lrwxrwxrwx 1 root root 16 … c99-gcc -> ../../bin/ccache
lrwxrwxrwx 1 root root 16 … cc -> ../../bin/ccache
lrwxrwxrwx 1 root root 16 … g++ -> ../../bin/ccache
lrwxrwxrwx 1 root root 16 … gcc -> ../../bin/ccache
lrwxrwxrwx 1 root root 16 … x86_64-linux-gnu-g++ -> ../../bin/ccache
lrwxrwxrwx 1 root root 16 … x86_64-linux-gnu-gcc -> ../../bin/ccache

すべて /usr/bin/ccache へのリンクです。このディレクトリを PATH の先頭に加えると、g++ と打つだけで自動的に ccache 経由になります。

セットアップ①:PATH 経由(最もシンプル)

最も手軽な方法です。~/.bashrc または ~/.zshrc に1行追加します。




ubuntu@linuxlab: ~
$ echo ‘export PATH=”/usr/lib/ccache:$PATH”‘ >> ~/.bashrc
$ source ~/.bashrc
$ which g++
/usr/lib/ccache/g++

これで which g++/usr/lib/ccache/g++ を返せば設定完了です。以降は makeninja を普段通り実行するだけで、裏側で ccache が動きます。

よくある落とし穴:ccache g++ と打つと逆効果になることがある

PATH に /usr/lib/ccache を追加した状態で ccache g++ と明示的に打つと、ccache が「自分自身(ccache)を ccache でラップしている」と判断して Uncacheable 扱いになります。PATH 経由で使うか、後述の CMake 統合を使うかのどちらかに統一してください。

セットアップ②:CMake プロジェクトへの統合

CMake を使っているプロジェクトでは、CMakeLists.txt に数行追加するだけで ccache が有効になります。PATH を変えずに済むのでプロジェクト単位で管理できます。




CMakeLists.txt
# CMakeLists.txt に追加(project() の後)
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
message(STATUS “ccache found: ${CCACHE_FOUND}”)
else()
message(STATUS “ccache not found, building without cache”)
endif()

cmake で configure したときに -- ccache found: /usr/bin/ccache と表示されれば有効になっています。




ubuntu@linuxlab: ~/myproject
$ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
— ccache found: /usr/bin/ccache
— Configuring done (0.1s)
— Build files have been written to: /home/user/myproject/build
$ cmake –build build
[ 50%] Building CXX object CMakeFiles/myapp.dir/main.cpp.o
[100%] Linking CXX executable myapp
[100%] Built target myapp

2回目以降のビルドでは、変更していないファイルのコンパイルが ccache のキャッシュから返るため、体感的に別物の速さになります。

実測:ビルド時間はどれくらい変わるか

Ubuntu 24.04 の Docker コンテナで、C++17 の CMake プロジェクトをビルドして時間を計測しました。コードは「100,000 以下の素数を列挙するテンプレートコード」で、g++ 13.3.0 / ccache 4.9.1 を使っています。

コンパイル時間比較(g++ vs ccache)
コンパイル時間比較(g++ vs ccache)

結果をまとめると:

ビルド方法 所要時間 対コールドg++比
g++ 直接(コールドスタート) 1,058 ms 基準
g++ 直接(ウォームキャッシュ) 794 ms 1.3×
ccache(初回・キャッシュミス) 359 ms 2.9×
ccache(2回目・キャッシュヒット) 172 ms 6.2×

1ファイルのビルドで 6倍という結果でした。実際のプロジェクトでは数百〜数千ファイルをコンパイルするので、変更していないファイルが多いほど効果は大きくなります。Linux カーネルの開発では、ビルド時間が 20分から 2分以下になる事例も報告されています。

著者アイコン
著者アイコン

正直、1ファイルだと「そこまで変わらないかな」と思っていたのですが、コールドスタートとの比較だと 6倍以上という数字が出ました。cmake の configure フェーズを含んでいるので完全なアップルtoアップルではないですが、体感値としては「ほぼ一瞬」になる感覚と一致します。

統計確認と設定チューニング

ccache がどれだけ機能しているかは ccache -s(または ccache --show-stats)で確認できます。CMake ビルドを2回実行した後の実出力がこれです。

ccache -s 実測統計出力
ccache -s 実測統計出力



ubuntu@linuxlab: ~
$ ccache -s
Summary:
Hits: 1 / 2 ( 50.00%)
Direct: 1 / 2 ( 50.00%)
Preprocessed: 0 / 2 ( 0.00%)
Misses: 1 / 2 ( 50.00%)
Local storage:
Cache size (GiB): 0.0 / 5.0 ( 0.00%)

初回ビルド(miss)と2回目ビルド(hit)で 50% のヒット率になりました。実際の開発では、ほとんどのファイルを触らずに1ファイルだけ変更するケースが多いので、ヒット率は 90% 以上になるのが普通です。

ccache 統計サマリーカード
ccache 統計サマリーカード

①キャッシュのサイズを変更する

デフォルトは 5 GiB です。大規模プロジェクト(Linux カーネル等)を扱うなら 20〜50 GiB に増やすのが一般的です。




ubuntu@linuxlab: ~
$ ccache –set-config=max_size=20G
$ ccache -p | grep max_size
(user_conf) max_size = 20.0G

②キャッシュをクリアする




ubuntu@linuxlab: ~
$ ccache -C # キャッシュを完全削除
Cleared cache directory /home/user/.cache/ccache
$ ccache -z # 統計カウンタだけリセット(キャッシュは消さない)
Statistics zeroed

③キャッシュの場所を変更する

デフォルトは ~/.cache/ccache です。SSD の別パーティションや共有ディレクトリに移したい場合は CCACHE_DIR 環境変数で指定します。




ubuntu@linuxlab: ~
$ export CCACHE_DIR=/mnt/fast-ssd/.ccache
$ ccache -p | grep cache_dir
(environment) cache_dir = /mnt/fast-ssd/.ccache

Ubuntu 22.04 vs 24.04 のバージョン差

Docker コンテナで両バージョンの apt キャッシュポリシーを確認しました。

Ubuntu 22.04 vs 24.04 バージョン比較表
Ubuntu 22.04 vs 24.04 バージョン比較表

Ubuntu 22.04(Jammy)には ccache 4.5.1、Ubuntu 24.04(Noble)には ccache 4.9.1 が入ります。バージョン間で変わる主な点は次の通りです。

  • 4.7 以降depend_mode(依存関係ベースキャッシュ)がデフォルト対応、ヘッダー変更の検出がより精密に
  • 4.9 以降ccache -s の出力形式が変わり、”Cacheable / Uncacheable” の区分が追加
  • 設定ファイルのキー名は両バージョンでほぼ共通だが、--show-stats の出力フォーマットが微妙に異なる



ubuntu@linuxlab: ~
$ # Ubuntu 22.04 の場合
$ apt-cache policy ccache | head -3
ccache:
Installed: (none)
Candidate: 4.5.1-1
$ # Ubuntu 24.04 の場合
$ apt-cache policy ccache | head -3
ccache:
Installed: 4.9.1-1
Candidate: 4.9.1-1

運用上のヒント

①CI/CD 環境でキャッシュを永続化する

GitHub Actions や GitLab CI では、~/.cache/ccache を actions/cache でキャッシュすると、プッシュのたびにフルビルドが走らなくなります。




.github/workflows/build.yml(抜粋)
– uses: actions/cache@v4
with:
path: ~/.cache/ccache
key: ${{ runner.os }}-ccache-${{ github.sha }}
restore-keys: |
${{ runner.os }}-ccache-

②ccache -s を定期的に確認する

ヒット率が 80% 未満のときは何かが変わっている証拠です。よくある原因はこれです。

  • コンパイラ本体のアップデート(mtime が変わるためキャッシュが全無効に)
  • ビルドスクリプトが毎回タイムスタンプを埋め込んでいる(-DBUILD_DATE=$(date) 等)
  • 絶対パスが混入している(base_dir の設定が必要なケース)

③CCACHE_SLOPPINESS で誤ったキャッシュ無効化を防ぐ

プリコンパイルヘッダー(PCH)やシステムヘッダーのタイムスタンプが変わってキャッシュが大量にミスするときは、次の設定を試してみてください。




ubuntu@linuxlab: ~
$ export CCACHE_SLOPPINESS=pch_defines,time_macros

time_macros を指定すると __TIME____DATE__ が含まれるファイルもキャッシュされるようになります(ビルドの再現性より速度を優先する場合に使います)。

まとめ

ccache を Ubuntu 24.04 で試した結果をまとめます。

  • sudo apt install ccache で ccache 4.9.1 が入り、/usr/lib/ccache/ にコンパイラのシンボリックリンクが自動作成される
  • PATH に /usr/lib/ccache を追加するか、CMake の RULE_LAUNCH_COMPILE を使うと、既存のビルドスクリプトを変えずに ccache が有効になる
  • 実測では CMake プロジェクトのビルドが 2回目以降 2.1倍速(359ms → 172ms)になった。ファイル数が多い実際のプロジェクトではより大きな効果が出る
  • ccache -s でヒット率を確認し、ヒット率が低いときは原因(コンパイラ更新・絶対パス混入)を特定する
  • CI/CD では ~/.cache/ccache をキャッシュストレージに永続化するのが定石

VPS でセルフビルドを繰り返す場合も、ccache があるとかなり楽になります。VPS 選びについては次の記事も参考にしてみてください。

コメント

タイトルとURLをコピーしました