Skip to content

EmbeddingObjectiveC

Jeff Lindsay edited this page Apr 2, 2021 · 2 revisions

Cgo allows you to embed C code in your Go code. It also allows you to share data between your Go code and C code. This is basically how macdriver works. It uses the Objective-C runtime, a C library, from Go via cgo but wraps it up nicely. You can use the same mechanism to embed actual Objective-C code in your Go code, and even interact with it just like C.

Here is a Go program that hands off execution to a function defined in Objective-C that uses NSLog to say "Hello world":

// main.go
package main

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -lobjc -framework Foundation
#include <Foundation/Foundation.h>

void Main() {
	NSLog(@"Hello world");
}

*/
import "C"

func main() {
	C.Main()
}

The great thing is, we can use the Go toolchain to build this program. That means we can quickly run it using go run:

$ go run main.go
2021-04-02 11:36:52.743 main[21348:2637164] Hello world

We used a capitalized Main in Objective-C to not conflict with the actual main, but it is just a C function (Objective-C being a superset of C) and could be called anything else and be callable from the C import.

Whatever frameworks you want to use in the embedded code must be added to LDFLAGS and then included. Since the Cocoa framework includes many of the common frameworks you'd need, this is often used.

For example, here we'll get the mouse location from NSEvent, which returns an NSPoint, then print to the screen using NSLog:

package main

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -lobjc -framework Cocoa
#include <Cocoa/Cocoa.h>

void Main() {
	NSPoint loc = [NSEvent mouseLocation];
	NSLog(@"Mouse Location: [%f, %f]", loc.x, loc.y);
}

*/
import "C"

func main() {
	C.Main()
}

NSLog uses a format string similar to printf but works with Objective-C objects and types.