Hi,
I deal with a codebase which follows the following pattern:
-
A.hpp
defines the type signatures.
-
A.hxx
defines the templated definitions, and is included at the bottom of A.hpp
. Logically, A.hpp
and A.hxx
together form the “header” for A
.
-
A.cpp
defines the non-templated definitions.
The problem is that, while using clangd
, A.hxx
will contain spurious errors since it’s usually compiled just by being included from A.hpp
, but it doesn’t really makes sense on its own (it has no includes itself, for example).
Is there a way to specify that A.hpp
and A.hxx
files should be basically treated as one thing? So that I can use clangd
with them.
Thanks,
Francesco
- A.hxx depends on A.hpp, and so should include it at the top.
- both are headers and should be include-guarded
// a.hpp
#ifndef A_HPP
#define A_HPP
template <int> void x();
#include "a.hxx" // IWYU pragma: export
#endif
// a.hxx
#ifndef A_HXX
#define A_HXX
#include "a.hpp"
template <int> void x() {}
#endif
Clangd will print a spurious header (main file cannot be recursively included) - this is a clangd bug - looks like Header-only library recursively including main file · Issue #337 · clangd/clangd · GitHub isn’t completely fix.
However it’s just one error, and all features should work.
HTH
Actually, that bug seems to be fixed in 15.0.2.
However, this requires me to modify all such files. Which might actually be feasible, but still kinda inconvenient.
I actually attempted to use the Compiler
config directive to have a wrapper which automatically adds a couple of lines those files. But that config directory seems to not affect clangd
, at least in my tests.
Sorry, clangd only supports standalone files, including headers.
I understand, I was trying to look for a way to preprocess those files transparently adding the right include.
Actually, while including from A.hxx
does make A.hxx
work, it then generates spurious errors in A.hpp
.
Given
% tail -n +1 *
==> A.hpp <==
#pragma once
class A {
int blah();
};
#include "A.hxx"
==> A.hxx <==
#pragma once
#include "A.hpp"
int A::blah() {
return 42;
}
I get error
[{
"resource": "/home/fmazzol/scratch/test-clangd/A.hpp",
"owner": "_generated_diagnostic_collection_name_#0",
"code": "redefinition",
"severity": 8,
"message": "In included file: redefinition of 'A'",
"source": "clang",
"startLineNumber": 7,
"startColumn": 10,
"endLineNumber": 7,
"endColumn": 17,
"relatedInformation": [
{
"startLineNumber": 3,
"startColumn": 7,
"endLineNumber": 3,
"endColumn": 8,
"message": "Error occurred here",
"resource": "/home/fmazzol/scratch/test-clangd/A.hpp"
},
{
"startLineNumber": 3,
"startColumn": 10,
"endLineNumber": 3,
"endColumn": 17,
"message": "'/home/fmazzol/scratch/test-clangd/A.hpp' included multiple times, additional include site here",
"resource": "/data/home/fmazzol/scratch/test-clangd/A.hxx"
}
]
}]
Possibly clangd
looks at each file in isolation, and then incorrectly derives that class A
is defined twice, because they both do? Even if A.hxx
would never be included anywhere else.
Actually, the problem does not seem to be specific to clangd – I’m investigating further…
FWIW your example doesn’t produce any diagnostics for me in a recent clangd.
@sam-mccall indeed, it does seem to work with 15.0.2. Thanks again for your help.