Quick explanation of how ObjC and C++ are working together under the hood?

I’m trying to write my own Bazel rule for building Juce on Mac. I’m hitting some trouble with the ObjC code that’s included. I see we have .mm files including .cpp files and .h files including ObjC SDKs.

Take juce_BasicNativeHeaders.* for instance. On Mac, the header includes Cocoa, so my attempts to build this with a c++ compiler are unsurprisingly not working (it doesn’t know what to do with NSString and so forth). If I knew how a makefile would try to do this, I’d probably be in good shape. What XCode does under the hood is beyond me. Would someone be willing to give me a quick overview of how these things work together in Juce?

I think all this might be working because of the .mm files, located in the juce modules root directories.

.mm source files are ObjectiveC++ files, which means that you can mix up Objective C and C++ code inside such a Source file. The llvm/clang Compiler used by Xcode is able to compile ObjectiveC++.

Now back to the juce modules: As far as I understood it, if the projucer sees a .cpp and a .mm file with the same name, it chooses to compile the .mm file instead of the .cpp file if it runs on a mac. As the .mm file only contains of a #include “the_cpp_source.cpp” Statement, effectively the same code will be compiled, but as ObjectiveC++ instead of C++. And since this is the case, it now should be perfectly possible to include ObjectiveC headers.

4 Likes

@Chet_Gnegy out of interest, what are the advantages of using Bazel over Projucer CLI + xcodebuild (or msbuild etc) ?

@JanosJuce - I see. I’ll have to compile them as ObjC++ targets then. Thanks, that actually helps a lot.

@jamiebullock - This may be a longer answer than you’re looking for. I started working in Juce in XCode a few years back. I’ve never been a big fan of XCode (save it’s debugger) and I never really got the hang of how Projucer and XCode worked together. I felt like I was always struggling to keep Projucer in sync with XCode. I had a tendency to want to make new files in XCode and then I occasionally had to go back and tell Projucer about them. Either because that’s the way it is or because I wasn’t following some proper workflow, I never got really comfortable.

The reason I switched has more to do with trying to scale to larger projects. If I’m going to build lots of plugins, I might as well share code between them. I believe in XCode, doing this “the right way” means having several interdependent projects and switching between them. That brings with it a ton of baggage. I don’t want my project folders filled with XCode junk. So I was working out of one file and using multiple targets. This works OK until you have to make edits to “some massively shared function in a header” and rebuild everything just to test it. Never really figured out how to do proper unit testing with XCode, either. The short answer is that XCode is too damn complicated for me. If other people like it, that’s awesome, though.

Enter bazel. I use it at work, so it’s already familiar. Unlike writing makefiles, bazel BUILD files are highly readable. Its error messages are mostly friendly. If I want to test “some massively shared function in a header”, it’s easy and the iteration cycle is very fast. Every .cpp/.h pair I write is its own target and I can write it a unit test. It’s not a perfect world, though. Though writing bazel build rules for my own code is beautiful, the major con of using bazel is that writing build rules for third party code can be a nightmare. Juce was a nightmare. Bazel wants to build a dependency tree where ProjectA and ProjectB both depend on Juce and that’s the end of the story. However, the Juce library needs project-specific information to build (the #defines in AppConfig.h) so I had to do some juggling to get around that.

I succeeded in getting everything working on Linux and I’m very happy with it. I really enjoy developing on Linux. However, Linux audio is kind of a sad situation compared to Mac. If I can’t build my plugins on Mac, I’ll never actually use them for making music. So I have to write some build rules that work on Mac. This shouldn’t be too bad now that I have some more understanding of the basic structure. Bazel support for C++/ObjC integration has improved quite a lot in the recent past. I haven’t tried Juce on Windows at all, but probably will someday. (If I have to. I guess.)

If anyone is thinking of going this route, feel free to ping me. If I manage not to scare you off, I’ll at least help you get your BUILD files working.

@Chet_Gnegy Thanks for the detailed answer. Really interesting! Personally I love Xcode, so I’m happy with my JUCE workflow as is (what I’d really like is Xcode on Windows ;)) But for some of my other projects, which don’t use JUCE it sounds like Bazel might be a really nice option. I could never get along with Cmake for some reason…

1 Like

@Chet_Gnegy Have you published your juce rules for Bazel anywhere? I’m interested in using Juce with bazel and would love to take a look.

1 Like

I haven’t looked at this in a while, but I feel like I’m very close to getting it working on OSX. I have it working on Linux. Which OS are you interested in?

All my work is in a private git repo, but I’m happy to share the bits of it that are just for getting Juce set up once I figure out the best way to do that. I’ll try and find some time tonight to copy what I have into a public repo.

2 Likes

I used Projucer once to create the Xcode/VS projects for me for both Win and Mac. Since then I didn’t use the Projucer again and I really don’t see a big benefit from it.

My project is structured into several frameworks which are several projects building a dylib on Mac (dll on Windows).

All the JUCE code builds as a separate framework. If the JUCE sources change I just need to rebuild the JUCE dylib. Plain and easy.

This has worked great for me and it has the big benefit that you still get valuable crash info although using the PACE wrappers.

FWIW, only my two cents :wink:

2 Likes

This only works with Linux. OSX support is coming, but I can’t say when. I started working on this three years ago and haven’t done much in that time. I can add my OSX efforts if someone is willing to help me figure it out.

Note that this isn’t enough code to build something, but it gets you most of the way there. You still have to add the VST code and the JUCE code, but it should be obvious where.

Thanks for encouraging me to dust this off. I think I figured out my OSX bug. It will still take a bit of configuring to get it to build AUs, but I think the worst might be behind me (famous last words)…

On OSX, it still builds only the VST with a .so extension, which seems to be different than OSX, where I usually see .vst.