Clang, clang++, and clangd can't find headers, even with compile_commands.json

TLDR

  1. Export compile_commands.json
  2. Set clangd (or your specific LSP) to query clang++ (or the compiler in compile_commands.json) for include paths.

See the concrete helix example from below and adapt it for your IDE.

Solution

You can use the --query-driver flag of clangd to have the same stdlibc++ includes that clang++ uses.

For example for helix I wrote something like this under .helix/languages.toml in the root of my project

[language-server.clangd]
command = "clangd"
args = ["--query-driver=/nix/store/*/bin/clang++", "--background-index"]
# or args = ["--query-driver=/nix/store/*/bin/clang++"]

Just make sure you provide clangd with compile_commands.json and depending on what’s inside you set the query driver to that compiler.

Below is also a reference flake with a devShell

{
  description = "A basic flake with a shell";
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
  inputs.systems.url = "github:nix-systems/default";
  inputs.flake-utils = {
    url = "github:numtide/flake-utils";
    inputs.systems.follows = "systems";
  };

  outputs =
    { nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        devShells.default = pkgs.mkShell {
          packages = with pkgs; [
            clang
            clang-tools
            meson
            ninja
            pkg-config
          ];
          shellHook = ''
            export CC=clang
            export CXX=clang++
          '';
        };
      }
    );
}