MetaLSP: C++ワークスペースの統合と分割
複数のLSP/DAPワークスペースを纏めて1つのLSP/DAPサーバーに見せる仕組みが必要なので準備する。
これが結構難しい。。LSPやDAPの開発元であるMSはWindows以外の環境に投資するモチベーションがあまり無いためか、LSP/DAPはマルチプラットフォームを意識したデザインになっていない。
ワークスペースの統合
"ワークスペース" とは、検索等の操作のスコープを指す。VS Codeでフォルダを開いた場合はそのフォルダがワークスペースとなり、通常はそのフォルダ内 および、そこのソースコードが #include <...>
するソースコードが検索の対象となる。
しかし、大規模な開発プロジェクトでは外部からstatic libraryやshared libraryの形でコンパイル済のコードを受け取ることがあり、(特にデバッグ中に)その実装内部までを探索したいケースがある。
例えば、デスクトップPC向けYuniframeの場合:
- Yuniframe本体
- ANGLE (OpenGL ES実装)
- C-WebGL (WebGL実装)
- SDL2
の4つのワークスペースに分割され、基本的にYuniframeアプリの開発中は 2 〜 4 のワークスペースを参照しなくても良い(2 〜 4 のプロジェクトが提供するパブリックヘッダファイルだけを参照できれば十分)。が、往々にしてGPUデバッグ時はANGLEの内部を確認する必要があることが多いため、 1 〜 4 のプロジェクト全てを単一のワークスペースとして扱えると都合が良い。
このような場合に、複数のワークスペースを統合して1つのワークスペースとする必要がある。
ワークスペースの分離
逆に、単一のワークスペースを複数に分離することも考えられる。
CMakeには "Multi-Config" ジェネレータの概念があり、 Ninja や msbuild、Xcodeのようなビルドツールでは単一プロジェクトにデバッグ版とリリース版を同居させることができるようになっている。
この "Multi-Config" ジェネレータで出力された build.ninja
に対して ninja -t compdb
すると単一のソースコードに対して複数のコマンドラインが出力されるため、正確なビルド情報がLSPサーバーに伝わらなくなってしまう。
(VS Codeでの通常の開発は、そもそも単一のbuild directoryで複数のconfigurationを扱わないことでこの問題を回避している。また、VSのIntelisenseは直接的にこのシナリオをサポートしている。)
リンク関係の追跡
ワークスペースの統合 / 分離 両者に必要なのがリンク関係の追跡、つまり、 ビルドの出力バイナリから元になっているソースコードおよびそのコマンドラインを抽出する となる。
ソースコードが高々1回しかコンパイルされない場合は、出力バイナリのデバッグ情報に含まれるソースコードからコマンドラインを特定できる。しかし、複雑なプロジェクトや、Multi-Configなプロジェクトではそうは行かない。例えば、Multi-Configケースでは単一のソースコードを -O0
(最適化無効) と -O2
(最適化有効) の両方でコンパイルしてリンクするため、デバッグ情報に含まれるファイル名だけではコマンドラインが -O0
だったのか -O2
だったのかは特定できない。
よって、リンク関係を追跡するためには、 gcc
なり clang
なりのコマンドラインをパースし、実際のオブジェクトファイルの単位で入出力を導出する必要がある。