Thanks a lot, I’ll give it a try!
Your recipe above worked (so far), thanks!
A couple of minor caveats:
-
I had to
add_library()asSTATICrather thanOBJECTfor my JUCE dependencies library: CMake complained about cyclic dependencies. I guess this isn’t a problem though. -
I had to add the
juce::namespace everywhere (not a problem, just a note for anyone else following this) -
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.
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.
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. ![]()
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 thatldhas a shot at our object files, we usetarget_link_libraries(mylibrary -r)which will sneakily insert the
-rparameter that indicates we want to pre-link, not generate a dylib. So instead of a file of typeMH_DYLIBwe now get anMH_OBJECTfile, a static lib just like we wanted. However, since CMake thinks we’re making a dylib, the generated file will still be namedmylibrary.dylibeven 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 ![]()
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
(A 17-months-later reply to your 11-months-later question… #SPEEDY)
If you look at the code for juce_generate_juce_header, it’s very simple and really relies on only two things:
- The target has a
JUCE_GENERATED_SOURCES_DIRECTORYproperty, which is used to set${juce_header}, the path to theJuceHeader.hthat will be generated. - The target has a
JUCE_DEFS_FILEproperty, which will be set as${defs_file}.
Both of those paths are then passed to the juceaide program in a custom command, the command line for which is:
juce::juceaide header ${defs_file} ${juce_header}
JuceAide is what generates the JuceHeader.h file.
The question becomes why you’d want to call juce_generate_juce_header at all, never mind on a non-JUCE target. As the JUCE CMake API docs say:
In plain CMake projects which don’t require Projucer compatibility, the use of JuceHeader.h is optional. Instead, module headers can be included directly in source files that require them.
Other than for ProJucer compatibility, there’s no need for a JuceHeader.h anymore, and you’re better off using more granular module #includes where necessary.
My previous post was in reply to you, I thought. But I notice it’s not showing up that way in the thread, so just adding this direct reply to trigger a notification.