clangd 設定

2023 更新。
`clang16` + `vc` の環境で試した。

# clangd の起動設定

```
"--enable-config" // .clangd 設定を有効化する
"--header-insertion=never" // 好みで
"--clang-tidy" // 好みで
"--compile-commands-dir=builddir" // 👈 compile_commands.json の場所を示す
```

## vscode

```json:.vscode/settings.json
{
    "clangd.arguments": [
        "--compile-commands-dir=${workspaceFolder}/build",
        "--header-insertion=never",
        "--clang-tidy",
        "--enable-config",
    ],
}
```

:::note warn

これは clangd の設定ではないので利きません。

```
    "C_Cpp.default.compileCommands": "builddir\\compile_commands.json",
```

:::

project local で clangd.arguments 上書きすると右下にメッセージが出てくる。

![clangd_setting.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59664/eb3ea42c-0ba4-6da2-d71e-5d0a1c3efb00.jpeg)

`Yes, use this setting` する。

## nvim

```
  lspconfig.clangd.setup {
    cmd = {
      "path_to_clangd",
      "--compile-commands-dir=FULLPATH_TO_DIR", -- 👈 fullpath が必要かもしれない 
      "--header-insertion=never",
      "--clang-tidy",
      "--enable-config",
    },
  } 
```

# compilation database (compile_commands.json)

:::note
clangdの起動オプション `--compile-commands-dir=` 必要
:::

cmake や meson や bear で compile_commands.json を生成して、
それにより clangd のコンパイルフラグを決めることができる。

:::note warn
clangd では compilation database (compile_commands.json) を使う場合と
使わない場合で一部の設定が排他になっている感じ。
`compile_flags.txt`, `fallbackFlags` が compilation database と共存できない。
:::

:::note warn
compile_commands.json に記述の無い header ファイルは適当に infer してくれる。

```
# header を check したときの verbose log
Compile command inferred
```

できるが `header` に対するコンパイルフラグの決定に問題を抱えている、
ような気がする。特に Windows MSVC で使う場合。
具体的には `-std=c++14` になってしまって、快適でない。
:::


## cmake
* CMake を使うときに `compile_commands.json` を出力させるには
  * `-DCMAKE_EXPORT_COMPILE_COMMANDS=1` 出力設定
  * `-G Ninja` を指定。(Windowsデフォルトの MSBuild にその機能が無い。Makefile か Ninja ならば Ninja であろう)

## meson
自動生成

## make
bear で生成する？。やったことない

# compilation database を使わないときに有効になる設定 
諦めてこっちで設定するのもありかも。特に msvc 環境。

`--compile-commands-dir=` 起動オプションを削除。

## `compile_flags.txt`

https://qiita.com/syoyo/items/e90a83c37b3ea17e8f3d

## fallbackFlags

### vscode

```json:settings.json
    "clangd.fallbackFlags": [
        "-std=c++20"
    ],
```

### nvim

`init_options`

# トラブル
`cl.exe` と `clang-cl.exe` で受け付けるオプションが微妙に違う。
要するに `-std=c++17` が通らずに `/std:c++17` にする必要がある(clangd16)。

:::note
meson で `cpp_std=c++latest` 形式で設定していた。
直接コマンドラインを指定していないので、ビルド設定から修正できない。
cmake でも同様の問題が起きそう。
:::

この現象は、 `header` のコマンドラインを推論したときだけに発生するらしく
ヘッダーで `c++17` 以降の `string_view` などを include するとエラー表示になって使いづらくなる。

これを `prject_root/.clangd` 設定で修正できる。

:::note
clangd の起動オプション `--enable-config` 必要。
:::

```.clangd
CompileFlags:
  Remove: [-std=c++latest]
  Add: ["/std:c++latest"] # 👈 ダブルクォートしないと yaml のシンタックス違反になるぽい
```

:::note
header を直接開いたときは効くのだが、
goto definition 移動したときは効かないなど、経路によって効いたり効かなかったり・・・。
:::

## `unknown type name ‘namespace’`

- https://stackoverflow.com/questions/75497627/clangd-lsp-shows-unknown-type-name-interface-in-dsound-h


# デバッグ

以下のようなコマンドラインで動作を確認できる。

```
"C:/Program Files/LLVM/bin/clangd.exe" --compile-commands-dir=builddir --check=source_or_header --enable-config
```

見るべきポイントは、

- 設定が読まれているか
- エラーメッセージ全般
- `internal (cc1) args are` で `-std=c++14` になっているか

など。

```
I[03:33:32.829] argv[0]: C:/Program Files/LLVM/bin/clangd.exe
I[03:33:32.829] argv[1]: --compile-commands-dir=builddir
I[03:33:32.829] argv[2]: --check=source_or_header
I[03:33:32.830] argv[3]: --enable-config
I[03:33:32.830] argv[4]: --log=verbose
V[03:33:32.834] User config file is %LOCALAPPDATA%\clangd\config.yaml
V[03:33:32.835] config note at .clangd:1:0: Parsing config fragment

E[03:33:33.193] [typename_nested_not_found] Line 18: no type named 'string_view' in namespace 'std'
E[03:33:33.193] [no_member_template] Line 24: no template named 'span' in namespace 'std'
```

さらに `--log=verbose` をつけることでヒントが見つかる場合がある。

```
Ignored diagnostic. unknown argument ignored in clang-cl: '-std=c++latest'
```

# clangd 設定

https://clangd.llvm.org/config

- ユーザー設定 `%LOCALAPPDATA%/clangd/config.yaml`
- コマンドライン(Editorのclangd起動設定)
- compilation database(compile_commands.json) `--compile-commands-dir=`
- プロジェクト設定(`PROJECT_ROOT/.clangd`) `--enable-config`