Open Krasjet opened 2 years ago
The path is correct. A precompiled header must be precompiled.
"command": "c++ -Ihello.p [...] -fpch-preprocess -include hello_pch.hpp [...]",
When it sees -include hello_pch.hpp
, it checks every include directory for a file named hello_pch.hpp .gch, including:
The second location is a path match. Attempting to include ../pch/hello_pch.hpp
would mean that the precompiled headers simply would never be found at all, ever, because that path cannot be resolved as a pch file.
This is strange. It seems that clangd
cannot provide any diagnosis information based on the .gch
/.pch
file alone.
Here is an equivalent example with cmake
:
.
├── hello.cpp
├── CMakeLists.txt
└── pch
└── hello_pch.hpp
pch/hello_pch.hpp
#include <iostream>
hello.cpp
int main()
{
std::cout << "hello, world!\n";
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(hello LANGUAGES CXX)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_executable(hello hello.cpp)
target_precompile_headers(hello PUBLIC pch/hello_pch.hpp)
After building the project, clangd
has no problem providing diagnosis info using the generated compile_commands.json
$ mkdir build && cd build
$ CXX=clang++ cmake ..
$ make
[
{
"directory": "/pch_cmake/build",
"command": "/usr/bin/clang++ -Winvalid-pch -fpch-instantiate-templates -Xclang -emit-pch -Xclang -include -Xclang /pch_cmake/build/CMakeFiles/hello.dir/cmake_pch.hxx -x c++-header -o CMakeFiles/hello.dir/cmake_pch.hxx.pch -c /pch_cmake/build/CMakeFiles/hello.dir/cmake_pch.hxx.cxx",
"file": "/pch_cmake/build/CMakeFiles/hello.dir/cmake_pch.hxx.cxx"
},
{
"directory": "/pch_cmake/build",
"command": "/usr/bin/clang++ -Winvalid-pch -Xclang -include-pch -Xclang /pch_cmake/build/CMakeFiles/hello.dir/cmake_pch.hxx.pch -Xclang -include -Xclang /pch_cmake/build/CMakeFiles/hello.dir/cmake_pch.hxx -o CMakeFiles/hello.dir/hello.cpp.o -c /pch_cmake/hello.cpp",
"file": "/pch_cmake/hello.cpp"
}
]
Notice that here cmake is actually including a new generated header called cmake_pch.hxx
/* generated by CMake */
#pragma clang system_header
#ifdef __cplusplus
#include "/pch_cmake/pch/hello_pch.hpp"
#endif // __cplusplus
Without it, clangd
cannot find the includes from hello_pch.hpp
. Is it possible to do something similar with meson?
p.s. I noticed that clangd
is not compatible with gcc
-generated pre-compiled headers, though after switching to clang
, the meson example still doesn't work. The new compile_commands.json
is
[
{
"directory": "/pch/build",
"command": "clang++ -Ihello.p -I. -I.. -fcolor-diagnostics -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -O0 -g -MD -MQ hello.p/hello_pch.hpp.pch -MF hello.p/hello_pch.hpp.pch.d -o hello.p/hello_pch.hpp.pch -c ../pch/hello_pch.hpp",
"file": "../pch/hello_pch.hpp",
"output": "hello.p/hello_pch.hpp.pch"
},
{
"directory": "/pch/build",
"command": "clang++ -Ihello.p -I. -I.. -fcolor-diagnostics -include-pch hello.p/hello_pch.hpp.pch -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -O0 -g -MD -MQ hello.p/hello.cpp.o -MF hello.p/hello.cpp.o.d -o hello.p/hello.cpp.o -c ../hello.cpp",
"file": "../hello.cpp",
"output": "hello.p/hello.cpp.o"
}
]
This seems to be related to https://github.com/clangd/clangd/issues/856 and https://github.com/clangd/vscode-clangd/issues/324.
Tools like clangd explicitly disable all PCH usage (e.g. see https://github.com/llvm/llvm-project/blob/96f303324f58a58a7e58d75f797793c66606e745/clang-tools-extra/clangd/Compiler.cpp#L61-L68), so these kinds of PCH includes in compile_commands.json
will just be ignored, which will break any language server features involving these headers.
Would it maybe be possible for meson to replace such -include-pch
directives with -include
directives pointing to the original (not precompiled) headers when generating compile_commands.json
?
No, because meson doesn't produce compile_commands.json, it simply instructs ninja to emit one based on the ninja rules.
Is this being fixed? What is the recommended workaround? I use VSCode C/C++ extension and has the same problem. Currently have to add
#if __INTELLISENSE__
#include "pch/pch.h"
#endif
at the top of every file, which is not good. And I think it only works for the C/C++ extension, not every other language server like clangd.
If it helps, I ended up just using a manually written sed
command to patch my compile_commands.json
after every reconfigure... It's stupid but at least it works.
Thanks. Just wrap the meson setup
in a script that adds -include ../pch/pch.h
works. Ugly though.
Describe the bug The
-include
path for precompiled headers incompile_commands.json
file does not include parent directories. Because the path is incorrect,clangd
cannot find any headers specified in the precompiled header file and hence cannot provide any completions and diagnoses for those headers.To Reproduce
The files and directory layout are as follows
pch/hello_pch.hpp
hello.cpp
meson.build
Notice that the precompiled header needs to be placed in a different directory as the source file, as mentioned in the documentation.
After building the project
There will be a
compile_commands.json
file generated in thebuild
directory.Notice that for the
command
ofhello.cpp
, the include flag is-include hello_pch.hpp
, but the precompiled header is not present in thebuild
directory.Expected behavior
Either
-include pch/hello_pch.hpp
or-include ../pch/hello_pch.hpp
should be generated incompile_commands.json
.system parameters
meson --version
ninja --version
if it's a Ninja build