LSPにclangdを使ってPocketSDRのソースを読む
動機
VSCodeでPocketSDRのコードを読んでいる。 MSのC/C++拡張 (cpptools) は変数や関数のジャンプがやたらと遅い。 そこで、clangdを使うことにした。
手順
makefileの変更
makefileに直に書かれている make を $(MAKE) に変更する。 サブモジュールのライブラリのmakefileも。
compile_commands.json の生成
PATHに C:msys64mingw64bin がある状態で、PowerShellやcmdで mingw32-make > build.log 2>&1 でmakefileを実行する。 (makeのログにあるパスがcygpathを経由せず、素のWindowsのパスとして出力されるようにする) 念のため -j は付けず、 make clean して実行するのが良いかもしれない (考えればわかる)。
compiledb --parse build.log --full-path で compile_commands.json を生成する。
この際、コンパイラのフルパスはPATHで最初に解決されたものになることに注意。 実際に使ったコンパイラと一致しているか確認。
VSCodeのclasgd拡張で読み込み
settings.json で --query-driver を指定する。 compiledbが出力するコンパイラのフルパスではgccやg++の拡張子が .EXE と大文字になることがある。 --query-driver に書いたパスが小文字だと検出されない(?)ようで、いろいろ考えるのが面倒だったためワイルドカードを用いた。 もしかしたら勘違いかもしれない。 また、余計なものが入る可能性があるため、地道に列挙しても良い。
"clangd.arguments": [ "--query-driver=C:\\msys64\\mingw64\\bin\\g*", "--clang-tidy", "--log=verbose" ],
clangdが mingw64/bin をPATHに持つ環境で起動するようにする。 色々と方法はあるが、ここではGoでラッパーを書いてそれを呼び出すようにした (Goは未経験だがAIに頼んだらGoで出してきた) 。 なお、実行ファイルでないとエラーが出る。
ラッパーのスクリプト
package main import ( "os" "os/exec" "strings" ) func main() { clangd := `C:\Program Files\LLVM\bin\clangd.exe` path := os.Getenv("PATH") add := `C:\msys64\mingw64\bin` if !strings.Contains(strings.ToLower(`;`+path+`;`), `;`+strings.ToLower(add)+`;`) { path = add + `;` + path } cmd := exec.Command(clangd, os.Args[1:]...) cmd.Env = append(os.Environ(), "PATH="+path) cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr if err := cmd.Run(); err != nil { os.Exit(1) } }
コンパイルコマンド
mkdir clangd_env cd clangd_env # コードを書いたら go mod init example.com/claangd_env go build -o clangd_env.exe clangd_env.go
settings.json
.clangd を書く。 必須なのは CompilationDatabase で、 compile_commands.json があるディレクトリを指定する。
補遺
各手順の理由は大部分を省略。 かなりclangd, clangd拡張, gccに (今回、筆者にとって) 都合の悪い仕様があったため、余裕があるとき [いつ?] に追加する。
感想
非常に大変だった。 ここまでたどり着くまでに10時間くらいかかってしまった。
そういえば、みちびき5号機が来月打ち上げられるそう。 成功を祈ります。