CMake examples in Xcode

Digging into CMake for the first time. Very excited about it, but had some questions about the Xcode project the example config produces.

I’m hoping to use CMake on CI and would like to use the built Xcode project locally, however it’s a bit cluttered with the default config it seems:

  1. The example CMake projects in the JUCE repo don’t add headers ( PluginEditor.h and PluginProcessor.h) to target_sources — not sure if this is intentional, but without listing them there, they don’t show up in Xcode for me, so I assume it’s an omission?

  2. Headers and Source are output into two separated folders — is this trivial to change? I’d like to have my source organized the way Projucer had it / the way it’s in source control.

  3. Is there a way to stick all the juce prefixed .mm and .h files in a subfolder to get them out of the way?

Thanks for any pointers!

New to CMake as well, but from what ive seen the source files list should really only contain source files (.cpp) that get compiled. If you want your header file to be found by xcode without providing the path to it in your include statement, you can add the directory it is in as an include directory:

target_include_directories(YOUR_TARGET PUBLIC
    DirectoryYourHeaderIsIn/
)

im on linux but I dont have all those juce module files in my source directory, not sure but that could be due to the way you are including juce in your cmake lists. How have you included it? Are you using cmake to find the library or have you got a juce subdirectory and are using add_subdirectory? It also could just be the way the xcode generator works. Like I said im on linux so im not too sure.

Hey there!

My CMakeLists.txt is here:

Which is essentially a derivative of the JUCE example for an Audio Plugin plus a few things I ran into on the forum.

Thanks! That’s helpful, my next step is to look into customizing things beyond the example config.

Yeah… I’m mainly wondering if the example CMakeLists.txt are just not (yet?) optimized for Xcode or if I’m missing something / my expectations are off…

Appreciate the reply!

So looking at your cmake list, you have enabled module source groups. The api docs say this:

JUCE_ENABLE_MODULE_SOURCE_GROUPS

This option controls whether dummy targets are added to the build, where these targets contain all of the source files for each module added with juce_add_module(s). If you’re planning to use an IDE and want to be able to browse all of JUCE’s source files, this may be useful. However, it will increase the size of generated IDE projects and might slow down configuration a bit. If you enable this, you should probably also add set_property(GLOBAL PROPERTY USE_FOLDERS YES) to your top level CMakeLists, otherwise the module sources will be added directly to the top level of the project, instead of in a nice ‘Modules’ subfolder.

In your cmake file you commented out the use folders set_property, so it looks like thats why the modules are all being added at the top level. Try uncommenting that and see if the modules get placed in their own folder:

set_property(GLOBAL PROPERTY USE_FOLDERS YES)
option(JUCE_ENABLE_MODULE_SOURCE_GROUPS "Show all module sources in IDE projects" ON)

Hey sorry @denvercoder9 — Apparently I left the github version of the repo in a messy state while I was troubleshooting. I caught this right after posting, but you were too quick! It’s updated now to the original config I wanted.

I tried building with and without JUCE_ENABLE_MODULE_SOURCE_GROUPS (blowing away the builds folder in between) as well as with and without the USE_FOLDERS in attempts to understand what was happening… no luck…

I tried to use source_group(TREE) as described here so that I can have CMake output source groups that mimic my actual source (my goal): https://cliutils.gitlab.io/modern-cmake/chapters/features/ides.html

However, not having much luck getting anything to show up that way. Next stop is looking into the cmake utils that juce provides, I think…

Followup on cleaning up the IDE presentation.

In the end I took an approach similar to what Tracktion’s pluginval does and have a more usable IDE-friendly xcode build with:

set(SourceFiles
	Source/PluginEditor.h
	Source/PluginProcessor.h
	Source/PluginEditor.cpp
	Source/PluginProcessor.cpp)

target_sources(Pamplejuce PRIVATE ${SourceFiles})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/Source PREFIX Source FILES ${SourceFiles})

This still felt pretty messy, so I’ve manually moved all the other targets into a folder called “Targets”:

