Module-only repo cmake problems

I’m trying to make a separate repo for modules to use in multiple plugins, but have build problems. I made a narrowed down repo with minimal code. I have separate directories for modules, examples (plugins just to exercise the modules), and tests. I started with the pamplejuce template, moved things around, and used some stuff from Jan Wilczek’s course and template.

I’m using CLion on macOS.

The Tests target (Catch2) fails to build, looking like it can’t find juce or STL includes.

====================[ Build | Tests | Debug ]===================================
/Applications/CLion.app/Contents/bin/cmake/mac/aarch64/bin/cmake --build /Users/sam/code/juce/other/modules-template/cmake-build-debug --target Tests -j 6
[0/2] Re-checking globbed directories...
[109/716] Building CXX object tests/CMakeFiles/Tests.dir/__/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp.o
FAILED: [code=1] tests/CMakeFiles/Tests.dir/__/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp.o 
/usr/bin/c++ -DDEBUG=1 -DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 -DJUCE_MODAL_LOOPS_PERMITTED=1 -DJUCE_MODULE_AVAILABLE_juce_core=1 -DJUCE_MODULE_AVAILABLE_juce_data_structures=1 -DJUCE_MODULE_AVAILABLE_juce_events=1 -DJUCE_MODULE_AVAILABLE_juce_graphics=1 -DJUCE_MODULE_AVAILABLE_juce_gui_basics=1 -DJUCE_MODULE_AVAILABLE_juce_gui_extra=1 -DJUCE_MODULE_AVAILABLE_module_a=1 -DJUCE_USE_CURL=0 -DJUCE_VST3_CAN_REPLACE_VST2=0 -DJUCE_WEB_BROWSER=0 -DRUN_PAMPLEJUCE_TESTS=1 -D_DEBUG=1 -I/Users/sam/code/juce/other/modules-template/tests/modules -I/Users/sam/code/juce/other/modules-template/modules -I/Users/sam/code/juce/other/modules-template/dependencies/Catch2/src/catch2/.. -I/Users/sam/code/juce/other/modules-template/cmake-build-debug/_deps/catch2-build/generated-includes -I/Users/sam/code/juce/other/modules-template/dependencies/JUCE/modules -g -std=gnu++2b -arch arm64 -mmacosx-version-min=10.14 -fcolor-diagnostics -g -O0 -Wall -Wshadow-all -Wshorten-64-to-32 -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wsign-conversion -Wbool-conversion -Wextra-semi -Wunreachable-code -Wcast-align -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wno-ignored-qualifiers -Wswitch-enum -Wpedantic -Wdeprecated -Wfloat-equal -Wmissing-field-initializers -Wzero-as-null-pointer-constant -Wunused-private-field -Woverloaded-virtual -Wreorder -Winconsistent-missing-destructor-override -MD -MT tests/CMakeFiles/Tests.dir/__/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp.o -MF tests/CMakeFiles/Tests.dir/__/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp.o.d -o tests/CMakeFiles/Tests.dir/__/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp.o -c /Users/sam/code/juce/other/modules-template/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp
/Users/sam/code/juce/other/modules-template/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp:47:27: error: unknown type name 'Component'
   47 |     void* getNativeChild (Component& component) const
      |                           ^
/Users/sam/code/juce/other/modules-template/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp:58:5: error: unknown type name 'Component'
   58 |     Component* getComponent (void* nativeChild) const
      |     ^
/Users/sam/code/juce/other/modules-template/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp:69:26: error: unknown type name 'Component'
   69 |     void setNativeChild (Component& component, void* nativeChild)
      |                          ^
/Users/sam/code/juce/other/modules-template/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp:83:26: error: unknown type name 'Component'
   83 |     void clearComponent (Component& component)
      |                          ^
/Users/sam/code/juce/other/modules-template/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp:91:5: error: use of undeclared identifier 'std'
   91 |     std::map<void*, Component*> componentForNativeChild;
      |     ^
/Users/sam/code/juce/other/modules-template/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp:91:21: error: use of undeclared identifier 'Component'
   91 |     std::map<void*, Component*> componentForNativeChild;
      |                     ^~~~~~~~~
/Users/sam/code/juce/other/modules-template/dependencies/JUCE/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp:91:31: error: expected expression
   91 |     std::map<void*, Component*> componentForNativeChild;
      |                               ^
truncated

