Using Juce project as a static lib

I want to be able to link statically to a juce project and be able to use all juce functionality (Windows only for now). I created a juce solution changed the target type to static .lib added in the include paths for headers for both modules and route juceLib (copied into project) folder. Hit build and sure enough tons of linker errors so I added the juce project as reference and hitting build starts juce compiling before my main project but I still get one linker error of

|Error|LNK2019|unresolved external symbol “public: static int __cdecl juce::JUCEApplicationBase::main(int,char const * * const)” (?main@JUCEApplicationBase@juce@@SAHHQEAPEBD@Z) referenced in function main|FromScratchCpp|C:\Data\Source\Repos\FromScratchCpp\App\Main.obj|1||

Any ideas on how to resolve. PS below is how I’m trying to setup my project. The reason for this is because it’s part of a much broader solution with many projects inside.

Ok maybe I’ll rephrase the question,

// How do I initalize an instance of
// class MyApplication  : public juce::JUCEApplication
// in a main function
// e.g.
int main() {
  MyApplication app{};
}

Would rather use the START_JUCE_APPLICATION macro for future proofing but for now I would settle knowing the above.

After a lot of hacking I figured I could do this

juce::JUCEApplicationBase* juce_CreateApplication() { return new MyApplication(); }

int main() {

    juce::JUCEApplicationBase::createInstance = &juce_CreateApplication;
    return juce::JUCEApplicationBase::main();
}

I know this sounds very unintuitive, but JUCE really doesn’t like building as a static library this way. It would only work if the static lib ‘hides’ JUCE as an implementation detail and just exposes your own headers.

For example in your case, exposing juce::Component to your app means that it would only work if the exact same set of flags are built in both your app and static lib, which means it will probably fail if you try to link more than one app to that static lib.

If you want to share JUCE-based code in multiple projects, I really suggest using JUCE modules. While that means that you’ll have to rebuild JUCE for each project, you can also be sure that each project will build JUCE with the right flags and you won’t encounter any mismatches.

Yeah I fully get if projects are greenfield and Juce is at the top of the stack. But there are a couple of use cases that I have run into…

  • If you have an existing UI project and you need to add Juce into it for audio…

  • If you have multiple complex solutions that have lets of setup required in IDE the projucer doesn’t cut above a few additional flags and dependancies. Adding files to project becomes a bitch as projucer overwrites solution changes

  • If say you use something like CUDA and the project files need some extra things in each save to make cuda kernels compile

So having the ability to compartmentalize Juce as a seperate project and link to it can have its advantages. All three above I have run into as problems. Any way my last post gives me a work around for now.

Ps. as a side note I have been dying to try and write a basic RUST lang wrapper for components and audio engine…

If it‘s about the limited capabilities of the Projucer when it comes to set up more complex projects, did you consider moving to CMake? All the use cases you mention can be managed ln a convenient way with CMake.

I‘d rather take that route than a static lib that exposes juce classes.

Just as an example, I already used CMake to set up a juce project targeting an FPGA SoC and compiling OpenCL sources for the FPGA along with the project. Or in my current project I compile rust sources in a CMake target that my app depends on. All that would have never been possible with a Projucer based workflow.

4 Likes

Yeah, sounds to me like you’re searching specifically for a CMake approach, where you can build all your shared configuration/source files stuff into an interface target/JUCE module and link against those to avoid repetition when setting up multiple projects that depend on an identical configuration.

The Projucer is indeed very limited when it comes to reusability of configurations.

Yeah so think we’ve spoken about embedded systems a while back. Yeah CMake I should imagine would be a good option but my knowledge is limited.

@eyalamir it’s not so much about code reuse/repetition and I’m quite comfortable knocking up a few juce modules which I have done for some of my commercial audio projects. But they are just pure Juce projects anyway.

For a real world example we built a game-ified audiometry test for kids in hospital which had an existing c++ Qt application were they wanted integration with. So great juce is a good call to expose audio hardware and we could do alot of the work on unit testing and getting code through EN7XXX and ISO27001 e.t.c. as a medical grade device. So mangling the 2 code bases was fun!..

Fortunitely on that project when I took over as Cheif Eng everything got rewritten in Unity so gave us Juce as a simple option for DSP.

Sounds good.

So in CMake here’s a simple way to create a shared ‘library’ for shared configuration (which could be anything, from sources, to compile flags, to the list of JUCE modules to link against):

project(AudioAppTemplate VERSION 0.0.1)

#Shared config stuff, ideally in it's own CMakeLists.txt file so it's shared with many targets

add_library(Shared_Target INTERFACE)

target_sources(Shared_Target INTERFACE
        Source/MainComponent.cpp
        Source/MainWindow.cpp)

target_compile_definitions(Shared_Target INTERFACE
        JUCE_WEB_BROWSER=0
        JUCE_USE_CURL=0)

target_link_libraries(Shared_Target INTERFACE
        juce_recommended_config_flags
        juce_recommended_lto_flags
        juce_recommended_warning_flags
        juce_gui_basics
        shared_processing_code)

#App-specific stuff

juce_add_gui_app(AudioAppTemplate PRODUCT_NAME "Audio App")
target_sources(AudioAppTemplate PRIVATE Source/Main.cpp)
target_link_libraries(AudioAppTemplate PRIVATE Shared_Target)

target_compile_definitions(AudioAppTemplate PRIVATE
        JUCE_APPLICATION_NAME_STRING="$<TARGET_PROPERTY:AudioAppTemplate,JUCE_PROJECT_NAME>"
        JUCE_APPLICATION_VERSION_STRING="$<TARGET_PROPERTY:AudioAppTemplate,JUCE_VERSION>")
1 Like