Find standard C/C++ library include directories for libclang

I’m using libclang to parse some C++ code. It seems that libclang has no default include path so I need to provide them. Is there a way to locate the C/C++ stdlib include paths for current nix-shell and, say, export them as an environment variable?

The source code is a mess and I cannot easily generate a compile_commands.json so the method listed at Get clangd to find standard headers in nix-shell - #12 by danielbarter probably won’t work.

Yes, if you look in ${clang}/nix-support, there are text files that contain all the system compilation flags that are used by the wrapper. What you need should be in there

1 Like

you can probably use bear to generate such a file.

Bear does not work particularly well with nix because it struggles to distinguish the compiler wrappers from the compilers themselves (at least last time I tried using it). The project @yipengsun links to is a simple bear like program that works with nix, but rather than listening to system calls, it instruments the compiler wrappers.

Thank you! I think libc-cflags and libcxx-cxxflags are probably what I’m looking for.

For the record, here’s what I’m doing to find C/C++ standard headers:

import subprocess

from glob import glob
from pathlib import Path

import chardet


def decodeStdout(proc):
    stdout, _ = proc.communicate()
    enc = chardet.detect(stdout)
    return stdout.decode(enc["encoding"])


def findCCppStdHeadersNix():
    # find clang
    process = subprocess.Popen(
        ["which", "clang"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
    )
    clangPath = Path(decodeStdout(process).strip())
    clangFlagsPath = clangPath.parent.parent / "nix-support"

    with open(clangFlagsPath / "libcxx-cxxflags") as f:
        flag = f.read().strip()
    cppHeader = flag.split(" ")[1]

    with open(clangFlagsPath / "libc-cflags") as f:
        flag = f.read().strip()
    cHeader = flag.split(" ")[1]

    # need bits/c++config.h
    bitsCppConfig = glob(f"{cppHeader}/**/bits/c++config.h", recursive=True)[0]
    bitsCppConfig = Path(bitsCppConfig).parent.parent

    # need stddef.h, a compiler-specific header
    process = subprocess.Popen(
        ["gcc", "--print-file-name=include"],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    stddefHeader = decodeStdout(process).strip()

    return [
        cppHeader,
        cHeader,
        stddefHeader,
        str(bitsCppConfig)
    ]