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


#1

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?


#2

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.


#3

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


#4

@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.


#5

@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…