Well, this got… weirdly antagonistic… but @kunitoki is right that there are users out there who have a use case for building shared libs out of JUCE code.
(Though that should be obvious, given that one of the old Projucer default project templates was “Dynamic Library: This project type is useful to create re-usable software libraries that build on top of JUCE. Use this for dynamic library linking.” If the JUCE team were under the impression that nobody was using that template, let me disabuse you of that notion.)
In fact, we’ve been building JUCE modules into a shared library for a number of years, now. Confusingly, though, the things @reuk cites as potential problems with shared libraries are exactly the things we avoid by building that way.
All of the JUCE code in our library is sequestered into its own, separate shared lib, “the audio library”. That gets built as a .so
, .dll
, or .dylib
depending on the platform, and then exported along with the headers for the relevant modules. Consumers of the library (including our own parent video-processing library) link only with those headers and that shared audio library — they don’t directly consume the JUCE code themselves, so there are no versioning issues or ODR violations.
I suppose if we were using plugins, or a more modular design, we might run into trouble. But for the moment, we’re not, and all of the JUCE API gets nicely encapsulated into the audio library build.
Another reason a shared library is the only viable choice is that our primary application is written in Python (with a PyQt5 interface). We create a set of SWIG-generated bindings as an extension module for Python (and Ruby). The extension is dynamically loaded by the Python interpreter, and in turn is linked to the shared libraries — very much the situation @kunitoki described in their last comment.
(Though AFAIK not the same situation, so I guess there’s at least 2 sets of us out there with very similar needs.)
We’ve even been building with CMake for all of those years, already. So, I can tell you how at least one project did it, and across all three major desktop platforms (via MSYS2, on Windows):
set(JUCE_MODULES_PATH "${CMAKE_CURRENT_SOURCE_DIR}/JuceLibraryCode/modules" CACHE PATH
"Location of the JUCE source code 'modules' directory")
# Default extension for source files
if(UNIX AND APPLE)
set(SOURCE_EXTENSION "mm")
else ()
set(SOURCE_EXTENSION "cpp")
endif()
# List of modules to build
set(JUCE_MODULES
juce_audio_basics
juce_audio_devices
juce_audio_formats
juce_core
juce_data_structures
juce_events )
# Convert to list of source files (extension based on OS)
foreach(j_module IN LISTS JUCE_MODULES)
list(APPEND JUCE_SOURCES
JuceLibraryCode/include_${j_module}.${SOURCE_EXTENSION} )
endforeach()
add_library(audio SHARED ${JUCE_SOURCES} )
# Include header directories
target_include_directories(audio PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/JuceLibraryCode/modules>
$<BUILD_INTERFACE:${JUCE_MODULES_PATH}>
$<INSTALL_INTERFACE:include/audio> )
Followed by, eventually:
# Install Header Files
foreach(j_module IN LISTS JUCE_MODULES)
install(DIRECTORY ${JUCE_MODULES_PATH}/${j_module}/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/audio/${j_module}
FILES_MATCHING PATTERN "*.h" )
endforeach()
# Install library
INSTALL(TARGETS audio
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
It works well enough, but when I heard JUCE would be debuting CMake support in JUCE 6, I was very much looking forward to mothballing our own build in favor of just using the official tooling. However, as things stand it’s not clear to me whether that can happen, as the provided infrastructure feels very narrowly focused to me, and that focus seems to be on a very different set of user priorities than our own.