JUCE Include Path Hierarchy

I’ve plunged into the depths of the Juce framework to better understand its deep inner workings and wanted to ask about how the framework is compiled.

Looking at a majority of pre-existing (non user configured) headers / implementation files, noticed all of them don’t have any ‘include’ statements defining what classes are needed, either inherited or composited classes. The JuceHeader.h contains a dump of it all, with all derived folder paths implemented in further subgroups of .h / .cpp files.

I’m looking to create something similar in my project and up to now, I’ve used the standard include statements at the top of every header / implementation file.

I understand setting up ‘header search paths’ in the IDE helps with the collection of these files, however I still don’t understand how a class that inherits from another, or composites another doesn’t need to explicitly declare its ‘#include’ path.

For example:
AudioDeviceManager.cpp doesn’t include AudioDeviceManager.h, yet compiles without errors.

Looking through JUCE Modules: juce_audio_devices.h & juce_audio_devices.cpp, I’m trying to understand how the example above, doesn’t require explicit include paths. The JuceHeader.h is only explicitly included in a default project, Main.cpp and MainComponent.h for example.

My project’s Xcode header search path looks the same as a default Juce project, and I’ve copied the same format with Juce’s JUCE Library Code & JUCE Modules.

Hoping someone can chime in :slight_smile:

As you expected, it all happens in the modules.

Since individual header files can get moved to different folders you shouldn’t include those directly.
But it is fine to include only a certain module header, e.g. the mentioned juce_audio_devices.h
The most convenient way is to use the generated JuceHeader.h. That will also take care of project configurations via AppConfig.h (even though I heard that one is to go when using CMake).

Each module consists of only one TU (translation unit, which is simplified a compiler instance). The juce_module_name.cpp or on Mac the juce_module_name.mm is the only one processed by your IDE, the other files are visible for reference. This master file will include all source files in that module. And at the beginning it includes all other module headers it depends on and the all headers of that module.

I can only encourage you to start writing your own modules, it is really easy to recycle your own code in that way. The documentation to that is found under JUCE/docs/JUCE module format.md

Hope that helps

Doh… I only just came across this file by reading the BEGIN_JUCE_MODULE_DECLARATION a little more closely.

Thanks Daniel. :smiley:


So, I had a look at the Juce module format.md file, and that explains things when building modules for Juce.

I’m trying to replicate the same behaviour without the implementation of a Juce module, in a brand new Xcode project (non Juce) for example.

I still don’t understand how a .cpp file doesn’t generate any complication errors when no .h include is explicitly defined. I’ve tried following the structure shown with the Modules, JuceHeader.h etc however no luck.

You would need to start with the source file (headers are never compiled, only copied into a TU).
Then think like a preprocessor. There is likely an include somewhere.
In the juce modules case it includes cpp files, which is again just copied into that TU by the preprocessor and all includes before will be valid for that source file as well.

Not sure if that was a better explanation than before…

BTW. in Xcode you can select a cpp file (one that is actually compiled, not one of the modules), click the assistant on the right, then the four squares and select “preprocess” all the way down. Then you can see the TU with all headers copied into: