Prototype: Precompiled headers for Visual Studio

The main reason to build all modules together is to ensure a consistent set of JUCE_MODULE_AVAILABLE_ definitions. One possiblity might be to exclude the plugin_client module from the staticlib and to manually define JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1 on the staticlib.

Sorry, I wasn’t clear. I meant linking the juce modules to the plugin target, in the same way as the plugin demo from the repo. JUCE modules are CMake INTERFACE targets, so they will be built into each target that links against them.

juce_add_plugin(AudioPluginExample ...)

target_link_libraries(AudioPluginExample
    PRIVATE
        juce::juce_audio_utils
        # other modules here
        )
2 Likes

I meant linking the juce modules to the plugin target, in the same way as the plugin demo from the repo.

Ah, but IIUC that’s incompatible with using a precompiled header, which is what I’m looking to do and the reason I stumbled upon this thread. I apologize if I wasn’t clear.

I can’t think of a great solution at the moment. If you’re just aiming to add PCH to a plugin, your best bet is probably to set the SKIP_PRECOMPILE_HEADERS source file property on each of the JUCE sources. This will need to be done in each directory which adds a PCH target. We can’t set this property in JUCEUtils.cmake because source-file properties are local to a directory.

target_link_libraries(AudioPluginExample
    PRIVATE
        # AudioPluginData           # If we'd created a binary data target, we'd link to it here
        juce::juce_audio_utils
    PUBLIC
        juce::juce_recommended_config_flags
        juce::juce_recommended_lto_flags
        juce::juce_recommended_warning_flags)

target_precompile_headers(AudioPluginExample PUBLIC header.hpp)

# Set the SKIP_PRECOMPILE_HEADERS source file property here...
1 Like

I’m not sure I understand how I should set the SKIP_PRECOMPILE_HEADERS as you proposed.

What I do see is that set_source_files_properties can be set on a target directory starting with CMake 3.18. set_source_files_properties — CMake 3.19.4 Documentation.
So I guess I can set it globally on all sources in the JUCE directory?

As I understand it, the DIRECTORY argument specifies the scope in which the flags should be visible. It does not specify that the flags should be set on all files in a particular directory.

You could do something like this:

# Collect up all the module `cpp/mm/r` files
file(GLOB_RECURSE module_sources CONFIGURE_DEPENDS ...)
# Set these files to ignore PCH
set_source_files_properties(${module_sources} PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE)
1 Like

Thanks for the help! I got it working.

@Ed95

Are you able to reproducde the error with a blank JUCE project? I’ve created a new blank GUI project in the Projucer, set the VS2019 exporter debug build config to use PCH, and set the file path to pch.h which just #includes <JuceHeader.h>. I’m able to build and re-build the project in VS whilst making changes to the source files without seeing that error. Can you perhaps attach the misbehaving project file?

Unfortunately, the approach you describe doesn’t seem to work for plugins. If I create a basic plugin instead of the blank GUI project, the build fails with:

error MSB3061: Unable to delete file "x64\Debug\JucePrecompiledHeader.pch". The process cannot access the file '...\Builds\VisualStudio2022\x64\Debug\JucePrecompiledHeader.pch' because it is being used by another process.

Tested with JUCE 7.0.8 on Windows 10 with Visual Studio 2022 (version 17.7.6)

Can you reproduce the error?

Apart from excluding the JUCE headers, I was able to get another way of using precompiled headers working that did include the juce headers as well:

  • Use Zi debug format (not sure why this is necessary)
  • Remove the #error Incorrect use of JUCE cpp file lines from the juce headers
  • defining the macros that the JUCE cpp files need when including the JUCE headers, such as JUCE_CORE_INCLUDE_OBJC_HELPERS

Example pch.h

#pragma once

#ifdef __cplusplus

#include <algorithm>
#include <array>
// .... many more
#include <xtree>
#include <xutility>

#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1
#define JUCE_CORE_INCLUDE_COM_SMART_PTR 1
#define JUCE_CORE_INCLUDE_JNI_HELPERS 1
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1
#define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1

#include <juce_core/juce_core.h>
#include <juce_audio_processors/juce_audio_processors.h>
#include <juce_gui_extra/juce_gui_extra.h>
#include <juce_audio_utils/juce_audio_utils.h>
#include <juce_product_unlocking/juce_product_unlocking.h>
#include <juce_dsp/juce_dsp.h>
#include <juce_audio_plugin_client/juce_audio_plugin_client.h>

#else
#endif

Does anyone have any thoughts about this? Are there any potential concerns for this approach?

It does speed up compile time a lot if all the juce headers are included in the precompiled headers as well.

I got this working on macOS and Windows

  • The ObjC helpers, ComSmartPtr, and other bits that have to be manually enabled aren’t intended to be public-facing APIs, so they might change without warning. If you were to start using declarations from the private headers in your own code, you might end up seeing unexpected build/runtime failures when switching between JUCE versions.
  • JUCE module sources are not tested with additional headers included. Normally, a module’s .cpp expects to only be preceded by its matching header. Including other module headers might cause issues if they introduce symbols that conflict with symbols in the .cpp, or change the meaning of other tokens (e.g. by introducing new preprocessor definitions). This might result in build failures or hard-to-diagnose runtime issues due to ODR violations. Even if there are no problems with this approach today, it’s not guaranteed to keep working in the future.
1 Like

@reuk As a very late follow-up, I’m noticing that JucePlugin_Name is also included in juce_AccessibilityHelpers.h, which seems like it’ll minimize reusability with PCH. Perhaps that could get moved to the .cpp?

Good idea, thanks!

1 Like