Optimal #include statement for inheriting from a Component

Hi, this is half a Juce question and half a C++ question.

I may be mistaken, but it seems like we are not able to #include header files for specific components (juce_Component.h, juce_Slider.h, etc.) directly and are forced to include the entire module instead (<juce_gui_basics/juce_gui_basics.h>)?

I’m using Cmake and am trying to create custom components in their own .h/.cpp files and wanted to know the idiomatic Juce way of doing that.

Here’s a simple example of a custom component (MyComponent.h):

#ifndef MYCOMPONENT_H
#define MYCOMPONENT_H

// Will not compile, as juce_Component.h doesn't include anything itself
#include <juce_gui_basics/components/juce_Component.h>

// Is this the only option (without editing the library code)?
// #include <juce_gui_basics/juce_gui_basics.h>

class MyComponent : public juce::Component
{
public:
    MyComponent();

    void paint(juce::Graphics& g) override;

    void resized() override;

private:
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MyComponent)
};

#endif // MYCOMPONENT

If I switch the two #include lines, making the active one
#include <juce_gui_basics/juce_gui_basics.h>,
the project compiles fine, but adds a TON of extra includes to MyComponent.h.

Say I have ten more custom components that all
#include <juce_gui_basics/juce_gui_basics.h>,
will this have a negative effect on my executable size or compile times? Or will they be the same because nothing is defined in any of those headers?

With the way the juce modules are structured, following a unity build approach, it’s indeed not possible to include single headers from a module. You will always need to include the main module header containing the class you need, so #include <juce_gui_basics/juce_gui_basics.h> is the only right way to go here.

It won’t have a negative effect on your executable size. Generally speaking, everything that is not referenced by your code will be stripped away from your final executable, keep in mind that there are a lot of juce classes available that are compiled with the module which might never be used in your code anyway.

However, yes it might affect compile times. There was a time where it was usual to not include module headers but an auto generated JuceHeader.h file, containing all the module headers. This was quite convenient at first but we saw a drastic reduction in compile times when reworking a huge project from not including the juce header but including necessary module headers only, so you can already see this as a step in the right direction. In the end, it’s a difficult question to answer if the speed up when compiling the modules outperforms the slowdown when compiling other translation units referencing classes from these modules. But this is more a theoretical question since you have to deal with this design decision made by juce long time ago anyway :man_shrugging:

4 Likes

Great, thanks very much PluginPenguin!

Hopefully, C++20 modules will represent a huge leap forward on this subject when they will be implemented by all major compilers. Fingers crossed for that to be true, happen soon and for JUCE to rework its code using that :crossed_fingers: :crossed_fingers: :crossed_fingers:

1 Like

I just had a quick look at the whole C++ 20 modules topic, since I don’t work on any C++ 20 based project at the moment, but it looks promising indeed. But do you know if exporting the juce modules as C++ 20 modules would be a breaking change or if it that could be implemented as a parallel optional way of handling the juce modules?

I think I saw in some tutorials the the standard library stuff can be pulled in with either e.g. #include <iostream> or #import <iostream>; – right? This gives me the impression that a parallel structure at least could be possible somehow. Otherwise I guess we’ll have to wait quite some time until C++ 20 can be assumed as a common standard and this pattern would have been adopted by the juce library :wink:

I believe the current structure of JUCE modules would allow the creation of a C++20 module for each fairly easily.
Let’s say one such module will be named “juce_gui_basics.ixx” (consensus on the extension to use is still to be reached AFAIK). In that file I believe it should be possible to do something like:

export 
{
    #include "juce_Label.cpp"
    #include "juce_TextEditor.cpp"
    // etc.
};

In practice reusing the existing files and gluing them together with one last usage of the preprocessor to obtain a file that externally will behave as a proper C++20 module, exporting all the classes and functions in that JUCE module.