Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails以外の開発一般

C++: 大規模コードベースのプロジェクトにおける VS Code の IntelliSense 設定例(コード補完など)

この記事では弊社製品である超縦書でも利用されている Chromium プロジェクトを例にして説明をします。

超縦書の場合、Chromium を含むこともありビルドシステムとして GNCMake を利用しています。

このような大規模なプロジェクトではIDE上でビルドまで一括で行う設定をするのが難しく、ビルドは別途コマンドを叩いて実行するようなケースがあります。

そのような場合に自動で IntelliSense の解析が正常に行えず、エディタでの作業に支障を来すことがあります。
※この記事ではコード補完などのコード支援機能を VS Code の固有名詞以外もまとめて IntelliSense と表記します

この記事では VS Code におけるその辺りの諸々について記載していきます。

🔗ビルド環境と VS Code のホスト環境が異なる場合について

Chromium のような大規模なプロジェクトではビルド環境の構築に非常に手間がかかることが多く、Docker Image などを作成することも多いと思います。

以降の解説では以下のような場合を想定します。

  • ビルド環境は Docker Image として構築、ビルドはコンテナ内で行う
  • VS Code はホスト環境で利用

VS Code をコンテナに接続することも出来ますが、コンテナ未起動でも VS Code によるコード閲覧は行える方が便利なため、コンテナ起動時に以下のような形で共有ディレクトリを指定します。

docker run -it -v ~/docker/mnt/:/home/user_name/mnt image_name /bin/bash

コンテナ内でソースやビルド結果を格納するディレクトリは /home/user_name/mnt の配下を利用し、ホスト環境の VS Code で ~/docker/mnt を開くイメージです。

自分の環境では Windows の WSL 上で docker run してビルド用コンテナを立ち上げており、Windows 環境の VS Code から WSL 拡張機能で WSL 内の ~/docker/mnt を開くような形をとっています。

🔗clangd のインストール

VS Code の IntelliSense の説明を読むと、C++ の場合 Microsoft が提供する C/C++ 拡張機能に含まれる機能を使うのが一般的に見えますが、速度面(特に大規模プロジェクト)で優れているとされる clangd を使うようにします。

ちなみに Chromium レベルのプロジェクトだと数十倍レベルで速度差があります。(2025/11現在)

C/C++ がインストールされていると clangd インストール直後に IntelliSense 機能の競合に関する警告が出ると思うので、既存の設定を無効にします。
手元で試した際には通知の disable ボタンを押してもうまく行かなかったので、手動で ./vscode/settings.json"C_Cpp.intelliSenseEngine": "disabled" を追記しました。

The 'clangd' language server was not found on your PATH. Would you like to download and install clangd 21.1.0?

また、上記のような通知も出たりすると思うので install ボタンを押して拡張機能が必要とする clangd サーバーをインストールします。

clangd のその他の設定は Configuration ページを参照。

🔗compile_commands.json の生成、設定

IntelliSense の解析に関わる設定はいくつかありますが、ここでは compile_commands.json を生成し、それを読み込ませるようにします。

このファイルの仕様については JSON Compilation Database を参照。

CMake の場合はビルド時に CMAKE_EXPORT_COMPILE_COMMANDS を有効にすると compile_commands.json が生成されます。

Chromium の場合は生成のために src/tools/clang/scripts/generate_compdb.py が用意されており、ビルド完了後に以下のようなコマンドを打つことで compile_commands.json を生成出来ます。
※ビルド中に動的生成されるファイルなどがあるため、コンパイル完了後にやる必要があります

# build_dir は build.ninja などがあるところ
src/tools/clang/scripts/generate_compdb.py -p build_dir > compile_commands.json

ここで生成した compile_commands.json を VS Code で読み込みたいわけですが、前述のようにビルド環境と VS Code のホスト環境が異なるような場合、パスが一致せずエラーになってしまいます。

また、複数の compile_commands.json が生成されるようなプロジェクトの場合、1つのファイルにマージする必要もあります。

そこで今回それらをまとめて行う Python3 スクリプトを作成しました。(95% Gemini製)

