llvm / llvm/llvm-project

[clangd] System includes from --query-driver miss builtin headers when -resource-dir is overridden

Open
#189,288 3 comments 0 reactions 0 assignees View on GitHub
clangd
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Summary

When clangd uses `--query-driver` to extract system includes from a compiler that uses `-isysroot`, and clangd overrides `-resource-dir` with its own, the builtin compiler headers (containing `size_t`, `ptrdiff_t`, etc.) are not added to the include search path. This causes `` and other standard headers to fail.

## Environment

- clangd 20.1.8 (macOS, arm64)
- Compiler: standalone clang++ from a custom toolchain (not system Xcode clang)
- Uses `-isysroot` pointing to a macOS SDK
- Uses `-nostdinc++` with custom libc++ headers

## Reproduction

The compile command (from `compile_commands.json`) contains:
```
clang++ --target=arm64-apple-macos11 -isysroot /path/to/sdk -nostdinc++ \
-I/path/to/custom/libcxx/include \
-c file.cpp
```

Note: there is no `-isystem` or `-resource-dir` in `compile_commands.json`.

clangd's `--query-driver` is configured to match this compiler. The system includes extractor runs:
```
System includes extractor: successfully executed /path/to/clang++
got includes: "/path/to/sdk/usr/include, /path/to/sdk/System/Library/Frameworks (framework directory)"
```

clangd then builds the command with:
1. `-isystem /path/to/sdk/usr/include` (from extractor)
2. `-resource-dir=/path/to/clangd/lib/clang/20` (clangd's own, overriding the compiler's)

The problem: the extractor output does **not** include the compiler's builtin include path (e.g. `/path/to/compiler/lib/clang/20/include`), because clangd is expected to provide its own via `-resource-dir`. However, clangd's `-resource-dir` override changes the resource dir path but does **not** add the corresponding `-isystem /include` to the search path.

### Include resolution chain failure

```
libcxx/cstddef
→ libcxx/stddef.h (next_include)
→ sdk/usr/include/stddef.h ← found via -isystem (from extractor)
→ sdk/usr/include/arm/_types.h
→ needs size_t from builtin stddef.h — NOT FOUND
```

The SDK's `stddef.h` expects that the compiler builtin `stddef.h` (from `/include/`) has already defined `size_t` and `ptrdiff_t`. But since clangd replaced `-resource-dir` without adding its include path to `-isystem`, the builtin `stddef.h` is never found via the `#include_next` chain.

### Workaround

Adding the resource-dir include path explicitly in `.clangd` config:
```yaml
CompileFlags:
Add:
- -isystem
- /path/to/clangd/lib/clang/20/include
```

This places the builtin includes before the sysroot includes, fixing the `#include_next` chain.

## Expected behavior

When clangd overrides `-resource-dir`, it should ensure that `/include` is in the system include search path (before sysroot includes), so that the `#include_next` chain from libc++ → builtin → sysroot works correctly.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.