Skip to content

Instantly share code, notes, and snippets.

@13k
Last active September 20, 2022 16:23
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save 13k/872ce11d4c5636fe27d7 to your computer and use it in GitHub Desktop.
Save 13k/872ce11d4c5636fe27d7 to your computer and use it in GitHub Desktop.
Accessing Foundation Framework from Go with cgo
// How to build: "CC=clang go build"
package main
import (
"fmt"
"net/url"
"strconv"
"unsafe"
)
//#cgo CFLAGS: -x objective-c
//#cgo LDFLAGS: -framework Foundation
//#include "foundation.h"
import "C"
// NSString -> C string
func cstring(s *C.NSString) *C.char { return C.nsstring2cstring(s) }
// NSString -> Go string
func gostring(s *C.NSString) string { return C.GoString(cstring(s)) }
// NSNumber -> Go int
func goint(i *C.NSNumber) int { return int(C.nsnumber2int(i)) }
// NSArray length
func nsarraylen(arr *C.NSArray) uint { return uint(C.nsarraylen(arr)) }
// NSArray item
func nsarrayitem(arr *C.NSArray, i uint) unsafe.Pointer {
return C.nsarrayitem(arr, C.ulong(i))
}
// NSURL -> Go url.URL
func gourl(nsurlptr *C.NSURL) *url.URL {
nsurl := *C.nsurldata(nsurlptr)
userInfo := url.UserPassword(
gostring(nsurl.user),
gostring(nsurl.password),
)
host := gostring(nsurl.host)
if nsurl.port != nil {
port := goint(nsurl.port)
host = host + ":" + strconv.FormatInt(int64(port), 10)
}
return &url.URL{
Scheme: gostring(nsurl.scheme),
User: userInfo, // username and password information
Host: host, // host or host:port
Path: gostring(nsurl.path),
RawQuery: gostring(nsurl.query), // encoded query values, without '?'
Fragment: gostring(nsurl.fragment), // fragment for references, without '#'
}
}
// NSArray<NSURL> -> Go []url.URL
func gourls(arr *C.NSArray) []url.URL {
var result []url.URL
length := nsarraylen(arr)
for i := uint(0); i < length; i++ {
nsurl := (*C.NSURL)(nsarrayitem(arr, i))
u := gourl(nsurl)
result = append(result, *u)
}
return result
}
func UserApplicationSupportDirectories() []url.URL {
return gourls(C.UserApplicationSupportDirectories())
}
func main() {
fmt.Printf("%#+v\n", UserApplicationSupportDirectories())
}
#import <Foundation/Foundation.h>
typedef struct _NSURLdata {
NSString *scheme;
NSString *user;
NSString *password;
NSString *host;
NSNumber *port;
NSString *path;
NSString *query;
NSString *fragment;
} NSURLdata;
const char* nsstring2cstring(NSString*);
int nsnumber2int(NSNumber*);
unsigned long nsarraylen(NSArray*);
const void* nsarrayitem(NSArray*, unsigned long);
const NSURLdata* nsurldata(NSURL*);
const NSArray* UserApplicationSupportDirectories();
#import "foundation.h"
const char*
nsstring2cstring(NSString *s) {
if (s == NULL) { return NULL; }
const char *cstr = [s UTF8String];
return cstr;
}
int
nsnumber2int(NSNumber *i) {
if (i == NULL) { return 0; }
return i.intValue;
}
unsigned long
nsarraylen(NSArray *arr) {
if (arr == NULL) { return 0; }
return arr.count;
}
const void*
nsarrayitem(NSArray *arr, unsigned long i) {
if (arr == NULL) { return NULL; }
return [arr objectAtIndex:i];
}
const NSURLdata*
nsurldata(NSURL *url) {
NSURLdata *urldata = malloc(sizeof(NSURLdata));
urldata->scheme = url.scheme;
urldata->user = url.user;
urldata->password = url.password;
urldata->host = url.host;
urldata->port = url.port;
urldata->path = url.path;
urldata->query = url.query;
urldata->fragment = url.fragment;
return urldata;
}
const NSArray*
UserApplicationSupportDirectories() {
NSFileManager *manager = [NSFileManager defaultManager];
return [manager URLsForDirectory: NSApplicationSupportDirectory
inDomains: NSUserDomainMask];
}
@variadico
Copy link

This code

package main

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation
#import <Foundation/Foundation.h>
void hello() {
    NSLog(@"Hello World");
}
*/
import "C"

func main() {
    C.hello()
}

from your Coderwall post doesn't work on macOS 10.12 beta (16A254g). If you install Xcode v7.3.1 (7D1014) and run CC=clang go build this will fail to compile with errors like these.

In file included from /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:10:
In file included from /System/Library/Frameworks/Foundation.framework/Headers/NSArray.h:5:
/System/Library/Frameworks/Foundation.framework/Headers/NSObject.h:44:12: error: unknown property attribute 'class'
@property (class, readonly) BOOL supportsSecureCoding;

Just a heads up! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment