I don’t actually know why but I was wondering how easy it is to integrate Cocoa with Go. Well [SPOILER] looks like it’s super easy!
The first comfortable piece I encountered, actually, was Go 1.3 changelog where it states:
Finally, the go command now supports packages that import Objective-C files (suffixed
.m) through cgo.
Gimme the code
I know, too much words and no code so far. Turns out that showing a Cocoa window with Go may be as easy as the following:
If you think this is too clean to be true you are kind of right. I actually started this project on GitHub which performs all the ugly bits underneath. I’d really love you to help me get this a little further.
How does it work?
go tool called
cgo which does most of the magic by itself when you build a hybrid project like this. The reference is rather comprehensive but I’d like to highlight a few issues I encountered while wrapping the code up.
1. Keep import “C” after the C statements
Let’s take my
application.go as an example:
As you can see
import "C" is preceded by three directives as per the cgo standard. Make sure the
import "C" directive is right after the actual
C directives otherwise your code won’t build. This is because
C is a pseudo package generated also using the code you provide through those preceding directives.
2. Always specify the compiler directives
Every file exposing the Objective-C bindings should specify the following flags at least.
// #cgo CFLAGS: -x objective-c
// #cgo LDFLAGS: -framework Cocoa
Otherwise you would end up in a long long list of compilation errors. At least this is what happened to me.
3. Always void*
If you end up working with pointers to ObjectiveC classes always convert them into
void* before returning them back to Go. If you don’t, passing them back to C/ObjectiveC might become painful or you may end up with errors like the following:
struct size calculation error off=8 bytesize=0
At least this is what occurred to me. You may help me see the light with this.
4. Keep the non-Go code in separate files
Although cgo allows for the whole non-Go code to go in the comments, please, don’t do that. You’ll end up in unreadable code. Check out my repository for a possible solution.
I don’t know actually. It really took me 1 hour to get this code compiling and running just for the sake of seeing a Cocoa Window. Didn’t expect much more.
Also, I’ve been doing some work with bindings in the past (Qt – Android – JNI, Cocoa – Qt – C++) and it always gets painful when the main framework is not run in the main thread. I don’t know if this will ever the case with Go. I’m not even sure how far this can be pushed especially when it’s about goroutines and
defer‘ed stuff. But, despite not so pleasant past experiences I’d like experimenting this with Go and Cocoa as well.
A question for you
How would you write tests for those bindings?
If you are any interested in this project, please, shout out loud. That would really help me experiment a bit more. Even if you just want to complain about something terribly wrong I did, please, do!