Using CMake flow to build libraries, Android apps

Thanks a lot, I’ll give it a try!

Your recipe above worked (so far), thanks!

A couple of minor caveats:

  1. I had to add_library() as STATIC rather than OBJECT for my JUCE dependencies library: CMake complained about cyclic dependencies. I guess this isn’t a problem though.

  2. I had to add the juce:: namespace everywhere (not a problem, just a note for anyone else following this)

  3. I wasn’t able to use the following:

     const juce::String getApplicationName() override
     {
        return juce::ProjectInfo::projectName;
     }
 
     const juce::String getApplicationVersion() override
     {
        return juce::ProjectInfo::versionString;
     }

in my juce::JUCEApplication; I assume juce::ProjectInfo is created along with JuceHeader.h. Not a show-stopper by any means; I can hard-code them for now and worst case, just define these some other way. Would be nice to re-use the JUCE way though.

1 Like

Following up on this thread @reuk @eyalamir as I am trying to contribute to Eyal’s CMake template, which has every project type except for the library type - as I mostly am making libraries it would be convenient to have a Github template set up with as much of the boiler plate as possible.

I tried the above recommendations, and unfortunately it seems that for me, the call

_juce_initialise_target(${TargetName})

is the single difference between the template building successfully or not. Without this line, there are many errors where juce_core’s .cpp files cannot find their own .h nor other symbols referenced from other headers.

Here’s what I have so far, if anyone can recommend a better way of doing it than this, thanks in advance!

project(LibraryTemplate VERSION 0.0.1)

set (TargetName ${PROJECT_NAME})

add_library(${TargetName} OBJECT)

_juce_initialise_target(${TargetName})

target_link_libraries(${TargetName}
        PRIVATE
        juce::juce_core
        PUBLIC
        juce::juce_recommended_config_flags
        juce::juce_recommended_warning_flags)

target_compile_definitions(${TargetName}
        INTERFACE
        $<TARGET_PROPERTY:${TargetName},COMPILE_DEFINITIONS>)

target_include_directories(${TargetName}
        INTERFACE
        $<TARGET_PROPERTY:${TargetName},INCLUDE_DIRECTORIES>)

set(SOURCES
    Source/LibraryAPI.cpp
    Source/LibraryImpl.cpp)

target_sources(${TargetName} PRIVATE ${SOURCES})

add_library(${TargetName}_shared SHARED)
add_library(${TargetName}_static STATIC)

target_link_libraries(${TargetName}_shared PUBLIC ${TargetName})
target_link_libraries(${TargetName}_static PUBLIC ${TargetName})

This might be a better reference, I was also trying to determine in what scenarios having both a static library and a consuming CLI app using juce_core would cause problems:

Maybe it was privately linking to juce_core in the static library that allowed things to (seemingly) work alright?

Here is also @eyalamir 's upstream equivalent, i noted he also needed to use the private _juce_initialise_target and so there is perhaps no better way to do this as of yet. (Caveat: I suspected in some projects I worked on that libraries could compile with JUCE without this call, but only if other non-library projects were part of the same larger CMake project and JUCE had the right visibility between parts of the larger project.)

I was also curious about the purpose of

target_compile_definitions(DLL PRIVATE JUCE_STANDALONE_APPLICATION=1)

as I did not need to add it to mine for things to work.

1 Like

When I remove it and try to build, I get the following warning:

#ifndef    JUCE_STANDALONE_APPLICATION
 JUCE_COMPILER_WARNING ("Please re-save your project with the latest Projucer version to avoid this warning")
 #define   JUCE_STANDALONE_APPLICATION 0
#endif

And I like my builds warning-free. :slight_smile:

2 Likes

So to return to a two year old convo:

On the Mac it turns out you can pre-link your static library and avoid this problem, details are here:

Hiding Symbols in Static Libraries with Xcode or CMake | Orange Juice Liberation Front).

In which he says:

A hackish way I found is to simply tell CMake to build a dynamic library, then modify the settings a bit. So instead of

add_library(mylibrary STATIC mylibrary.c mylibraryutils.c)

your CMake file says

add_library(mylibrary SHARED mylibrary.c mylibraryutils.c)

Of course, that just gets us a dylib. But it makes CMake call ld. Now that ld has a shot at our object files, we use

target_link_libraries(mylibrary -r)

which will sneakily insert the -r parameter that indicates we want to pre-link, not generate a dylib. So instead of a file of type MH_DYLIB we now get an MH_OBJECT file, a static lib just like we wanted. However, since CMake thinks we’re making a dylib, the generated file will still be named mylibrary.dylib even though it is static. So we need to override that suffix:

set_target_properties(foo PROPERTIES SUFFIX ".a")

I’m off to investigate for Windows. It’d be really useful to be able to build static libraries with the JUCE CMake system easily :slight_smile:

Hey, got something very similar running right now. Was just wondering if there is any way to use juce_generate_juce_header on targets that were made from add_library?

Probably not, but I figured it’d be worth asking