Open Falven opened 3 years ago
Just saw this thread.
I think adding the --compile-commands-dir=
partially solves the issue, however, when analyzing a cpp file that includes a header for a compilation unit not in your compilation database, clangd
seems to still try to compile it with clang
and fallback arguments as the intellisense errors that are produced seem consistent with that.
I think we need a better solution here, clearly this affects a lot of end-users.
Just saw this thread. I think adding the
--compile-commands-dir=
partially solves the issue,
Yep, I would recommend using that. You can also do it using config as described here.
however, when analyzing a cpp file that includes a header for a compilation unit not in your compilation database,
clangd
seems to still try to compile it withclang
and fallback arguments
I'm not following this part. A command applies to the whole translation unit, so if you open a cpp file, the contents of the entire translation unit (including all included headers) are analyzed using the same command.
If you open a header file, the header file is analyzed as its own translation unit, but if you're using --compile-commands-dir
, clangd should still find a command from the database to get flags for it.
Just saw this thread. I think adding the
--compile-commands-dir=
partially solves the issue,Yep, I would recommend using that. You can also do it using config as described here.
Using a project config won't work for my scenario, because the file in question, Arduino.h
, is not a part of the project, so clangd
will never find the configuration as it searches in parent directories of the Arduino.h
file. Using a user-level config doesn't seem like a good solution either as this particular configuration is project-specific. However, as I mentioned, using the argument "--compile-commands-dir=${workspaceFolder}\\build",
in my VS Code workspace settings seems to work. It allows clangd
to infer the correct compilation command when navigating to Arduino.h
.
That is a very subtle change to get compilation command inference working. I think it should be enabled by default, as long as clangd
finds a CDB. If not, then at a minimum all of the ways to configure this should be documented in clangd
configuration page.
however, when analyzing a cpp file that includes a header for a compilation unit not in your compilation database,
clangd
seems to still try to compile it withclang
and fallback argumentsI'm not following this part. A command applies to the whole translation unit, so if you open a cpp file, the contents of the entire translation unit (including all included headers) are analyzed using the same command.
If you open a header file, the header file is analyzed as its own translation unit, but if you're using
--compile-commands-dir
, clangd should still find a command from the database to get flags for it.
Maybe this is a bug or a false-positive, but that does not seem to be what I am observing. I am observing a large mismatch between clangd
output and the compiler output.
clangd
will correctly infer the following compilation command from the CDB:
If we remove the --target=arm-none-eabi --driver-mode=g++ -resource-dir=
flags, add --verbose
and execute this compilation command in the terminal, we get no errors, warnings, or diagnostics; indicating a successful compilation:
If we take a look at the clangd
output, we can see it reports using the correctly-determined compilation database and it correctly infers the compilation command:
However, it falsely reports errors that spill over to other code in the file and make development impossible.
These errors that are being emitted above, to me, smell like a bug with clangd
trying to compile that header with clang
instead of the command used for the compilation unit. I don't know what else it could possibly be as the command clearly works in the terminal, but not when clangd
executes it.
i believe the piece missing here is the command line generated by clangd is not executed as-is it is used to create a clang compiler instance. hence the need for deleting --driver-mode or --resource-dir when invoking the command as-is, because these won't work with gcc.
as mentioned in a separate topic the diagnostic for anon bit field qualifiers
is a real error for C++. You can compare https://en.cppreference.com/w/cpp/language/bit_field vs https://en.cppreference.com/w/c/language/bit_field (I know cppreference is not authoritative for the spec but it is close enough), basically this is allowed in C, but not in C++.
so unless there are some builtin macros clang is failing to infer (which is a shortcoming of custom toolchain support, if a compiler has magical builtin macros clang(d) can't really know about them and there's no good way to communicate those today), this must be an extension of gcc. We can diagnose this better if you can provide the contents from the ac.h
around line 241 (as indicated by clang's error).
i believe the piece missing here is the command line generated by clangd is not executed as-is it is used to create a clang compiler instance. hence the need for deleting --driver-mode or --resource-dir when invoking the command as-is, because these won't work with gcc.
I see. I couldn't find those commands on the documentation for arm-none-eabi-g++
, so that makes sense.
as mentioned in a separate topic the diagnostic for
anon bit field qualifiers
is a real error for C++. You can compare https://en.cppreference.com/w/cpp/language/bit_field vs https://en.cppreference.com/w/c/language/bit_field (I know cppreference is not authoritative for the spec but it is close enough), basically this is allowed in C, but not in C++.
Yes, I realize it is a real error. Obviously though, it compiles fine using arm-none-eabi-g++
so there is some bug with clangd
where the cross compilation is not working correctly.
so unless there are some builtin macros clang is failing to infer (which is a shortcoming of custom toolchain support, if a compiler has magical builtin macros clang(d) can't really know about them and there's no good way to communicate those today), this must be an extension of gcc. We can diagnose this better if you can provide the contents from the
ac.h
around line 241 (as indicated by clang's error).
I am not an expert on this low-level stuff, to be honest, so I really appreciate all the help you can give; this is also why I am using Arduino and not developing down to the metal for SAMD 😁.
It seems to me like the basic types for SAMD are somehow missing. Or this could be a false positive?
This is probably about the definition of __I
macro. You can check where it is defined to see if there's anything interesting.
This is probably about the definition of
__I
macro. You can check where it is defined to see if there's anything interesting.
It sounds like you may have a good idea of what is going on. I did notice that this ac.h
file never includes stdint.h
but that shouldn't be a problem, right? But are you expecting the compiler to be modified to work with clangd
?
I found where __I
is defined.
I may have found the bug. It can't include _stdint.h
... even though it is in the include path.
Does this have something to do with --sysroot
?
but it didn't change anything.
This seems to potentially be the first error that causes all others.
Sorry feels like this is getting messier and away from land of clangd. First of all, clangd would provide really poor results on those internal headers without a proper project setup for those. It is fine to include them in another project as they can usually be compiled as part of your project with good compile flags clangd has access to, but if you open them directly story changes a lot since the flags are usually from far away directories and even more those headers are not necessarily self-contained (e.g. they are only meaningful as part of a bigger translation unit that includes a bunch of other code before that particular header).
I was suggesting the location of __I
but don't see anything around that in your last message. It is probably the case that __I
is defined with a cv-qualifier in some configs and without in others (by depending on some macros). I was suggesting you figure out which branch clangd should use and find out why it is not using that one.
Sorry feels like this is getting messier and away from land of clangd. First of all, clangd would provide really poor results on those internal headers without a proper project setup for those. It is fine to include them in another project as they can usually be compiled as part of your project with good compile flags clangd has access to, but if you open them directly story changes a lot since the flags are usually from far away directories and even more those headers are not necessarily self-contained (e.g. they are only meaningful as part of a bigger translation unit that includes a bunch of other code before that particular header).
Right, I don't specifically care about errors from clangd when I open non-project files, but unfortunately these errors spill over to any of my code and cause all sorts of false positives on basic stuff like initializing strings. It is pretty much unusable. Again I don't understand if the project files compile fine with G++
why should it be any different with clangd
intellisense? Why does clangd
show any errors? Does clangd
aggressively try to compile files that are not part of the project or included, even when I don't open them? It makes no sense.
I was suggesting the location of
__I
but don't see anything around that in your last message. It is probably the case that__I
is defined with a cv-qualifier in some configs and without in others (by depending on some macros). I was suggesting you figure out which branch clangd should use and find out why it is not using that one.
I'll keep looking, I guess...
Does
clangd
aggressively try to compile files that are not part of the project or included, even when I don't open them?
I'm sure you're aware that C and C++ compilers operate at the level of "translation units". That is to say, while a compilation command may only be given one input file, any #include
-ed files need to be read as well, and the declarations inside them processed by the compiler. Clangd is no different: it needs to process the declarations in headers to be able to correctly process the declarations in the main file.
but unfortunately these errors spill over to any of my code and cause all sorts of false positives on basic stuff like initializing strings.
That's just it: even if you suppress the errors coming from the headers, not being able to correctly parse the declarations in the headers will mean not being able to correctly handle code in the main file which uses those declarations.
If clangd can't find a compilation command in the compilation database, as is common for, say, header files included in your source files, it will fallback to calling the
clang
executable along with any flags you define inclangd.fallbackFlags
. However, this does not support cross compilation scenarios. I need to be able to specify theclangd.fallbackCommand
.I think another, better, way to address this would be to modify
compile_commands.json
to allow "fallback" commands that work for all files and other commands can extend. This would actually simplifycompile_commands.json
as well, such that you don't have to repeat arguments to each file you would like to compile.Example: Before:
After:
Granted this example was contrived rather quickly.
Logs
System information PS C:\source\repos\clangd-arduino> clangd --version clangd version 11.0.0 Editor/LSP plugin: VS Code Operating system: Windows 10