# https://cliutils.gitlab.io/modern-cmake/chapters/features/ides.html
set_property(TARGET Pamplejuce_AU PROPERTY FOLDER "Targets")
set_property(TARGET Pamplejuce_AUv3 PROPERTY FOLDER "Targets")
set_property(TARGET Pamplejuce_VST3 PROPERTY FOLDER "Targets")
set_property(TARGET Pamplejuce_All PROPERTY FOLDER "Targets")
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "Targets")
set(CMAKE_SUPPRESS_REGENERATION true) # No ZERO_CHECK

I did this manually because set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "Targets") doesn’t seem to work (or is maybe overridden by JUCEUtils.cmake)?

Looking better:

Next up I plan on looking into:

  1. Consolidating/nesting/removing the “Source Files” and “Header Files” directories. These seem to be default cmake groupings but I haven’t figured out if it would require changes to JUCEUtils.cmake
  2. Setting some scheme options by default, for example having the AudioPluginHost being the executable: https://cmake.org/cmake/help/latest/prop_tgt/XCODE_GENERATE_SCHEME.html
  3. Figuring out if I can remove the module schemes that get added when JUCE_ENABLE_MODULE_SOURCE_GROUPS is on.
1 Like

So cool, let’s hope the JUCE team has a look at this!

1 Like

@yfede Thanks!

Here are a few more Xcode sanity bringers:

JUCE_ENABLE_MODULE_SOURCE_GROUPS is great, but adds Xcode schemes which makes things very noisy:

So I turned off scheme generation globally:

set(CMAKE_XCODE_GENERATE_SCHEME OFF)

And then selectively turned it on for the Plugin targets:

set_target_properties(Pamplejuce_AU Pamplejuce_AUv3 Pamplejuce_VST3 Pamplejuce_All PROPERTIES 
	FOLDER "Targets"
	XCODE_GENERATE_SCHEME ON)

But it would probably be nicer to have these properties set in JUCEUtils.cmake (maybe in _juce_add_interface_library)?

To reduce noise from the default “Header Files” and “Source Files” folders, I’m using a shotgun approach:
source_group("JUCE Library Code" REGULAR_EXPRESSION "juce_")

This would probably be nicer also handled in JUCEUtils.cmake (but not sure where…)

Current status:

  1. Still can’t seem to stick ALL_BUILD in Targets
  2. Still has duplicate nesting setup by JUCEUtils.cmake

But looking nicer! Current CMakeLists.txt

3 Likes

Yeah the folder were just naggin’ at me all day. I was just about to embark on another journey through the CMake forest to find that you have already taken it upon yourself. Thank you!

1 Like

@frye Awesome! I spent some more time on folders recently but couldn’t figure out how to get rid of that extra folder named after the target (Pamplejuce > Pamplejuce in my example).

I confirmed that PROJECT_SOURCE_DIR as well as the target’s SOURCE_DIR don’t have that extra folder. Also inspected via get_target_property(MY_PROJECT_SOURCES Pamplejuce SOURCES) and everything seems correct…

Turning off USE_FOLDERS or having it on and set_target_properties(Pamplejuce PROPERTIES FOLDER "") still leaves a top level target folder in Xcode called “Pamplejuce” so maybe I’m still missing something and will have to learn to love that nested lyfe.

1 Like

Haha, well I took a CMake journey a couple months back and had a pretty good setup, after building it looked like this but with no juce source files in there:
CMakeLists.txt (6.7 KB)


After commenting out the generate_juce_header those popped up. Your changes got those out of there and fixed a couple other things but the .mm files are now in the “Target Membership” list on the right… I attached the old file I had worked out if you want to check that out.

One thing, I haven’t noticed anyone use the IF(WIN32) / IF(UNIX) type statements in any juce examples, do you know if this is considered a bad idea or something?

It’s totally fine to use if statements.

I think the JUCE examples didn’t use them just because they’re trying the ‘user’ script to be as clean and portable as possible, and for simple/personal projects you might not need platform specific configuration as JUCE took care of most of it.