VSCodeでIntelliSense用に設定しているC/C++のマクロが有効にならない問題の解決
VSCodeのC/C++モードのIntelliSenseが意図しない動作をしていた問題を解決できたのでメモ。
問題
- C/C++モードの設定ファイル
c_cpp_properties.json
でdefines
に、定義済みマクロとして認識してほしいマクロを記載しているが、IntelliSenseにそのマクロが認識されない
c_cpp_properties.json
の記載例:
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/usr/include/json-c",
"/usr/include/cutter"
],
"defines": [],
"cStandard": "gnu99",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools",
}
],
"version": 4
}
原因
- configurationProvider で IntelliSense 用の設定ファイルが提供されている .c ファイルについては、
c_cpp_properties.json
の設定が使われない項目がある。defines
もその項目に該当する。
- 参考リンク https://code.visualstudio.com/docs/cpp/customize-default-settings-cpp#_system-include-pathdefines-resolution-strategies - このケースでは、
ms-vscode.makefile-tools
が指定されており、Makefile Tools が事前にmake --dry-run
を実行したログを元に、各 .c ファイルについてコンパイルオプション等を記録して、その設定を利用して IntelliSense が動作している - つまり、Makefileのビルド対象に入っている .c ファイルについては、
defines
の設定値は考慮されない
対処方法
- mergeConfigurations を設定し、configuration provider の設定値と
c_cpp_properties.json
の設定値をマージするように設定する
設定の例:
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/usr/include/json-c",
"/usr/include/cutter"
],
"defines": [],
"cStandard": "gnu99",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools",
"mergeConfigurations": true,
}
],
"version": 4
}
雑感
対処方法自体は簡単なものだったが、configuration provider という概念を理解していないために苦労した。
結局のところ、configuration provider とはコンパイルオプション等の configuration を C/C++モード(IntelliSense含む) に提供してくれる仕組みのことで、makefile-tools の場合には make --dry-run
を裏で実行した出力を解析し、C/C++モード に与える設定ファイルを生成しているだけ。
settings.json
に下記のような設定を1行加えると、その内実を確認できる。
"makefile.extensionOutputFolder": "${workspaceFolder}/.vscode/makefile-tools",
これを書き加えて、コマンドパレットで "Makefile: Reset the Makefile Tools Extension workspace (略)" を実行してしばらく待つと、${workspaceFolder}/.vscode/makefile-tools/configurationCache.log
というファイルが作成される。
これが configuration provider (makefile-tools) によって作成された IntelliSense に読み込ませる設定となっている。
中身はJSON形式で記載されているので、jq などで表示すれば何が書かれているかは簡単に解読できる。
この中で、各 .c ファイルについて下記のようなエントリが作成されている。
[
"/path/to/file.c",
{
"uri": {
"$mid": 1,
"fsPath": "/path/to/file.c",
"path": "/path/to/file.c",
"scheme": "file"
},
"configuration": {
"defines": [
"HAVE_CONFIG_H",
],
"includePath": [],
"forcedInclude": [],
"compilerPath": "/usr/bin/gcc",
"compilerArgs": [
冒頭の問題に戻ると、c_cpp_properties.json
の defines
の設定値が使われないのは、この configuration provider (makefile-tools) によって作成された値が利用されているからである。c_cpp_properties.json
に記載されているのは、あくまでデフォルト値という扱いで、configuration provider から与えられている場合にはそちらが優先される。
Discussion