usage: map_compile_commands.py [-h] -m 'CONTAINER_ABSOLUTE_PATH:HOST_PATH' -o OUTPUT input_files [input_files ...]

複数の compile_commands.json ファイルをマージし、1つ以上のマッピングを使用してコンテナパスをホストパスに置換します。

positional arguments:
  input_files           [Required] Path(s) to the input compile_commands.json files

options:
  -h, --help            show this help message and exit
  -m 'CONTAINER_ABSOLUTE_PATH:HOST_PATH', --map 'CONTAINER_ABSOLUTE_PATH:HOST_PATH'
                        [Required] Path mapping. Can be used multiple times.
                        Example: -m /home/user_name/mnt:~/projects/mnt -m /home/user_name/opt/android_ndk:$ANDROID_HOME/ndk/version
  -o OUTPUT, --output OUTPUT
                        [Required] Path to the output merged compile_commands.json

上記ヘルプに記載のように -m オプションでコンテナとホストのパスマッピングを指定します。
ここではコンテナとホストという記載ですが、状況によっては他PC環境からの移行や他人への配布時にも使えるかもしれません。

前述の docker run -it -v ~/docker/mnt/:/home/user_name/mnt image_name /bin/bash で起動したコンテナであれば、 -m "/home/user_name/mnt:~/docker/mnt" を指定することになります。

全てのパスが共有ディレクトリ配下であればこれだけでもうまく行く場合もありますが、ヘルプの Example のように共有ディレクトリ外に NDK (ここでは Android のビルドを想定)のパスがあったりすると標準ライブラリのパスなどが解決できません。

そういう場合はそこのマッピングも指定する必要があります。この場合、NDK だけはホスト側にもインストールが必要になります。
(Chromium の場合、標準のNDKを使っていない場合もありますが、ビルドに利用するわけではないので近いバージョンのNDKを指定すれば概ね問題がないはずです)

このスクリプトで生成した、ホストのパスに変換された compile_commands.json を VS Code に読み込ませれば IntelliSense(clangd) がうまく動くはずです。

プロジェクト配下にある compile_commands.json は自動で検索してくれたりもしますが、余計なファイルを読み込んだりして速度低下やその他不具合が発生する可能性もあるため、専用ディレクトリに配置するのをおすすめします。
※特に今回の例のように複数の compile_commands.json がある場合など

例えば VS Code の作業ディレクトリ直下に .clangd_cache のようなディレクトリを作り、ここに compile_commands.json を格納します。

そして ./vscode/settings.json に以下のような設定を追記します。

{
    "clangd.arguments": [
        "--compile-commands-dir=${workspaceFolder}/.clangd_cache"
    ],
}

これで VS Code の作業ディレクトリ直下にある .clangd_cache/compile_commands.json を読んでくれるようになります。

正常に動いているかどうかは VS Code の出力タブの出力内容を clangd に切り替えることで確認できます。

設定などを切り替えた直後にうまく読んでくれない場合は clangd: Restart language server を実行するか、VS Code を開き直します。

正常に処理が進行していくと .clangd_cache/.cache/clangd にキャッシュが生成されていきます。
※キャッシュ生成が終わるまでは多少時間がかかります

🔗あとがき

当初超縦書プロジェクトに参加してから現状の開発環境に落ち着くまで、通常業務と並行してちょっとずつ改善を繰り返していたため結構長い期間を費やしました。

特に IntelliSense 周りは長いこと不便を感じており、数十万行あるソースから参照関数を検索機能経由で調査しなければいけなかったこともあり、「適切な内容の compile_commands.json」を clangd で読み込めた時の快適さは本当に感動的でした。

compile_commands.json 周りの話は検索すればちょこちょこ出てくるので昔から認識はしていたのですが、前述のパスマッピングの問題などで面倒くさくて放置していたところ、昨今の AI の進歩により置換スクリプト作成コストが急減してようやく対応出来ました。

大分ニッチな内容かとは思いますが、同様の悩みを持っている方の参考になれば幸いです。


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。