Complete implementation of delegates. Update app example with an

NSApplicationDelegate.
This commit is contained in:
Greg 2019-05-09 22:05:04 -04:00
parent 0d2321d516
commit 44b3b75e23
3 changed files with 321 additions and 80 deletions

View File

@ -196,6 +196,7 @@ func Start() (err error) {
w.Import(Config.Imports) w.Import(Config.Imports)
w.SysImport(Config.Sysimports) w.SysImport(Config.Sysimports)
w.Pragma(Config.Pragma) w.Pragma(Config.Pragma)
w.Delegate(Config.Delegates)
if Config.Vaargs == 0 { if Config.Vaargs == 0 {
Config.Vaargs = 16 Config.Vaargs = 16
} }
@ -215,13 +216,10 @@ func Start() (err error) {
w.AddFunction(x) w.AddFunction(x)
} }
case *ast.ObjCProtocolDecl: case *ast.ObjCProtocolDecl:
DELEGATES:
for _,ps := range Config.Delegates { for _,ps := range Config.Delegates {
_ = ps if matches(x.Name,ps) {
//if matches(x.Name,ps) { w.AddProtocol(x)
// w.AddProtocol(x) }
break DELEGATES
//}
} }
case *ast.EnumDecl: case *ast.EnumDecl:
w.AddEnum(x,Config.Enums) w.AddEnum(x,Config.Enums)

View File

@ -2,15 +2,43 @@ package main
//go:generate nswrap //go:generate nswrap
import ( import (
"fmt"
"runtime" "runtime"
"gitlab.wow.st/gmp/nswrap/examples/app/ns" "gitlab.wow.st/gmp/nswrap/examples/app/ns"
) )
func didFinishLaunching(n *ns.NSNotification) {
fmt.Println("Go: did finish launching")
}
func shouldTerminate(s *ns.NSApplication) ns.NSApplicationTerminateReply {
fmt.Println("Go: should terminate")
return ns.NSTerminateNow
}
func willTerminate(n *ns.NSNotification) {
fmt.Println("Go: will terminate")
}
func didBecomeActive(n *ns.NSNotification) {
fmt.Println("Go: did become active")
}
func app() { func app() {
//Lock OS thread because Cocoa uses thread-local storage //Lock OS thread because Cocoa uses thread-local storage
runtime.LockOSThread() runtime.LockOSThread()
a := ns.NSApplicationSharedApplication() a := ns.NSApplicationSharedApplication()
a.SetActivationPolicy(ns.NSApplicationActivationPolicyRegular) a.SetActivationPolicy(ns.NSApplicationActivationPolicyRegular)
//Set up an AppDelegate
del := ns.AppDelegateAlloc()
del.ApplicationDidFinishLaunchingCallback(didFinishLaunching)
del.ApplicationShouldTerminateCallback(shouldTerminate)
del.ApplicationWillTerminateCallback(willTerminate)
del.ApplicationDidBecomeActiveCallback(didBecomeActive)
a.SetDelegate(del)
//Set up an NSWindow
w := ns.NSWindowAlloc().InitWithContentRect( w := ns.NSWindowAlloc().InitWithContentRect(
ns.NSMakeRect(200,200,600,600), ns.NSMakeRect(200,200,600,600),
ns.NSWindowStyleMaskTitled, ns.NSWindowStyleMaskTitled,
@ -22,6 +50,8 @@ func app() {
w.SetTitle(nst("Hi World")) w.SetTitle(nst("Hi World"))
w.MakeKeyAndOrderFront(w) w.MakeKeyAndOrderFront(w)
w.SetAlphaValue(0.85) w.SetAlphaValue(0.85)
//Build a basic menu
m1 := ns.NSMenuAlloc().InitWithTitle(nst("Main")) m1 := ns.NSMenuAlloc().InitWithTitle(nst("Main"))
appItem := ns.NSMenuItemAlloc() appItem := ns.NSMenuItemAlloc()
fileItem := ns.NSMenuItemAlloc() fileItem := ns.NSMenuItemAlloc()
@ -43,13 +73,17 @@ func app() {
a.SetMainMenu(m1) a.SetMainMenu(m1)
//Add a random button that does nothing
b1 := ns.NSButtonWithTitle(nst("push"),s,nil) b1 := ns.NSButtonWithTitle(nst("push"),s,nil)
b1.SetFrame(ns.NSMakeRect(0,550,100,50)) b1.Id.NSView().SetFrame(ns.NSMakeRect(0,550,100,50))
w.ContentView().AddSubview(&b1.NSView,ns.NSWindowAbove,nil) w.ContentView().AddSubview(&b1.NSView,ns.NSWindowAbove,nil)
//Run the app
a.Run() a.Run()
} }
func main() { func main() {
//Run our app in an autorelease pool just for fun
go ns.Autorelease(app) go ns.Autorelease(app)
select { } select { }
} }

View File

@ -22,7 +22,8 @@ type Wrapper struct {
Functions map[string]*Method Functions map[string]*Method
NamedEnums map[string]*Enum NamedEnums map[string]*Enum
AnonEnums []*Enum AnonEnums []*Enum
Protocols []*Protocol Delegates map[string][]string
Protocols map[string]*Protocol
cgoFlags strings.Builder // put cGo directives here cgoFlags strings.Builder // put cGo directives here
cCode strings.Builder // put cGo code here cCode strings.Builder // put cGo code here
@ -43,7 +44,7 @@ func NewWrapper(debug bool) *Wrapper {
Functions: map[string]*Method{}, Functions: map[string]*Method{},
NamedEnums: map[string]*Enum{}, NamedEnums: map[string]*Enum{},
AnonEnums: []*Enum{}, AnonEnums: []*Enum{},
Protocols: []*Protocol{}, Protocols: map[string]*Protocol{},
Processed: map[string]bool{}, Processed: map[string]bool{},
Vaargs: 16, Vaargs: 16,
} }
@ -62,20 +63,20 @@ func (w *Wrapper) Frameworks(ss []string) {
return return
} }
for _,s := range ss { for _,s := range ss {
w.cCode.WriteString(fmt.Sprintf("#import <%s/%s.h>\n",s,s)) w.cgoFlags.WriteString(fmt.Sprintf("#import <%s/%s.h>\n",s,s))
} }
w.cgoFlags.WriteString("#cgo LDFLAGS: -framework " + strings.Join(ss," -framework ")) w.cgoFlags.WriteString("#cgo LDFLAGS: -framework " + strings.Join(ss," -framework "))
} }
func (w *Wrapper) Import(ss []string) { func (w *Wrapper) Import(ss []string) {
for _,s := range ss { for _,s := range ss {
w.cCode.WriteString("\n#import \"" + s + "\"\n") w.cgoFlags.WriteString("\n#import \"" + s + "\"\n")
} }
} }
func (w *Wrapper) SysImport(ss []string) { func (w *Wrapper) SysImport(ss []string) {
for _,s := range ss { for _,s := range ss {
w.cCode.WriteString("\n#import <" + s + ">\n") w.cgoFlags.WriteString("\n#import <" + s + ">\n")
} }
} }
@ -85,6 +86,10 @@ func (w *Wrapper) Pragma(ss []string) {
} }
} }
func (w *Wrapper) Delegate(ds map[string][]string) {
w.Delegates = ds
}
type Property struct { type Property struct {
Name, Attr string Name, Attr string
Type *types.Type Type *types.Type
@ -110,7 +115,7 @@ type Enum struct {
type Protocol struct { type Protocol struct {
Name, GoName string Name, GoName string
Methods []*Method Methods map[string]*Method
Polymorphic map[string]bool Polymorphic map[string]bool
} }
@ -129,9 +134,10 @@ func (m Method) hasFunctionParam() bool {
return false return false
} }
func (w Wrapper) cparamlist(m *Method) (string,string) { func (w Wrapper) cparamlist(m *Method) (string,string,string) {
ns := make([]string,0) ns := make([]string,0)
ret := make([]string,0) ret := make([]string,0)
tps := []string{"void*"}
if !m.ClassMethod { if !m.ClassMethod {
ret = append(ret,"void* o") ret = append(ret,"void* o")
} }
@ -144,8 +150,9 @@ func (w Wrapper) cparamlist(m *Method) (string,string) {
} }
ns = append(ns,p.Vname) ns = append(ns,p.Vname)
ret = append(ret,fmt.Sprintf("%s %s",tp,p.Vname)) ret = append(ret,fmt.Sprintf("%s %s",tp,p.Vname))
tps = append(tps,tp)
} }
return strings.Join(ns,", "),strings.Join(ret,", ") return strings.Join(ns,", "),strings.Join(ret,", "),strings.Join(tps,", ")
} }
func (w Wrapper) objcparamlist(m *Method) string { func (w Wrapper) objcparamlist(m *Method) string {
@ -182,7 +189,6 @@ var goreserved map[string]bool = map[string]bool{
} }
func (w *Wrapper) gpntp(m *Method) ([]string,[]*types.Type,string) { func (w *Wrapper) gpntp(m *Method) ([]string,[]*types.Type,string) {
w.processType(m.Type)
ns := []string{} ns := []string{}
tps := []*types.Type{} tps := []*types.Type{}
if !m.ClassMethod { if !m.ClassMethod {
@ -278,14 +284,16 @@ func (w *Wrapper) AddFunction(n *ast.FunctionDecl) {
} }
func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) { func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) {
p := &Protocol{ p := w.Protocols[n.Name]
Name: n.Name, if p == nil {
GoName: types.NewTypeFromString(n.Name,n.Name).GoType(), fmt.Printf("Adding protocol %s\n",n.Name)
Methods: []*Method{}, p = &Protocol{
Polymorphic: map[string]bool{}, Name: n.Name,
GoName: types.NewTypeFromString(n.Name,n.Name).GoType(),
Methods: map[string]*Method{},
Polymorphic: map[string]bool{},
}
} }
seen := make(map[string]bool)
fmt.Printf("Adding protocol %s\n",n.Name)
for _,c := range n.Children() { for _,c := range n.Children() {
switch x := c.(type) { switch x := c.(type) {
case *ast.ObjCMethodDecl: case *ast.ObjCMethodDecl:
@ -299,16 +307,14 @@ func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) {
var avail bool var avail bool
m.Parameters, avail = w.GetParms(x,p.Name) m.Parameters, avail = w.GetParms(x,p.Name)
if avail { if avail {
fmt.Printf(" method %s\n",m.Name) if p.Methods[m.Name] != nil {
p.Methods = append(p.Methods,m)
if seen[m.Name] {
p.Polymorphic[m.Name] = true p.Polymorphic[m.Name] = true
} }
seen[m.Name] = true p.Methods[m.Name] = m
} }
} }
} }
w.Protocols = append(w.Protocols,p) w.Protocols[n.Name] = p
} }
//FIXME: copied from nswrap/main.go, should put this in a utils package //FIXME: copied from nswrap/main.go, should put this in a utils package
@ -436,12 +442,12 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
Parameters: []*Parameter{}, Parameters: []*Parameter{},
} }
for _,p := range m.Parameters { for _,p := range m.Parameters {
m2.Parameters = append(m2.Parameters, p2 := &Parameter{
&Parameter{
Pname: p.Pname, Pname: p.Pname,
Vname: p.Vname, Vname: p.Vname,
Type: p.Type.CloneToClass(i.Name), Type: p.Type.CloneToClass(i.Name),
}) }
m2.Parameters = append(m2.Parameters,p2)
} }
i.Methods[m.Name] = m2 i.Methods[m.Name] = m2
} }
@ -525,10 +531,6 @@ func (w *Wrapper) GetParms(n ast.Node,class string) ([]*Parameter,bool) {
if !avail.Available() { if !avail.Available() {
return nil, false return nil, false
} }
// check that we found the right number of parameters
//if len(ret) != len(n.Parameters) {
// fmt.Printf("Error in method declaration %s: Wrong number of ParmVarDecl children: %d parameters but %d ParmVarDecl children\n",n.Name,len(n.Parameters),len(ret))
//}
return ret, true return ret, true
} }
@ -685,6 +687,8 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) {
if m.Type.IsFunction() || m.Type.IsFunctionPtr() || m.hasFunctionParam() { if m.Type.IsFunction() || m.Type.IsFunctionPtr() || m.hasFunctionParam() {
return return
} }
w.processType(m.Type)
//w.processType(m.GoClass) //??
gname := strings.Title(m.Name) gname := strings.Title(m.Name)
receiver := "" receiver := ""
switch { switch {
@ -769,8 +773,7 @@ func %s%s(%s) %s {
} else { } else {
cobj = "(" + m.Class + "*)o" cobj = "(" + m.Class + "*)o"
} }
cns,cntps := w.cparamlist(m) cns,cntps,_ := w.cparamlist(m)
_ = cns
if fun { if fun {
return return
} }
@ -829,6 +832,7 @@ func gStringToNsstring(s string) string {
func (w *Wrapper) ProcessEnum(e *Enum) { func (w *Wrapper) ProcessEnum(e *Enum) {
//fmt.Printf("Processing enum (%s)\n",e.Name) //fmt.Printf("Processing enum (%s)\n",e.Name)
w.processType(e.Type)
gtp := "" gtp := ""
ctp := "" ctp := ""
if e.Name != "" { if e.Name != "" {
@ -858,52 +862,237 @@ const %s %s= C.%s
//FIXME: need to disambiguate polymorphic method names. Something like: //FIXME: need to disambiguate polymorphic method names. Something like:
//func Disambiguate([]*Method) []*Method {} ... //func Disambiguate([]*Method) []*Method {} ...
//Can allow user to decide on a disambiguation strategy //Can allow user to decide on a disambiguation strategy
func (w *Wrapper) ProcessProtocol(p *Protocol) { //NOTE: The delegate wrapper does not support variadic callback functions.
fmt.Printf("Processing protocol (%s)\n",p.Name) func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
//To create (per protocol): //To create (per delegate):
//1. ObjC protocol interface //1. ObjC interface
//2. ObjC protocol implementation //2. ObjC implementation
//3. Go type //3. ObjC constructor function
//4. Go constructor //4. Go type
//5. Go dispatch database for callbacks //5. Go constructor
//6. Go dispatch database for callbacks
//To create (per method): //To create (per method):
//1. ObjC function prototypes for go exports //1. ObjC function prototypes for go exports
//2. ObjC constructor function //2. Go callback registration functions
//3. Go exported callback function wrappers //3. Go exported callback function wrappers
var ccode, gocode, goexports strings.Builder //organize output into string builders
//1. ObjC protocol interface var cprotos, ccode, gotypes, gocode, goexports strings.Builder
ccode.WriteString(fmt.Sprintf(`
@interface %s : %s //set up array of methods for this delegate
`,p.Name,p.Name)) methods := []*Method{}
//2. ObjC protocol implementation for _,pname := range ps {
ccode.WriteString(fmt.Sprintf(` proto := w.Protocols[pname]
`)) if proto == nil {
//3. Go type fmt.Printf("Failed to find protocol %s for delegate %s\n",pname,dname)
gocode.WriteString(fmt.Sprintf(` os.Exit(-1)
`)) }
//4. Go constructor fmt.Printf(" proto %s\n",pname)
gocode.WriteString(fmt.Sprintf(` for _,m := range proto.Methods {
`)) if proto.Polymorphic[m.Name] {
//5. Go dispatch database for callbacks //FIXME: skip polymorphic methods for now
gocode.WriteString(fmt.Sprintf(` fmt.Printf(" Skipping polymorphic method '%s'\n",m.Name)
`)) continue
//6. Go callback registration function }
gocode.WriteString(fmt.Sprintf(` methods = append(methods,m)
`)) }
//To create (per method):
for _,m := range p.Methods {
_ = m
//1. ObjC function prototypes for go exports
ccode.WriteString(fmt.Sprintf(`
`))
//2. ObjC constructor function
ccode.WriteString(fmt.Sprintf(`
`))
//3. Go exported callback function wrappers
goexports.WriteString(fmt.Sprintf(`
`))
} }
methprotos := make([]string,len(methods)) // objc method prototypes
gnames := make([]string,len(methods)) // go names for methods
gname := strings.Title(dname) // go name for this Delegate
vnames := make([][]string,len(methods)) // objc variable names
gtypes := make([][]string,len(methods)) // go parameter types for each method
getypes := make([][]string,len(methods)) // parameter types for go export
grtypes := make([]string,len(methods)) // go retrun types for each method
cgtypes := make([]string,len(methods)) // cgo return types
crtypes := make([]string,len(methods)) // c return types for each method
//1. ObjC interface
fmt.Printf("Delegate %s <%s>: %d methods\n",dname,strings.Join(ps,", "),len(methods))
for i,m := range methods {
w.processType(m.Type)
vnames[i] = make([]string,len(m.Parameters)+1)
getypes[i] = make([]string,len(m.Parameters)+1)
vnames[i][0] = "self"
getypes[i][0] = "unsafe.Pointer"
gtypes[i] = make([]string,len(m.Parameters))
//fmt.Printf("%s: %s\n",dname,m.Name)
var parms string
if len(m.Parameters) == 0 {
parms = ""
} else {
pm := m.Parameters[0]
w.processType(pm.Type)
parms = fmt.Sprintf(":(%s)%s",pm.Type.Node.Ctype(),pm.Vname)
vnames[i][1] = pm.Vname
gtypes[i][0] = pm.Type.GoType()
if pm.Type.IsPointer() {
getypes[i][1] = "unsafe.Pointer"
} else {
getypes[i][1] = gtypes[i][0]
}
}
for j := 1; j < len(m.Parameters); j++ {
pm := m.Parameters[j]
w.processType(pm.Type)
parms = parms + fmt.Sprintf(" %s:(%s)%s",pm.Pname,pm.Type.Node.Ctype(),pm.Vname)
vnames[i][j+1] = pm.Vname
gtypes[i][j] = pm.Type.GoType()
var getp string
if pm.Type.IsPointer() {
getp = "unsafe.Pointer"
} else {
getp = gtypes[i][j]
}
getypes[i][j+1] = getp
}
methprotos[i] = fmt.Sprintf(
`- (%s)%s%s;`,m.Type.Node.Ctype(),m.Name,parms)
gnames[i] = strings.Title(m.Name)
if x := m.Type.GoType(); x == "Void" {
grtypes[i] = ""
} else {
grtypes[i] = " " + x
}
crtypes[i] = m.Type.CTypeAttrib()
if m.Type.IsPointer() {
// work around cgo bugs with struct size calculation
/*FIXME: DON'T NEED TO DO THIS?
crtypes[i] = "void*"
if x := m.Type.Node.Qualifiers(); x != "" {
crtypes[i] = x + " " + crtypes[i]
}
if x := m.Type.Node.Annotations(); x != "" {
crtypes[i] = crtypes[i] + " " + x
}
*/
cgtypes[i] = "unsafe.Pointer"
} else {
crtypes[i] = m.Type.CTypeAttrib()
cgtypes[i] = m.Type.CGoType()
}
}
ccode.WriteString(fmt.Sprintf(`
@interface %s : NSObject <%s>
{ }
%s
@end
`,dname,strings.Join(ps,", "),strings.Join(methprotos,"\n")))
//2. ObjC implementation
methdecls := make([]string,len(methods))
for i,mp := range methprotos {
var ret string
if crtypes[i] != "void" {
ret = "return "
}
methdecls[i] = fmt.Sprintf(`
%s
{
%s%s(%s);
}`,mp[:len(mp)-1],ret,gname + gnames[i],strings.Join(vnames[i],", "))
}
ccode.WriteString(fmt.Sprintf(`
@implementation %s
%s
@end
`,dname,strings.Join(methdecls,"\n")))
//3. ObjC constructor function
ccode.WriteString(fmt.Sprintf(`
void*
%sAlloc() {
return [[%s alloc] autorelease];
}
`,dname,dname))
//4. Go type
gotypes.WriteString(fmt.Sprintf(`
type %s struct { Id }
func (o *%s) Ptr() unsafe.Pointer { return unsafe.Pointer(o) }
func (o *Id) %s() *%s { return (*%s)(unsafe.Pointer(o)) }
`,gname,gname,gname,gname,gname))
//5. Go constructor
gocode.WriteString(fmt.Sprintf(`
func %sAlloc() *%s {
return (*%s)(unsafe.Pointer(C.%sAlloc()))
}
`,gname,gname,gname,dname))
//6. Go dispatch database for callbacks
dispitems := make([]string,len(gnames))
for i,n := range gnames {
dispitems[i] = fmt.Sprintf(
` %s func(%s)%s`,n,strings.Join(gtypes[i],", "),grtypes[i])
}
gocode.WriteString(fmt.Sprintf(`
type %sDispatch struct {
%s
}
var %sLookup map[unsafe.Pointer]*%sDispatch =
map[unsafe.Pointer]*%sDispatch{}
`,gname,strings.Join(dispitems,"\n"),gname,gname,gname))
//To create (per method):
cprotos.WriteString("\n\n")
for i,m := range methods {
//1. ObjC function prototypes for go exports
_,_,ctps := w.cparamlist(m)
cprotos.WriteString(fmt.Sprintf(
`%s %s%s(%s);
`,crtypes[i],gname,gnames[i],ctps))
//2. Go callback registration functions
gocode.WriteString(fmt.Sprintf(`
func (d *%s) %sCallback(f func(%s)%s) {
dispatch := %sLookup[d.Ptr()]
if dispatch == nil {
dispatch = &%sDispatch{}
%sLookup[d.Ptr()] = dispatch
}
dispatch.%s = f
}
`,gname,gnames[i],strings.Join(gtypes[i],", "),grtypes[i],gname,gname,gname,gnames[i]))
//3. Go exported callback function wrappers
earglist := []string{"self unsafe.Pointer"}
garglist := []string{}
for j := 1; j < len(vnames[i]); j++ {
earglist = append(earglist,vnames[i][j] + " " + getypes[i][j])
garglist = append(garglist,fmt.Sprintf(
`(%s)(%s)`,gtypes[i][j-1],vnames[i][j]))
}
retdecl := ""
retname := ""
retn := ""
retnparen := ""
crtype := ""
if cgtypes[i] != "C.void" {
retdecl = "var ret " + cgtypes[i] + "\n\t"
retname = " ret"
if cgtypes[i] == "unsafe.Pointer" {
retn = "return unsafe.Pointer("
crtype = " unsafe.Pointer"
} else {
retn = "return (" + cgtypes[i] + ")("
crtype = " " + cgtypes[i]
}
retnparen = ")"
}
goexports.WriteString(fmt.Sprintf(`
//export %s%s
func %s%s(%s)%s {
%scb := %sLookup[self].%s
if cb == nil { return%s }
%scb(%s)%s
}
`,gname,gnames[i],gname,gnames[i],strings.Join(earglist,", "),crtype,retdecl,gname,gnames[i],retname,retn,strings.Join(garglist,", "),retnparen))
}
//DEBUG
w.cCode.WriteString(cprotos.String())
w.cCode.WriteString(ccode.String())
w.goTypes.WriteString(gotypes.String())
w.goCode.WriteString(gocode.String())
w.goExports.WriteString(goexports.String())
} }
func (w *Wrapper) Wrap(toproc []string) { func (w *Wrapper) Wrap(toproc []string) {
@ -918,6 +1107,11 @@ func (w *Wrapper) Wrap(toproc []string) {
fmt.Printf("Error opening file %s\n%s\n",path.Join(w.Package,"main.go"),err) fmt.Printf("Error opening file %s\n%s\n",path.Join(w.Package,"main.go"),err)
os.Exit(-1) os.Exit(-1)
} }
ef,err := os.Create(path.Join(w.Package,"exports.go"))
if err != nil {
fmt.Printf("Error opening file %s\n%s\n",path.Join(w.Package,"exports.go"),err)
os.Exit(-1)
}
fmt.Printf("Writing output to %s\n",path.Join(w.Package,"main.go")) fmt.Printf("Writing output to %s\n",path.Join(w.Package,"main.go"))
pInterfaces := map[string]*Interface{} pInterfaces := map[string]*Interface{}
for _,iface := range toproc { for _,iface := range toproc {
@ -976,13 +1170,17 @@ void*
for _,e := range w.AnonEnums { for _,e := range w.AnonEnums {
w.ProcessEnum(e) w.ProcessEnum(e)
} }
for _,p := range w.Protocols { for n,p := range w.Delegates {
w.ProcessProtocol(p) w.ProcessDelegate(n,p)
} }
fmt.Printf("%d functions\n", len(w.Functions)) fmt.Printf("%d functions\n", len(w.Functions))
fmt.Printf("%d enums\n", len(w.NamedEnums) + len(w.AnonEnums)) fmt.Printf("%d enums\n", len(w.NamedEnums) + len(w.AnonEnums))
of.WriteString("package " + w.Package + "\n\n") of.WriteString("package " + w.Package + "\n\n")
ef.WriteString("package " + w.Package + "\n\n")
of.WriteString(w.cgoFlags.String() + "\n") of.WriteString(w.cgoFlags.String() + "\n")
ef.WriteString(w.cgoFlags.String() + "\n")
of.WriteString(w.cCode.String()) of.WriteString(w.cCode.String())
of.WriteString(` of.WriteString(`
*/ */
@ -997,4 +1195,15 @@ import (
of.WriteString(w.goHelpers.String()) of.WriteString(w.goHelpers.String())
of.WriteString(w.goCode.String()) of.WriteString(w.goCode.String())
of.Close() of.Close()
ef.WriteString(`
*/
import "C"
import (
"unsafe"
)
`)
ef.WriteString(w.goExports.String())
ef.Close()
} }