I have a CMake configured project with everything set up.
Everytime I open a header file from the project I get a popup-warning with "unable to provide IntelliSense configuration information".
I guess this is due to header files not being in the compilation database. However "associated" headers can be fit with the same information as their source files (foo.h/hpp and foo.c/cpp), especially when they are in the same folder. And headers in the same path usually also share the same options. Maybe add an option to control how fuzzy the matching is?
Thank you for you work on the cool new update @vector-of-bool !
The message text: CMake Tools' is unable to provide IntelliSense configuration information for '/home/xxx/yyy/zzz.hpp'. Settings from the 'Linux' configuration will be used instead., plus there is a dialog from IntelliSense: Configure your IntelliSense settings to help find missing headers.
I usually split headers and sources into src/ and include/ folders, so it may be a bit tricky to handle. I wonder what would be a proper configuration for such headers. Maybe adopting the configuration of any of the sources that include it would suffice.
Are your header files listed in the CMakeLists.txt? CMake Tools won't be able to provide the configurations unless those files are included in your CMakeLists.txt.
I came across this issue too. I personally don't divide my headers into an Include folder, but I always #include my headers relative to the root of my Source folder by doing the following:
set(PROJECT_INCLUDE_PRIVATE Source/)
set(PROJECT_SOURCES Source/main.cpp Source/Something/other.cpp)
set(PROJECT_HEADERS Source/Something/other.hpp)
source_group("Sources" FILES ${PROJECT_SOURCES})
source_group("Headers" FILES ${PROJECT_HEADERS})
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_INCLUDE_PRIVATE})
Notice I only use my ${PROJECT_HEADERS } variable for the source_group and the compiler is actually finding them by adding my Source directory to the include path. It seems that currently CMake Tools can't currently provide configuration for my headers that are only included through my target_include_directories.
I found that if I add ${PROJECT_HEADERS } to add_executable (ie. add_executable(${PROJECT_NAME} ${PROJECT_SOURCES} ${PROJECT_HEADERS})) then the intellisense works.
I agree though, hopefully there would be a way for intellisense to be provided for files in my include path.
@bobbrow I don't list the headers in the CMakeLists.txt. I am a lazy one, so similarly to @BJMH, I tend to do just something like:
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
instead of managing the includes in both .cpp file and CMakeLists.txt. (Otherwise, the CMakeLists could grow enormously, e.g., managing the headers of https://github.com/ericniebler/range-v3 twice seems kind of dirty.). CMake seems to be smart enough to detect the dependencies between sources and headers automatically during the first build and when a header changes, only those sources that include it are rebuilt.
@bobbrow is correct: CMake won't know about the headers unless they are attached to a target. Doing a "best match" is possible but very error-prone.
CMake actually doesn't do any work to detect header dependencies: that's up to the build tool (Make/Ninja/MSBuild), so CMake is truly completely unaware of the header files.
@vector-of-bool Good to know, thanks. So I added all headers to all executable/library targets and the error is gone and when I change a header Make/Ninja are still smart enough to rebuild only the targets that really include it, great.
Unfortunately, I have a lot of "IntelliSense include errors". The reason is that some of my executable/library targets are linked against e.g., Eigen, whose headers reside in /usr/include/eigen3. The executable/library targets properly include${EIGEN3_INCLUDE_DIRS}, so .cpp have no "IntelliSense include errors", but when a .hpp file needs some eigen header, IntelliSense does not know where to look.
.cpp file has no include errors:

.hpp file has include errors:

So the problem is - .cpp files take CMake settings and flags into account and .hpp files do not. I am not really sure how to solve/workaround it. Any ideas?
@vector-of-bool , thanks for the extension. Actually, I am having the same problem as @FloopCZ 's . I have some modules providing header-only library. In the CMakeLists.txt, I put:
target_include_directories(${LIBNAME} PUBLIC include)
Then, other modules will include those library header files in their source files. For cmake to lookup the include path, in CMakeLists.txt, I put:
target_link_libraries(${EXENAME} ${LIBNAME})
In vscode, .cpp files are working fine but .hpp files are having include errors.
Ok so one problem is that CMake is not aware of the headers. Adding the headers in the CMakeLists cannot be done (either because they are transitive from other libs or because project owners will refuse to clutter the CMakeLists for the sake of IDE compatibility, I dislike that too but that's what at least I have to deal with)
So one solution: Using heuristics to get a cpp file that IS present in CMake and return those flags.
Another one: The C++ extension allows to use the compile_commands.json. That seemed to work. Maybe a better way would be to have the CMakeTools make sure this database is created and the C++ extension finds it?
Actually, I have added those header files in my target too. In the cmake project outline of vscode, it can list out all my header files. So, I am not quit sure if CMake is aware of the headers or not. And 1 more observation is that vscode can still parse those library header files and perform auto-completion even it is showing "include error"
Just to clarify:
Adding the headers in the CMakeLists cannot be done.
It can be done, but it does not help. The headers do not adopt the compilation flags from the sources that include them. So if a header includes some header file not directly in e.g., /usr/include (e.g., Eigen), IntelliSense is not able to find it. No transitivity needed.
Another one: The C++ extension allows to use the compile_commands.json. That seemed to work.
For me, this did not work with header files as well, but it did not complain with a pop-up. This happens only with the configurationProvider option. Previously, a small light bulb showed up when hovering the cursor over the affected line:

(Note that the pop-up can be disabled, of course, but it would be pretty cool to find a way for IntelliSense to work even in header files and header only libraries).
So one solution: Using heuristics to get a cpp file that IS present in CMake and return those flags.
I believe that IntelliSense by itself does something similar when not provided with the configurationProvider. A good heuristic might be e.g., to adopt the flags of the first target that includes the given header (unfortunately, this would also work only if the headers are manually added to the CMakeLists, but better than nothing).
Another observation:
Given that there are source files src/main.cpp and src/Foo.hpp,
a) main.cpp includes Foo.hpp
b) Foo.hpp includes other internal library header files
Then,
@danleepw Info I got from the MS team (C++ ext) is, that they parse files outside browse.path only when they are open in an editor. So it seems what is happening is: Parser parses main.cpp and Foo.hpp with it -> Symbols available. Opening Foo.hpp alone will try to initially parse it w/o any flags and fail.
Probably adding its (both) paths to browse.path would solve this. (Maybe not, if configurationProvider is used)
@Flamefire, your explanation seems correctly. Qtcreator provides a dropdown box for user to select the compile target to determine the parsing parameters of header files. In vscode, opening the cpp file is acting the similar effect, I guess.
@FloopCZ , could you pls try to open the cpp file and then the hpp file to see if my observation can be re-produced in your setup?
If foo.cpp and foo.hpp are source files of the same target, they should both receive the same configuration information, so foo.hpp should be fine.
If you have a main.cpp for myexe that includes a foo.hpp, where foo.hpp is a member of a _different_ library target (we'll call it libfoo), and that foo.hpp includes an external header (such as Eigen), then the include directories for Eigen etc. should be set on libfoo, not on myexe. myexe will link to libfoo and inherit its include directories for Eigen etc.
If all of the above conditions are satisfied, then it would seem to be a bug either in CMT or cpptools. @bobbrow do you think there's anything in cpptools that could make this mistake?
If you set "C_Cpp.loggingLevel": "Debug" and then reload the window cpptools will print out the include paths we are using for your translation units when they opened in the editor. If those paths are correct and you're still seeing errors, then it is a cpptools issue. If the paths are not correct, it would seem to be a CMT issue.
I can confirm @danleepw's observation about the ordering of opening files. cpptools tries to share translation units with as many files as possible to reduce inefficiencies. So if you open a .cpp first, and then a header included by that .cpp, cpptools will ignore the configuration for that header and use the .cpp's configuration instead (e.g. they will share the IntelliSense process). If you open the header first and there is no config information coming from CMT, then cpptools will make a best effort to configure that header for IntelliSense, but it can't always do the "right" thing.
CMakeToolTest.tar.gz
Hi @vector-of-bool and @bobbrow , I have attached a cmake project for your reference. As you can see in the project, main.cpp and Foo.hpp in folder "Foo" are source files of exe "foo". Exe "foo" is using an internal library "libbar"
I enabled "C_Cpp.loggingLevel": "Debug" to test the behavior:
1) If i open main.cpp of Foo just after reload, the log shows include path "libbar/include"
2) If i open Foo.hpp of Foo just after reload, the log doesn't show include path "libbar/include"
Another question: I set the c++ std to be c++11 in cmake. However, the cpptool log shows "stdver: --c++17"
Thanks for the test case. Your CMakeLists.txt looks like it should work. I'll investigate.
I've found the issue an a work-around/fix:
The issue: CMake Server reports back files in "groups" of fileGroups, where files with common configs are grouped together. Turns out that header files have no associated includePath or compileDefinitions or anything else like that.
The workaround/fix: Since individual source files can have different include paths or options, I can't just give _all_ files in a target the same options. What I _can_ do is set a "default" includePath per-target if one is not defined for a file. This is the workaround/fix: Before building the data for each group, I find all the includes/defines/options for each group and consider them as the "default" for that target. Any files that don't have an includePath/compileFlags/defines will receive this "default."
Just for understanding: You set those defaults for the target and expect, that the header files are associated with a target (as in: added to a CMake target along with the source files)?
What about external headers, header-only libraries or libraries where the headers are not added to CMake targets (as mentioned: Some projects don't allow adding headers to targets as that is "only" for IDEs)?
I actually like the idea that headers get their flags from the first cpp file that (transitively) includes them. Eagerly parsing all cpp files would mean that all headers are parsed correctly too.
Some background information about how cpptools works:
browse.path variable.browse.path variable and included by another file that was eagerly parsed.browse.limitSymbolsToIncludedHeaders is false, we eagerly parse every file reachable by the paths in the browse.path variable.Note that this parsing does not have a preprocessor and when building up a map of included files it will make mistakes when #if/#ifdef/etc blocks would normally exclude a header.
When a source file is opened in the editor we do the following (in order) to try to get a language server:
c_cpp_properties.json and create a new LS.The biggest flaw I see in the current system when dealing with STL/header-only libraries is step 3 because if cpptools picks a translation unit whose configuration could be but hasn't been served by CMT yet, it will be misconfigured. I've also been thinking about simply ditching the include map because I don't think there will be any significant side effects (if a .c* file is opened later that includes the header, the header's LS will be disposed in favor of the "better" one), but we need to test it out and see how it performs. Creating LS's is a slow operation so we avoid doing it whenever we can. There may be some middle ground we can find by perhaps restricting the map's depth to 1 - since if you open a.h and a.cpp exists right next to it, it's probably safe to assume that a.cpp is the best match for it and should be chosen as the translation unit for the LS.
For now, the most reliable thing to do is open .c* files before the dependent .h* files, but we recognize that this isn't always how people develop software, so we're thinking about ways to make this better (it affects us too).
CMT will _only_ provide information for source files that are associated with a target. External headers will not have any config information. Header-only libraries is an interesting problem because there will be no source files from which to grab the compilation information directly. Of course, a test file might include the file which can be used to infer the config, but that's not always available.
We eagerly parse files outside your workspace if they are referenced in the browse.path variable and included by another file that was eagerly parsed.
How does this work together with CMT? AFAIK CMT does not set the browse.path, so does that mean, one would still have to set browse.path manually? If so, could CMT add all paths of files, that are associated with a CMake target to browse.path automatically? Or maybe at least all include folders? Wouldn't that solve most of the problems already?
CMT will only provide information for source files that are associated with a target.
Then what about the standard header files (<iostream>, <memory>...)? These are also "header-only libraries", although special ones. But they could be handled the same way: They get their flags from the first Cpp file found to include them.
I have exactly the same problem.
It could be a great improvement to solve this issue :)
@vector-of-bool The problem still exists or reappeared: I have a Foo.cpp file and a Foo.hpp file in the same folder. VSC reports "No configuration for Foo.hpp" and fails to provide information on that completely failing the intellisense (LOTS of errors)
Foo.cpp is mentioned in the CMakeLists, Foo.hpp is not. I though eadae98 was supposed to fix this?
Is there any debug logging for CMT to check where it fails?
@Flamefire @camelator I'm sorry for the delay on this issue! I know its an important one. I've been busy with several projects for a few weeks.
The linked commit, while merged into develop, has not yet been released. This will be fixed in 1.1.2. I have the release branch open, but I have a few pending fixes that need to be included.
I've just been really busy with several community projects this month, and a full-time job eats a lot of my time. This has been a recurring theme that I periodically fall behind on CMT issues as other things being to take precedent. Sorry about that!
Thanks for the clarification. Could you then modify the milestone of this? It is set to 1.1.1 which is why I assumed that it must be part of that.
Wait, no... It looks like I am wrong. It appears that the fix _should_ be present in the current release. Is this still going on??
@vector-of-bool Thank you for looking into this. Yes, this is still happening for me. I still see errors like Configure your IntelliSense settings to help find missing headers. and #include errors detected. Please update your includePath. in my header files.
It gets better if I also open a .cpp file that (even indirectly) includes the header (but sometimes the only .cpp file that imports the header is one of the unit tests, so it is kind of uncomfortable workaround).
Yes, same here
Seeing this as well for standard C++ includes.
It seems the current vscode-cpptools configuration provider does use the compiler's system header paths for IntelliSense by default. So it seems like CMake Tools could just use the configured compiler/kit's include path to at least recognize system headers as well? I noticed in a comment above that the current extension just scans for header files explicitly called out int the CMakeLists file.
Actually my above comment relates to #546.
In the case where CMT does not provide a configuration for a source file, cpptools will use whatever settings are in the includePath, defines, and compilerPath to provide IntelliSense. If you want to guarantee a specific set of system includes/defines are used, you would need to set the compilerPath in your c_cpp_properties.json to match the Kit selected. Perhaps we can update the provider API to allow CMT to provide a "default" configuration (which might just be the compilerPath).
I'm running into this issue as well, but only for transitive includes (e.g. A includes a header from B/inc, and B/inc includes a header from C/inc; A depends on B but not C directly; B depends on C).
I don't know if it helps, but the way I specify dependencies in CMakeLists.txt for three such projects is through the target_link_libraries() command, and I specify include directories using target_include_directories(). The way CMake works is the target_include_directories() for C are added _both_ to A and B (B gets them directly, A gets them transitively). Unfortunately, CMT and/or cpptools (I really don't know which, to be honest) is only listing B/inc in the debug output include folders list for A, when I set "C_Cpp.loggingLevel": "Debug" in user settings.
My work-around is to let cpptools (I think?) set this up in c_cpp_properties.json, although I don't like it because I think it's heavy-handed to just basically "search everywhere" for headers and not just the paths the compiler will actually search, as I expect:
"includePath": [
"${workspaceFolder}/**"
],
I'm wondering why isn't the include list from compile_commands.json used? Because for me, the list is correct, it has both B/inc and C/inc.
I've also been suffering this issue a lot recently (as well as others I'm seeing in the list of issues #602 ) and what has worked and solved everything for me at the end (and after long troubleshooting sessions) is doing a re-scan for kits from VSCode command palette.
Before doing this I would suggest deleting/renaming the existing file in _%localappdata%\CMakeTools_ since that file persists even you reinstall the CMT or if you do a CMT Reset from VSCode command palette.
I'm not sure if the change in the behavior has been provoked by CMT, CMake or VS, but for the kits that rely on Visual Studio, in the config file the "VisualStudio" attribute has changed from a kind of a reference number to the literal "Visual Studio 15 2017".
Worth to try (and apologies if it is specified somewhere already but otherwise I believe it could be good to emphasize that re-scanning kits seems to be a best practice to exercise once you update any component in the toolchain you could be using).
Still having this issue in 2019
@seanngpack, can you open a new issue with details about your problem? Thank you!
Most helpful comment
I've also been suffering this issue a lot recently (as well as others I'm seeing in the list of issues #602 ) and what has worked and solved everything for me at the end (and after long troubleshooting sessions) is doing a re-scan for kits from VSCode command palette.
Before doing this I would suggest deleting/renaming the existing file in _%localappdata%\CMakeTools_ since that file persists even you reinstall the CMT or if you do a CMT Reset from VSCode command palette.
I'm not sure if the change in the behavior has been provoked by CMT, CMake or VS, but for the kits that rely on Visual Studio, in the config file the "VisualStudio" attribute has changed from a kind of a reference number to the literal "Visual Studio 15 2017".
Worth to try (and apologies if it is specified somewhere already but otherwise I believe it could be good to emphasize that re-scanning kits seems to be a best practice to exercise once you update any component in the toolchain you could be using).