VSCode clangd extension can not find header file
Asked Answered
O

1

12

My current file structure is:

├── common
│   └── example.cc
├── compile_commands.json
├── include
    └── common
        └── example.hh

example.hh: Leave it blank

example.cc:

#include "common/example.hh"

int main() {
    return 0;
}

compile_commands.json:

[
    {
        "directory": "/home/user/project",
        "file": "/home/user/project/common/example.cc",
        "arguments": [
            "/usr/bin/clang++",
            "-I /home/user/project/include",
            "-o example",
            "/home/user/project/common/example.cc"
        ],
        "output": "example"
    }
]

When opening example.cc it produces error:

'common/example.hh' file not found clang(pp_file_not_found)

I run the command directly and it works fine:

$ /usr/bin/clang++ -I /home/user/project/include -o example /home/user/project/common/example.cc

Environment info:

$ clang++ --version
clang version 10.0.0-4ubuntu1 
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

vscode: 1.47.3

vscode-clangd: 0.1.7

Oncoming answered 8/9, 2020 at 5:30 Comment(1)
What's the result now?Bowra
F
2

The problem is that in the "arguments" field of the compile_commands.json entry, "-I /home/user/project/include" is a single argument. (So is "-o example" though that doesn't cause any harm in this case.)

That means the command that's executed will be as if you had written:

$ /usr/bin/clang++ "-I /home/user/project/include" "-o example" /home/user/project/common/example.cc

(note the quotes around "-I /home/user/project/include" and "-o example").

If you run that command, that gives the same 'common/example.hh' file not found clang(pp_file_not_found) error. Basically, the quotes make clang think that the argument to -I starts with a space character, which then does not resolve as a path.

The solution is to place each token of the command line in a separate element of "arguments":

[
    {
        "directory": "/home/user/project",
        "file": "/home/user/project/common/example.cc",
        "arguments": [
            "/usr/bin/clang++",
            "-I",
            "/home/user/project/include",
            "-o",
            "example",
            "/home/user/project/common/example.cc"
        ],
        "output": "example"
    }
]

The reason "arguments" is interpreted in this way is that the format specification for compile_commands.json describes "arguments" as follows:

arguments: The compile command argv as list of strings. This should run the compilation step for the translation unit file. arguments[0] should be the executable name, such as clang++. Arguments should not be escaped, but ready to pass to execvp().

Basically, "arguments" are expected to be the command line arguments as a shell would parse them and pass them to the argv of a program. Since arguments are space-separated, the only way a single argument can contain an internal space is if that argument was quoted on the command line.


Finally, I'll note that compile_commands.json files are generally not meant to be written by hand, but instead generated by a tool (usually your project's build system or something related). See https://clangd.llvm.org/installation#project-setup for a list of commonly used tools to generate them.

If you must hand-write a compile_commands.json, it's probably easier to use "command" instead of "arguments" (refer to the spec for an example), precisely to avoid issues like this.

Furst answered 8/7, 2022 at 5:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.