Adding Visual Studio Code code completion

No, it’s not a breaking change. I’ve done this to all my modules (took a few hours of work for about 30 modules) and the ‘client’ code is unaffected if done correctly.

These steps don’t guarantee working code completion in VS Code, though. Because all of the .cpp files are built in one go, they will see transitive includes from .cpp files included earlier in the main module .cpp. Getting the module building does not guarantee that each inner .cpp actually includes all of the headers it requires in isolation.

Ideally we’d want some way of checking that each ‘inner’ .cpp file can build in isolation, but this would mean moving away from the unity build system (or at least having the option of a non-unity build that we can run in CI).

They are actually.

If you think of how VSCode and other text editors look at ‘regular’ C++ code, it can’t look at the cpp files because it doesn’t know much about them (those are connected to the build system). All it does is recursively parse the headers from the source file it’s looking at.

That’s why the steps I suggest will (do) work.
I’m happy to send a PR of doing it on juce_core, if you want to take a look.

That would be a breaking change indeed and isn’t needed for this. Testing that the entire module cpp file can build is just enough, as this is the how the module builds.

Switching to another type of build system might be useful for other things, but you don’t need to test a build system you don’t use, IMO, and code completion doesn’t care about the cpp files.

Maybe I’m missing something.

Imagine that we have this setup:

a.cpp, uses symbols from
| x.h
| y.h

b.cpp, uses symbols from
| x.h
| y.h
| z.h

module.cpp, contains
#include "a.cpp"
#include "b.cpp"

Now, we try building the module. We start by adding the x.h and y.h headers to a.cpp and rebuild. There are no build errors in a.cpp, but we see some undefined symbols in b.cpp. It looks like the z.h header is missing from b.cpp, but we don’t get any warning that x.h and y.h are also used in that file, because they already got included in a.cpp.

I think in this scenario, after running the steps you suggested, completion would still be broken in b.cpp, (it would only include z.h) even though the build would work.

Did I miss a step that would guarantee b.cpp would actually get the required x.h and y.h includes?

That’s technically true, but it would still be about 50x better than it is now, because headers including x.h will get correct completion.

So for users of that module, life is now better, and you can now iterate on edge cases like the ones you mentioned.

In most cases, it’s actually a.h that would require x.h, and a.cpp just includes a.h, so fixing that header would fix 99% of problems.

1 Like

As a quick example, I forked JUCE on the develop branch and added explicit includes to juce_osc. Took about 10 minutes to do.

juce_core would probably be a better candidate but it’s a tad more work so I’d only do it if it’s something that has a chance of getting accepted by the JUCE team.

Notice that as a start, all the cpps just blindly include “mycppname.h”, to try and minimize (even though not avoid completely) the issue brought above.

Most of the compile errors then were on dependencies between headers, that are then easily resolved, like making sure juce_OSCReceiver.h included juce_OSCBundle.h, which then included juce_OSCMessage, etc.

2 Likes

Worth bearing in mind the sheer number of native source files in JUCE - it’d be a real pain to have to manually go through on each platform adding the required includes to every single file. Also makes it difficult to maintain in the future as new files need to be included.

As @reuk said, the best way to tackle that would be with a tool (something like include-what-you-use) that can fail a pipeline if a file isn’t including the right headers.

@eyalamir Checked out your example there and it does play nicely with VSCode (after also adding the modules folder to the include paths in c_cpp_properties.json).

1 Like

Most of it would be the same.
If you look at my example, many of the stuff in the module header are just copied to another header, like juce_osc_common.h and that includes all the external native headers in a very copy-paste way, as that part shouldn’t change.

While having a tool that makes sure your code has “good C++” includes is a nice idea, it’s really such a boring change that doesn’t require the complication of searching and configuring a tool. It’s really the most straightforward copy/paste job and using the compiler to help you find the errors.

From a practical sense, I suspect looking for some tool here will make this change not happen, and not using a tool can make it happen in a day. So as a pragmatic person I vote for just doing that, and then searching for a tool when there’s actual time to invest in a ‘perfect’ solution.

Thanks!
I believe if you have an app that links with that module, it should know to add the module include path automatically to that json file if you’re using CMAKE_EXPORT_COMPILE_COMMANDS=1)

I had the same problem with AppCode and Resharper. In the end after I moaned at Jetbrains enough and filled in a few support tickets it all got fixed :slight_smile:

I mean, the lights dim slightly when starting the IDE, but after that it all works :slight_smile:

1 Like

+1 for using CPM over git submodules, particularly when you are maintaining your own fork of JUCE and actively working on it. With submodules I found they were higher maintenance as checking out a specific commit would put it in a detached head state, which is not what you want if you are actively making changes to your fork.

With CPM you can do a side-by-side local clone of your JUCE fork next to your project repo folder, and then you can freely work on your JUCE fork without any fuss.

1 Like