Using CMake flow to build libraries, Android apps

At the moment, the CMake support focuses on building plugins, gui apps, and console apps, using the JUCE ‘build everything directly into the final binary’ model. Unfortunately we don’t have android or library examples, yet.

There are good reasons in both cases:

  • The Android/Gradle build system expects to ‘own’ the build, and will itself invoke CMake. That means it’s not really possible to write a CMake-only Android build - Gradle is required too. There’s also a lot of stuff that the Projucer normally does (like modifying and copying boilerplate Java files into the Gradle project) that we can’t easily recreate from a CMake build, because that stuff needs to happen before Gradle is invoked. It’s a bit of a circular problem, with no clear solution at the moment. That being said, it should be possible to create a new ‘native’ project which includes a JUCE-dependent shared library in its CMake portion. This leads onto JUCE-dependent libraries…
  • Due to the way JUCE modules work, it’s important that every module sees exactly the same set of JUCE_MODULE_AVAILABLE_* flags during the build, which in turn means that the final set of JUCE modules that end up in the build must be known ahead of time. When building JUCE into a library, it’s very easy to run into situations where a JUCE module gets included twice in the build, sometimes with different flags, which is likely to introduce subtle bugs. We don’t really want to encourage this build model, because it’s too easy to get it wrong.

With that out of the way, it should be possible to build a JUCE staticlib using a setup a bit like this:

add_library(juce_plugin_modules STATIC)

target_link_libraries(juce_plugin_modules
    PRIVATE
        juce::juce_audio_utils
        juce::juce_dsp
    PUBLIC
        juce::juce_recommended_config_flags
        juce::juce_recommended_lto_flags
        juce::juce_recommended_warning_flags)

target_compile_definitions(juce_plugin_modules
    PUBLIC
        JUCE_WEB_BROWSER=0
        JUCE_USE_CURL=0
    INTERFACE
        $<TARGET_PROPERTY:juce_plugin_modules,COMPILE_DEFINITIONS>)

target_include_directories(juce_plugin_modules
    INTERFACE
        $<TARGET_PROPERTY:juce_plugin_modules,INCLUDE_DIRECTORIES>)

set_target_properties(juce_plugin_modules PROPERTIES
    POSITION_INDEPENDENT_CODE TRUE
    VISIBILITY_INLINES_HIDDEN TRUE
    C_VISIBILITY_PRESET hidden
    CXX_VISIBILITY_PRESET hidden)

This will build the audio_utils and dsp modules (along with all their dependencies) into a staticlib, which exports the recommended warning/config/lto flags in its interface. Note that if you choose to use an approach like this, the staticlib should be the one and only source of JUCE modules in the project. That means, all juce-dependent targets in the project should link against the same juce_plugin_modules target, and they should avoid linking any additional JUCE modules directly.

2 Likes