Hi,
I’m working on a Linux environment with a self-configured GCC. This GCC is built from scratch, without any patch from distro vendor. Then I’m trying to use Clangd alone on this platform, only to find that Clangd would emit error about missing include header ‘limits.h’.
The error occurs at /usr/include/limits.h
, where this header is using #include_next <limits.h>
to include next limits.h
in system headers.
I tried to provide Clangd with correct -resource-dir
but nothing works. I noticed that this “missing” header ‘limits.h’ is located in this include-fixed
dir. I then did some research and found this trying to explain why GCC would like to put some headers in this quirk dir.
I’ve also looked into GCC build script of CentOS. It looks like I should copy these limits.h
files from include-fixed
to include
dir directly. But even without this step, GCC that built from scratch still works on my system. I found that this is because GCC would search this include-fixed
dir. Then it comes to me that maybe Clang did not handle this case:
I did a rough look on Clang Driver, and It appears to me that clang/lib/Driver/ToolChains/Linux.cpp:AddClangSystemIncludeArgs
is where Clang injects search dirs. (See here on trunk).
// Add 'include' in the resource directory, which is similar to
// GCC_INCLUDE_DIR (private headers) in GCC. Note: the include directory
// contains some files conflicting with system /usr/include. musl systems
// prefer the /usr/include copies which are more relevant.
SmallString<128> ResourceDirInclude(D.ResourceDir);
llvm::sys::path::append(ResourceDirInclude, "include");
if (!DriverArgs.hasArg(options::OPT_nobuiltininc) &&
(!getTriple().isMusl() || DriverArgs.hasArg(options::OPT_nostdlibinc)))
addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
The logic here did not handle the case of include-fixed
. I patched this code like this and rebuilt Clangd, then it works like a charm.
SmallString<128> ResourceDirInclude(D.ResourceDir);
llvm::sys::path::append(ResourceDirInclude, "include");
SmallString<128> ResourceDirIncludeFixed(D.ResourceDir);
llvm::sys::path::append(ResourceDirIncludeFixed, "include-fixed");
if (!DriverArgs.hasArg(options::OPT_nobuiltininc) &&
(!getTriple().isMusl() || DriverArgs.hasArg(options::OPT_nostdlibinc))) {
addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
addSystemInclude(DriverArgs, CC1Args, ResourceDirIncludeFixed);
}
So my question is, can anyone explain the reason behind this? I don’t know if this is by intention. If not, is this the correct way to fix this?
My environment detail is as follows:
OS: CentOS 7 with GCC 7.5 built from source.
$ gcc --print-search-dirs
install: /usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.5.0/
$ gcc -v
gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/bin/../libexec/gcc/x86_64-pc-linux-gnu/7.5.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../gcc-7.5.0/configure --prefix=/home/qspace/install_tools/gcc7/install --with-dwarf-2 --disable-libstdcxx-dual-abi
Thread model: posix
gcc version 7.5.0 (GCC)
Clangd: Built from source, without any other components.
Running test:
// test.cpp
#include <limits.h>
$ clangd --resource-dir=/usr/local/lib/gcc/x86_64-pc-linux-gnu/7.5.0/ --check=test.cpp
Without my patch, it emits:
E[01:14:35.533] [pp_file_not_found] Line 1: in included file: 'limits.h' file not found
I[01:14:35.536] All checks completed, 1 errors
After my patch:
I[01:15:13.054] All checks completed, 0 errors