The ExampleAPlugin_All target builds with just a weird message about the vst3 signature. I can run the standalone and the AU and VST3 in Reaper. They just print a message in the PluginEditor like the default pamplejuce plugin. The PluginProcessor includes <module_a/module_a.h> and adds a private member, “modules::A a;”.

====================[ Build | ExampleAPlugin_All | Debug ]======================
/Applications/CLion.app/Contents/bin/cmake/mac/aarch64/bin/cmake --build /Users/sam/code/juce/other/modules-template/cmake-build-debug --target ExampleAPlugin_All -j 6
[0/2] Re-checking globbed directories...
[65/66] Linking CXX CFBundle shared module examples/ExampleA/ExampleAPlugin_artefacts/Debug/VST3/ExampleA.vst3/Contents/MacOS/ExampleA
/Users/sam/code/juce/other/modules-template/cmake-build-debug/examples/ExampleA/ExampleAPlugin_artefacts/Debug/VST3/ExampleA.vst3: code has no resources but signature indicates they must be present
-- Replacing invalid signature with ad-hoc signature
/Users/sam/code/juce/other/modules-template/cmake-build-debug/examples/ExampleA/ExampleAPlugin_artefacts/Debug/VST3/ExampleA.vst3: replacing existing signature
removing moduleinfo.json

Build finished

There’s some weirdness with std::flat_set, which is new in c++23.

The only thing in module_a (module_a/implementation/a.h) is

struct A {
    std::flat_set<int> fs;
    std::set<int> s;
};

If I don’t include <flat_set> in module_a/module_a.h, the plugin build fails with

/Users/sam/code/juce/other/modules-template/modules/module_a/implementation/a.h:6:10: error: no template named 'flat_set' in namespace 'std'
    6 |     std::flat_set<int> fs;
      |     ~~~~~^

I don’t need to include at all for it to build, but CLion makes “set” red. Where does the compiler normally get all the STL includes? Do they come from juce header files?

If I include <flat_set> in implementation/a.h instead of module_a.h, the plugin build fails with many errors in files under the MacOSX.sdk such as the following.

In file included from /Users/sam/code/juce/other/modules-template/examples/ExampleA/source/PluginEditor.cpp:1:
In file included from /Users/sam/code/juce/other/modules-template/examples/ExampleA/source/PluginEditor.h:3:
In file included from /Users/sam/code/juce/other/modules-template/examples/ExampleA/source/PluginProcessor.h:4:
In file included from /Users/sam/code/juce/other/modules-template/modules/module_a/module_a.h:31:
In file included from /Users/sam/code/juce/other/modules-template/modules/module_a/implementation/a.h:3:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/flat_set:60:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/__flat_set/flat_multiset.h:31:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/__flat_map/key_value_iterator.h:18:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/__iterator/product_iterator.h:58:32: error: unknown class name 'false_type'; did you mean '::std::false_type'?
   58 | struct __is_product_iterator : false_type {};
      |                                ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/integral_constant.h:32:40: note: '::std::false_type' declared here
   32 | typedef integral_constant<bool, false> false_type;
      |                                        ^

Why would it make a difference including it where its used vs in the main module header?

Any other feedback on setting up a repo for modules would be appreciated.

In module_a.h we’ve got this:

namespace modules
{
#include "implementation/a.h"
}

So if “implementation/a.h” does #include <flat_set>, then what the compiler will see is:

namespace modules
{
// content of a.h:
#include <flat_set>
}

This’ll wrap all the declarations in flat_set in namespace modules, which will cause problems when attempting to do symbol lookup on other stdlib headers that were included earlier, outside of namespace modules.

Thanks reuk.

The Tests build failure is fixed in tests/CMakeLists.txt by replacing

add_executable(Tests ${TestFiles})

with

juce_add_console_app (Tests)
target_sources (Tests PRIVATE ${TestFiles})

This is because in JUCEDefaults.cmake from pamplejuce’s cmake-includes, it turns on the JUCE_ENABLE_MODULE_SOURCE_GROUPS option. The JUCE CMake API documentation says, “Source groups will only work when all JUCE-dependent targets are created using the juce_add_* functions. The standard add_executable and add_library commands are likely to result in broken builds when source groups are enabled!” The problem is alternatively fixed by leaving this option off.

It’s curious that the unmodified pamplejuce works. There the juce modules are linked to the SharedCode target that’s created with add_library and that’s linked to the Tests target created with add_executable. Neither target uses a juce_add_*.