What
fbuild clangd-config (and every other consumer of CompileDatabase::translate_for_clang) bakes GCC builtin include directories into the emitted compile_commands.json as -isystem — but it collects them from every toolchain in the fbuild cache, not from the toolchain the project actually builds with.
builtin_isystem_args() (crates/fbuild-build-engine/src/compile_database/clang.rs:92) calls find_gcc_builtin_include_dirs() (crates/fbuild-toolchain/src/toolchain/clang.rs:290), which walks the whole ~/.fbuild/prod/cache/toolchains/ tree recursively (find_gcc_includes_recursive, depth ≤ 6) and returns every lib/gcc/<triple>/<version>/include that contains stdbool.h.
Observed
For bench/blink -e esp32s3 (ESP32-S3, xtensa-esp32s3-elf toolchain), the clangd database carries:
-isystem .../toolchains/3bbf.../8.4.0+2021r2-patch5/lib/gcc/xtensa-esp32s3-elf/8.4.0/include <- correct
-isystem .../toolchains/arduino-tools/08e1.../7.3.0-atmel3.6.1-arduino7/avr/lib/gcc/avr/7.3.0/include
-isystem .../toolchains/developer-gnu/e064.../15.2.Rel1/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/lib/gcc/arm-none-eabi/15.2.1/include
-isystem .../toolchains/dl-toolchain-gccarmnoneeabi-.../9.2.1/lib/gcc/arm-none-eabi/9.2.1/include
-isystem .../toolchains/dl-toolchain-xtensa-linux_x86_64-2.100300.220621/.../2.100300.220621/lib/gcc/xtensa-lx106-elf/10.3.0/include
-isystem .../toolchains/earlephilhower-esp-quick-toolchain/.../3.2.0-gcc10.3/xtensa-lx106-elf/lib/gcc/xtensa-lx106-elf/10.3.0/include
... (10 `-isystem` entries total)
AVR, ARM, and xtensa-lx106 (ESP8266) builtin headers are on the search path of an ESP32-S3 project.
Why it matters
-isystem dirs are searched before the compiler's own builtins, and these directories hold the freestanding C headers (stdint.h, stddef.h, stdarg.h, stdbool.h, ...) whose contents are architecture-specific. With AVR/ARM/lx106 dirs ahead of the esp32s3 one, clangd can resolve #include <stdint.h> — or any of those freestanding headers — to another target's copy, so go-to-definition, hover, and diagnostics describe the wrong architecture. It is also a silent source of "works in the IDE, fails on the board" confusion.
Build correctness is not affected: the real g++ invocation carries no -isystem at all (compile_commands.raw.json has 0 -isystem entries), so this is confined to the clangd/IDE database.
Suspected fix
Restrict the lookup to the toolchain actually selected for the env being emitted — plumb the resolved toolchain (or its lib/gcc/<triple> root) into translate_for_clang instead of scanning the cache root. Note the call site is also unconditional on target arch, so a project building for both AVR and ESP32-S3 in one fbuild.ini needs the dirs chosen per env, not once per database.
Found while investigating #1537.
What
fbuild clangd-config(and every other consumer ofCompileDatabase::translate_for_clang) bakes GCC builtin include directories into the emittedcompile_commands.jsonas-isystem— but it collects them from every toolchain in the fbuild cache, not from the toolchain the project actually builds with.builtin_isystem_args()(crates/fbuild-build-engine/src/compile_database/clang.rs:92) callsfind_gcc_builtin_include_dirs()(crates/fbuild-toolchain/src/toolchain/clang.rs:290), which walks the whole~/.fbuild/prod/cache/toolchains/tree recursively (find_gcc_includes_recursive, depth ≤ 6) and returns everylib/gcc/<triple>/<version>/includethat containsstdbool.h.Observed
For
bench/blink -e esp32s3(ESP32-S3, xtensa-esp32s3-elf toolchain), the clangd database carries:AVR, ARM, and xtensa-lx106 (ESP8266) builtin headers are on the search path of an ESP32-S3 project.
Why it matters
-isystemdirs are searched before the compiler's own builtins, and these directories hold the freestanding C headers (stdint.h,stddef.h,stdarg.h,stdbool.h, ...) whose contents are architecture-specific. With AVR/ARM/lx106 dirs ahead of the esp32s3 one, clangd can resolve#include <stdint.h>— or any of those freestanding headers — to another target's copy, so go-to-definition, hover, and diagnostics describe the wrong architecture. It is also a silent source of "works in the IDE, fails on the board" confusion.Build correctness is not affected: the real g++ invocation carries no
-isystemat all (compile_commands.raw.jsonhas 0-isystementries), so this is confined to the clangd/IDE database.Suspected fix
Restrict the lookup to the toolchain actually selected for the env being emitted — plumb the resolved toolchain (or its
lib/gcc/<triple>root) intotranslate_for_clanginstead of scanning the cache root. Note the call site is also unconditional on target arch, so a project building for both AVR and ESP32-S3 in onefbuild.inineeds the dirs chosen per env, not once per database.Found while investigating #1537.