mirror of
https://github.com/mappu/miqt.git
synced 2025-04-01 11:20:23 +00:00
genbindings: multi-package support
This commit is contained in:
parent
61107aa1f2
commit
88ef4e922c
@ -70,13 +70,13 @@ func (p CppParameter) RenderTypeCabi() string {
|
|||||||
|
|
||||||
if ft, ok := p.QFlagsOf(); ok {
|
if ft, ok := p.QFlagsOf(); ok {
|
||||||
if e, ok := KnownEnums[ft.ParameterType]; ok {
|
if e, ok := KnownEnums[ft.ParameterType]; ok {
|
||||||
ret = e.UnderlyingType.RenderTypeCabi()
|
ret = e.Enum.UnderlyingType.RenderTypeCabi()
|
||||||
} else {
|
} else {
|
||||||
ret = "int"
|
ret = "int"
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if e, ok := KnownEnums[p.ParameterType]; ok {
|
} else if e, ok := KnownEnums[p.ParameterType]; ok {
|
||||||
ret = e.UnderlyingType.RenderTypeCabi()
|
ret = e.Enum.UnderlyingType.RenderTypeCabi()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ func emitCABI2CppForwarding(p CppParameter, indent string) (preamble string, for
|
|||||||
|
|
||||||
} else if listType, ok := p.QListOf(); ok {
|
} else if listType, ok := p.QListOf(); ok {
|
||||||
|
|
||||||
preamble += indent + p.ParameterType + " " + nameprefix + "_QList;\n"
|
preamble += indent + p.GetQtCppType().ParameterType + " " + nameprefix + "_QList;\n"
|
||||||
preamble += indent + nameprefix + "_QList.reserve(" + p.ParameterName + "->len);\n"
|
preamble += indent + nameprefix + "_QList.reserve(" + p.ParameterName + "->len);\n"
|
||||||
|
|
||||||
preamble += indent + listType.RenderTypeCabi() + "* " + nameprefix + "_arr = static_cast<" + listType.RenderTypeCabi() + "*>(" + p.ParameterName + "->data);\n"
|
preamble += indent + listType.RenderTypeCabi() + "* " + nameprefix + "_arr = static_cast<" + listType.RenderTypeCabi() + "*>(" + p.ParameterName + "->data);\n"
|
||||||
@ -343,7 +343,7 @@ func emitAssignCppToCabi(assignExpression string, p CppParameter, rvalue string)
|
|||||||
|
|
||||||
shouldReturn = p.RenderTypeQtCpp() + " " + namePrefix + "_ret = "
|
shouldReturn = p.RenderTypeQtCpp() + " " + namePrefix + "_ret = "
|
||||||
|
|
||||||
afterCall += indent + "// Convert QList<> from C++ memory to manually-managed C memory\n"
|
afterCall += indent + "// Convert QSet<> from C++ memory to manually-managed C memory\n"
|
||||||
afterCall += indent + "" + t.RenderTypeCabi() + "* " + namePrefix + "_arr = static_cast<" + t.RenderTypeCabi() + "*>(malloc(sizeof(" + t.RenderTypeCabi() + ") * " + namePrefix + "_ret.size()));\n"
|
afterCall += indent + "" + t.RenderTypeCabi() + "* " + namePrefix + "_arr = static_cast<" + t.RenderTypeCabi() + "*>(malloc(sizeof(" + t.RenderTypeCabi() + ") * " + namePrefix + "_ret.size()));\n"
|
||||||
afterCall += indent + "int " + namePrefix + "_ctr = 0;\n"
|
afterCall += indent + "int " + namePrefix + "_ctr = 0;\n"
|
||||||
afterCall += indent + "QSetIterator<" + t.RenderTypeQtCpp() + "> " + namePrefix + "_itr(" + namePrefix + "_ret);\n"
|
afterCall += indent + "QSetIterator<" + t.RenderTypeQtCpp() + "> " + namePrefix + "_itr(" + namePrefix + "_ret);\n"
|
||||||
@ -448,7 +448,7 @@ func getReferencedTypes(src *CppParsedHeader) []string {
|
|||||||
// Convert to sorted list
|
// Convert to sorted list
|
||||||
foundTypesList := make([]string, 0, len(foundTypes))
|
foundTypesList := make([]string, 0, len(foundTypes))
|
||||||
for ft := range foundTypes {
|
for ft := range foundTypes {
|
||||||
if strings.HasPrefix(ft, "QList<") || strings.HasPrefix(ft, "QVector<") {
|
if strings.HasPrefix(ft, "QList<") || strings.HasPrefix(ft, "QVector<") { // TODO properly exclude via the QListOf() check above
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(ft, "Private") { // qbrush.h finds QGradientPrivate
|
if strings.HasSuffix(ft, "Private") { // qbrush.h finds QGradientPrivate
|
||||||
@ -475,12 +475,16 @@ func cabiClassName(className string) string {
|
|||||||
return strings.Replace(className, `::`, `__`, -1)
|
return strings.Replace(className, `::`, `__`, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitBindingHeader(src *CppParsedHeader, filename string) (string, error) {
|
func emitBindingHeader(src *CppParsedHeader, filename string, packageName string) (string, error) {
|
||||||
ret := strings.Builder{}
|
ret := strings.Builder{}
|
||||||
|
|
||||||
includeGuard := "GEN_" + strings.ToUpper(strings.Replace(filename, `.`, `_`, -1))
|
includeGuard := "GEN_" + strings.ToUpper(strings.Replace(filename, `.`, `_`, -1))
|
||||||
|
|
||||||
bindingInclude := "../libmiqt/libmiqt.h"
|
bindingInclude := "../libmiqt/libmiqt.h"
|
||||||
|
if packageName != "qt" {
|
||||||
|
bindingInclude = "../" + bindingInclude
|
||||||
|
}
|
||||||
|
|
||||||
ret.WriteString(`#ifndef ` + includeGuard + `
|
ret.WriteString(`#ifndef ` + includeGuard + `
|
||||||
#define ` + includeGuard + `
|
#define ` + includeGuard + `
|
||||||
|
|
||||||
@ -592,7 +596,7 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
|
|||||||
ret.WriteString(`#include <` + ref + ">\n")
|
ret.WriteString(`#include <` + ref + ">\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.WriteString(`#include "` + filename + "\"\n")
|
ret.WriteString(`#include <` + filename + ">\n")
|
||||||
ret.WriteString(`#include "gen_` + filename + "\"\n")
|
ret.WriteString(`#include "gen_` + filename + "\"\n")
|
||||||
ret.WriteString("#include \"_cgo_export.h\"\n\n")
|
ret.WriteString("#include \"_cgo_export.h\"\n\n")
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ func goReservedWord(s string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p CppParameter) RenderTypeGo() string {
|
func (p CppParameter) RenderTypeGo(gfs *goFileState) string {
|
||||||
if p.Pointer && p.ParameterType == "char" {
|
if p.Pointer && p.ParameterType == "char" {
|
||||||
return "string"
|
return "string"
|
||||||
}
|
}
|
||||||
@ -28,11 +28,11 @@ func (p CppParameter) RenderTypeGo() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if t, ok := p.QListOf(); ok {
|
if t, ok := p.QListOf(); ok {
|
||||||
return "[]" + t.RenderTypeGo()
|
return "[]" + t.RenderTypeGo(gfs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if t, ok := p.QSetOf(); ok {
|
if t, ok := p.QSetOf(); ok {
|
||||||
return "map[" + t.RenderTypeGo() + "]struct{}"
|
return "map[" + t.RenderTypeGo(gfs) + "]struct{}"
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.ParameterType == "void" && p.Pointer {
|
if p.ParameterType == "void" && p.Pointer {
|
||||||
@ -40,10 +40,6 @@ func (p CppParameter) RenderTypeGo() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret := ""
|
ret := ""
|
||||||
if p.ByRef || p.Pointer {
|
|
||||||
ret += "*"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch p.ParameterType {
|
switch p.ParameterType {
|
||||||
case "unsigned char", "uchar", "quint8":
|
case "unsigned char", "uchar", "quint8":
|
||||||
// Go byte is unsigned
|
// Go byte is unsigned
|
||||||
@ -101,10 +97,25 @@ func (p CppParameter) RenderTypeGo() string {
|
|||||||
default:
|
default:
|
||||||
|
|
||||||
if ft, ok := p.QFlagsOf(); ok {
|
if ft, ok := p.QFlagsOf(); ok {
|
||||||
ret += cabiClassName(ft.ParameterType)
|
|
||||||
|
|
||||||
} else if p.IsKnownEnum() {
|
if enumInfo, ok := KnownEnums[ft.ParameterType]; ok && enumInfo.PackageName != gfs.currentPackageName {
|
||||||
ret += cabiClassName(p.ParameterType)
|
// Cross-package
|
||||||
|
ret += enumInfo.PackageName + "." + cabiClassName(ft.ParameterType)
|
||||||
|
gfs.imports[importPathForQtPackage(enumInfo.PackageName)] = struct{}{}
|
||||||
|
} else {
|
||||||
|
// Same package
|
||||||
|
ret += cabiClassName(ft.ParameterType)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if enumInfo, ok := KnownEnums[p.ParameterType]; ok {
|
||||||
|
if enumInfo.PackageName != gfs.currentPackageName {
|
||||||
|
// Cross-package
|
||||||
|
ret += enumInfo.PackageName + "." + cabiClassName(p.ParameterType)
|
||||||
|
gfs.imports[importPathForQtPackage(enumInfo.PackageName)] = struct{}{}
|
||||||
|
} else {
|
||||||
|
// Same package
|
||||||
|
ret += cabiClassName(p.ParameterType)
|
||||||
|
}
|
||||||
|
|
||||||
} else if strings.Contains(p.ParameterType, `::`) {
|
} else if strings.Contains(p.ParameterType, `::`) {
|
||||||
// Inner class
|
// Inner class
|
||||||
@ -117,6 +128,15 @@ func (p CppParameter) RenderTypeGo() string {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pkg, ok := KnownClassnames[p.ParameterType]; ok && pkg.PackageName != gfs.currentPackageName {
|
||||||
|
ret = pkg.PackageName + "." + ret
|
||||||
|
gfs.imports[importPathForQtPackage(pkg.PackageName)] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.ByRef || p.Pointer {
|
||||||
|
ret = "*" + ret
|
||||||
|
}
|
||||||
|
|
||||||
return ret // ignore const
|
return ret // ignore const
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +174,7 @@ func (p CppParameter) parameterTypeCgo() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitParametersGo(params []CppParameter) string {
|
func (gfs *goFileState) emitParametersGo(params []CppParameter) string {
|
||||||
tmp := make([]string, 0, len(params))
|
tmp := make([]string, 0, len(params))
|
||||||
|
|
||||||
skipNext := false
|
skipNext := false
|
||||||
@ -171,7 +191,7 @@ func emitParametersGo(params []CppParameter) string {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Ordinary parameter
|
// Ordinary parameter
|
||||||
tmp = append(tmp, p.ParameterName+" "+p.RenderTypeGo())
|
tmp = append(tmp, p.ParameterName+" "+p.RenderTypeGo(gfs))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,7 +199,8 @@ func emitParametersGo(params []CppParameter) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type goFileState struct {
|
type goFileState struct {
|
||||||
imports map[string]struct{}
|
imports map[string]struct{}
|
||||||
|
currentPackageName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gfs *goFileState) emitParametersGo2CABIForwarding(m CppMethod) (preamble string, forwarding string) {
|
func (gfs *goFileState) emitParametersGo2CABIForwarding(m CppMethod) (preamble string, forwarding string) {
|
||||||
@ -279,7 +300,16 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble
|
|||||||
} else if /*(p.Pointer || p.ByRef) &&*/ p.QtClassType() {
|
} else if /*(p.Pointer || p.ByRef) &&*/ p.QtClassType() {
|
||||||
// The C++ type is a pointer to Qt class
|
// The C++ type is a pointer to Qt class
|
||||||
// We want our functions to accept the Go wrapper type, and forward as cPointer()
|
// We want our functions to accept the Go wrapper type, and forward as cPointer()
|
||||||
rvalue = p.ParameterName + ".cPointer()"
|
// cPointer() returns the cgo pointer which only works in the same package -
|
||||||
|
// anything cross-package needs to go via unsafe.Pointer
|
||||||
|
|
||||||
|
if classInfo, ok := KnownClassnames[p.ParameterType]; ok && gfs.currentPackageName != classInfo.PackageName {
|
||||||
|
// Cross-package
|
||||||
|
rvalue = "(" + p.parameterTypeCgo() + ")(" + p.ParameterName + ".UnsafePointer())"
|
||||||
|
} else {
|
||||||
|
// Same package
|
||||||
|
rvalue = p.ParameterName + ".cPointer()"
|
||||||
|
}
|
||||||
|
|
||||||
} else if p.IntType() || p.IsFlagType() || p.IsKnownEnum() || p.ParameterType == "bool" {
|
} else if p.IntType() || p.IsFlagType() || p.IsKnownEnum() || p.ParameterType == "bool" {
|
||||||
if p.Pointer || p.ByRef {
|
if p.Pointer || p.ByRef {
|
||||||
@ -331,7 +361,7 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
|||||||
|
|
||||||
shouldReturn = "var " + namePrefix + "_ma *C.struct_miqt_array = "
|
shouldReturn = "var " + namePrefix + "_ma *C.struct_miqt_array = "
|
||||||
|
|
||||||
afterword += namePrefix + "_ret := make([]" + t.RenderTypeGo() + ", int(" + namePrefix + "_ma.len))\n"
|
afterword += namePrefix + "_ret := make([]" + t.RenderTypeGo(gfs) + ", int(" + namePrefix + "_ma.len))\n"
|
||||||
afterword += namePrefix + "_outCast := (*[0xffff]" + t.parameterTypeCgo() + ")(unsafe.Pointer(" + namePrefix + "_ma.data)) // hey ya\n"
|
afterword += namePrefix + "_outCast := (*[0xffff]" + t.parameterTypeCgo() + ")(unsafe.Pointer(" + namePrefix + "_ma.data)) // hey ya\n"
|
||||||
afterword += "for i := 0; i < int(" + namePrefix + "_ma.len); i++ {\n"
|
afterword += "for i := 0; i < int(" + namePrefix + "_ma.len); i++ {\n"
|
||||||
|
|
||||||
@ -347,7 +377,7 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
|||||||
|
|
||||||
shouldReturn = "var " + namePrefix + "_ma *C.struct_miqt_array = "
|
shouldReturn = "var " + namePrefix + "_ma *C.struct_miqt_array = "
|
||||||
|
|
||||||
afterword += namePrefix + "_ret := make(map[" + t.RenderTypeGo() + "]struct{}, int(" + namePrefix + "_ma.len))\n"
|
afterword += namePrefix + "_ret := make(map[" + t.RenderTypeGo(gfs) + "]struct{}, int(" + namePrefix + "_ma.len))\n"
|
||||||
afterword += namePrefix + "_outCast := (*[0xffff]" + t.parameterTypeCgo() + ")(unsafe.Pointer(" + namePrefix + "_ma.data)) // hey ya\n"
|
afterword += namePrefix + "_outCast := (*[0xffff]" + t.parameterTypeCgo() + ")(unsafe.Pointer(" + namePrefix + "_ma.data)) // hey ya\n"
|
||||||
afterword += "for i := 0; i < int(" + namePrefix + "_ma.len); i++ {\n"
|
afterword += "for i := 0; i < int(" + namePrefix + "_ma.len); i++ {\n"
|
||||||
|
|
||||||
@ -362,9 +392,15 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
|||||||
// Construct our Go type based on this inner CABI type
|
// Construct our Go type based on this inner CABI type
|
||||||
shouldReturn = "" + namePrefix + "_ret := "
|
shouldReturn = "" + namePrefix + "_ret := "
|
||||||
|
|
||||||
|
crossPackage := ""
|
||||||
|
if pkg, ok := KnownClassnames[rt.ParameterType]; ok && pkg.PackageName != gfs.currentPackageName {
|
||||||
|
crossPackage = pkg.PackageName + "."
|
||||||
|
gfs.imports[importPathForQtPackage(pkg.PackageName)] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
if rt.Pointer || rt.ByRef {
|
if rt.Pointer || rt.ByRef {
|
||||||
gfs.imports["unsafe"] = struct{}{}
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
return assignExpr + " new" + cabiClassName(rt.ParameterType) + "_U(unsafe.Pointer(" + rvalue + "))"
|
return assignExpr + " " + crossPackage + "UnsafeNew" + cabiClassName(rt.ParameterType) + "(unsafe.Pointer(" + rvalue + "))"
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// This is return by value, but CABI has new'd it into a
|
// This is return by value, but CABI has new'd it into a
|
||||||
@ -373,7 +409,13 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
|||||||
// finalizer to automatically Delete once the type goes out
|
// finalizer to automatically Delete once the type goes out
|
||||||
// of Go scope
|
// of Go scope
|
||||||
|
|
||||||
afterword += namePrefix + "_goptr := new" + cabiClassName(rt.ParameterType) + "(" + namePrefix + "_ret)\n"
|
if crossPackage == "" {
|
||||||
|
afterword += namePrefix + "_goptr := new" + cabiClassName(rt.ParameterType) + "(" + namePrefix + "_ret)\n"
|
||||||
|
} else {
|
||||||
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
|
afterword += namePrefix + "_goptr := " + crossPackage + "UnsafeNew" + cabiClassName(rt.ParameterType) + "(unsafe.Pointer(" + namePrefix + "_ret))\n"
|
||||||
|
|
||||||
|
}
|
||||||
afterword += namePrefix + "_goptr.GoGC() // Qt uses pass-by-value semantics for this type. Mimic with finalizer\n"
|
afterword += namePrefix + "_goptr.GoGC() // Qt uses pass-by-value semantics for this type. Mimic with finalizer\n"
|
||||||
|
|
||||||
// If this is a function return, we have converted value-returned Qt types to pointers
|
// If this is a function return, we have converted value-returned Qt types to pointers
|
||||||
@ -389,17 +431,17 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
|||||||
} else if rt.IntType() || rt.IsKnownEnum() || rt.IsFlagType() || rt.ParameterType == "bool" || rt.QtCppOriginalType != nil {
|
} else if rt.IntType() || rt.IsKnownEnum() || rt.IsFlagType() || rt.ParameterType == "bool" || rt.QtCppOriginalType != nil {
|
||||||
// Need to cast Cgo type to Go int type
|
// Need to cast Cgo type to Go int type
|
||||||
// Optimize assignment to avoid temporary
|
// Optimize assignment to avoid temporary
|
||||||
return assignExpr + "(" + rt.RenderTypeGo() + ")(" + rvalue + ")\n"
|
return assignExpr + "(" + rt.RenderTypeGo(gfs) + ")(" + rvalue + ")\n"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return shouldReturn + " " + rvalue + "\n" + afterword
|
return shouldReturn + " " + rvalue + "\n" + afterword
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitGo(src *CppParsedHeader, headerName string) (string, error) {
|
func emitGo(src *CppParsedHeader, headerName string, packageName string) (string, error) {
|
||||||
|
|
||||||
ret := strings.Builder{}
|
ret := strings.Builder{}
|
||||||
ret.WriteString(`package qt
|
ret.WriteString(`package ` + packageName + `
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@ -413,7 +455,8 @@ import "C"
|
|||||||
`)
|
`)
|
||||||
|
|
||||||
gfs := goFileState{
|
gfs := goFileState{
|
||||||
imports: map[string]struct{}{},
|
imports: map[string]struct{}{},
|
||||||
|
currentPackageName: packageName,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if short-named enums are allowed.
|
// Check if short-named enums are allowed.
|
||||||
@ -457,7 +500,7 @@ import "C"
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret.WriteString(`
|
ret.WriteString(`
|
||||||
type ` + goEnumName + ` ` + e.UnderlyingType.RenderTypeGo() + `
|
type ` + goEnumName + ` ` + e.UnderlyingType.RenderTypeGo(&gfs) + `
|
||||||
`)
|
`)
|
||||||
|
|
||||||
if len(e.Entries) > 0 {
|
if len(e.Entries) > 0 {
|
||||||
@ -483,7 +526,16 @@ import "C"
|
|||||||
|
|
||||||
// Embed all inherited types to directly allow calling inherited methods
|
// Embed all inherited types to directly allow calling inherited methods
|
||||||
for _, base := range c.Inherits {
|
for _, base := range c.Inherits {
|
||||||
ret.WriteString("*" + cabiClassName(base) + "\n")
|
|
||||||
|
if pkg, ok := KnownClassnames[base]; ok && pkg.PackageName != gfs.currentPackageName {
|
||||||
|
// Cross-package parent class
|
||||||
|
ret.WriteString("*" + pkg.PackageName + "." + cabiClassName(base) + "\n")
|
||||||
|
gfs.imports[importPathForQtPackage(pkg.PackageName)] = struct{}{}
|
||||||
|
} else {
|
||||||
|
// Same-package parent class
|
||||||
|
ret.WriteString("*" + cabiClassName(base) + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.WriteString(`
|
ret.WriteString(`
|
||||||
@ -496,12 +548,26 @@ import "C"
|
|||||||
return this.h
|
return this.h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *` + goClassName + `) UnsafePointer() unsafe.Pointer {
|
||||||
|
if this == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return unsafe.Pointer(this.h)
|
||||||
|
}
|
||||||
|
|
||||||
`)
|
`)
|
||||||
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
|
|
||||||
localInit := "h: h"
|
localInit := "h: h"
|
||||||
for _, base := range c.Inherits {
|
for _, base := range c.Inherits {
|
||||||
gfs.imports["unsafe"] = struct{}{}
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
localInit += ", " + cabiClassName(base) + ": new" + cabiClassName(base) + "_U(unsafe.Pointer(h))"
|
|
||||||
|
ctorPrefix := ""
|
||||||
|
if pkg, ok := KnownClassnames[base]; ok && pkg.PackageName != gfs.currentPackageName {
|
||||||
|
ctorPrefix = pkg.PackageName + "."
|
||||||
|
}
|
||||||
|
|
||||||
|
localInit += ", " + cabiClassName(base) + ": " + ctorPrefix + "UnsafeNew" + cabiClassName(base) + "(unsafe.Pointer(h))"
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.WriteString(`
|
ret.WriteString(`
|
||||||
@ -520,7 +586,7 @@ import "C"
|
|||||||
// that never happens in Go's type system.
|
// that never happens in Go's type system.
|
||||||
gfs.imports["unsafe"] = struct{}{}
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
ret.WriteString(`
|
ret.WriteString(`
|
||||||
func new` + goClassName + `_U(h unsafe.Pointer) *` + goClassName + ` {
|
func UnsafeNew` + goClassName + `(h unsafe.Pointer) *` + goClassName + ` {
|
||||||
return new` + goClassName + `( (*C.` + goClassName + `)(h) )
|
return new` + goClassName + `( (*C.` + goClassName + `)(h) )
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,7 +599,7 @@ import "C"
|
|||||||
gfs.imports["runtime"] = struct{}{}
|
gfs.imports["runtime"] = struct{}{}
|
||||||
ret.WriteString(`
|
ret.WriteString(`
|
||||||
// New` + goClassName + maybeSuffix(i) + ` constructs a new ` + c.ClassName + ` object.
|
// New` + goClassName + maybeSuffix(i) + ` constructs a new ` + c.ClassName + ` object.
|
||||||
func New` + goClassName + maybeSuffix(i) + `(` + emitParametersGo(ctor.Parameters) + `) *` + goClassName + ` {
|
func New` + goClassName + maybeSuffix(i) + `(` + gfs.emitParametersGo(ctor.Parameters) + `) *` + goClassName + ` {
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
` + preamble + ` ret := C.` + goClassName + `_new` + maybeSuffix(i) + `(` + forwarding + `)
|
` + preamble + ` ret := C.` + goClassName + `_new` + maybeSuffix(i) + `(` + forwarding + `)
|
||||||
return new` + goClassName + `(ret)
|
return new` + goClassName + `(ret)
|
||||||
@ -546,7 +612,7 @@ import "C"
|
|||||||
} else {
|
} else {
|
||||||
ret.WriteString(`
|
ret.WriteString(`
|
||||||
// New` + goClassName + maybeSuffix(i) + ` constructs a new ` + c.ClassName + ` object.
|
// New` + goClassName + maybeSuffix(i) + ` constructs a new ` + c.ClassName + ` object.
|
||||||
func New` + goClassName + maybeSuffix(i) + `(` + emitParametersGo(ctor.Parameters) + `) *` + goClassName + ` {
|
func New` + goClassName + maybeSuffix(i) + `(` + gfs.emitParametersGo(ctor.Parameters) + `) *` + goClassName + ` {
|
||||||
` + preamble + ` ret := C.` + goClassName + `_new` + maybeSuffix(i) + `(` + forwarding + `)
|
` + preamble + ` ret := C.` + goClassName + `_new` + maybeSuffix(i) + `(` + forwarding + `)
|
||||||
return new` + goClassName + `(ret)
|
return new` + goClassName + `(ret)
|
||||||
}
|
}
|
||||||
@ -558,7 +624,7 @@ import "C"
|
|||||||
for _, m := range c.Methods {
|
for _, m := range c.Methods {
|
||||||
preamble, forwarding := gfs.emitParametersGo2CABIForwarding(m)
|
preamble, forwarding := gfs.emitParametersGo2CABIForwarding(m)
|
||||||
|
|
||||||
returnTypeDecl := m.ReturnType.RenderTypeGo()
|
returnTypeDecl := m.ReturnType.RenderTypeGo(&gfs)
|
||||||
if returnTypeDecl == "void" {
|
if returnTypeDecl == "void" {
|
||||||
returnTypeDecl = ""
|
returnTypeDecl = ""
|
||||||
}
|
}
|
||||||
@ -580,7 +646,7 @@ import "C"
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret.WriteString(`
|
ret.WriteString(`
|
||||||
func ` + receiverAndMethod + `(` + emitParametersGo(m.Parameters) + `) ` + returnTypeDecl + ` {`)
|
func ` + receiverAndMethod + `(` + gfs.emitParametersGo(m.Parameters) + `) ` + returnTypeDecl + ` {`)
|
||||||
if m.LinuxOnly {
|
if m.LinuxOnly {
|
||||||
gfs.imports["runtime"] = struct{}{}
|
gfs.imports["runtime"] = struct{}{}
|
||||||
ret.WriteString(`
|
ret.WriteString(`
|
||||||
@ -613,13 +679,13 @@ import "C"
|
|||||||
conversion += gfs.emitCabiToGo(fmt.Sprintf("slotval%d := ", i+1), pp, pp.ParameterName) + "\n"
|
conversion += gfs.emitCabiToGo(fmt.Sprintf("slotval%d := ", i+1), pp, pp.ParameterName) + "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.WriteString(`func (this *` + goClassName + `) On` + m.SafeMethodName() + `(slot func(` + emitParametersGo(m.Parameters) + `)) {
|
ret.WriteString(`func (this *` + goClassName + `) On` + m.SafeMethodName() + `(slot func(` + gfs.emitParametersGo(m.Parameters) + `)) {
|
||||||
C.` + goClassName + `_connect_` + m.SafeMethodName() + `(this.h, C.intptr_t(cgo.NewHandle(slot)) )
|
C.` + goClassName + `_connect_` + m.SafeMethodName() + `(this.h, C.intptr_t(cgo.NewHandle(slot)) )
|
||||||
}
|
}
|
||||||
|
|
||||||
//export miqt_exec_callback_` + goClassName + `_` + m.SafeMethodName() + `
|
//export miqt_exec_callback_` + goClassName + `_` + m.SafeMethodName() + `
|
||||||
func miqt_exec_callback_` + goClassName + `_` + m.SafeMethodName() + `(cb C.intptr_t` + ifv(len(m.Parameters) > 0, ", ", "") + strings.Join(cgoNamedParams, `, `) + `) {
|
func miqt_exec_callback_` + goClassName + `_` + m.SafeMethodName() + `(cb C.intptr_t` + ifv(len(m.Parameters) > 0, ", ", "") + strings.Join(cgoNamedParams, `, `) + `) {
|
||||||
gofunc, ok := cgo.Handle(cb).Value().(func(` + emitParametersGo(m.Parameters) + `))
|
gofunc, ok := cgo.Handle(cb).Value().(func(` + gfs.emitParametersGo(m.Parameters) + `))
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("miqt: callback of non-callback type (heap corruption?)")
|
panic("miqt: callback of non-callback type (heap corruption?)")
|
||||||
}
|
}
|
||||||
|
@ -10,20 +10,20 @@ func InsertTypedefs() {
|
|||||||
// Seed well-known typedefs
|
// Seed well-known typedefs
|
||||||
|
|
||||||
// QString is deleted from this binding
|
// QString is deleted from this binding
|
||||||
KnownTypedefs["QStringList"] = CppTypedef{"QStringList", parseSingleTypeString("QList<QString>")}
|
KnownTypedefs["QStringList"] = lookupResultTypedef{"qt", CppTypedef{"QStringList", parseSingleTypeString("QList<QString>")}}
|
||||||
|
|
||||||
// FIXME this isn't picked up automatically because QFile inherits QFileDevice and the name refers to its parent class
|
// FIXME this isn't picked up automatically because QFile inherits QFileDevice and the name refers to its parent class
|
||||||
KnownTypedefs["QFile::FileTime"] = CppTypedef{"QFile::FileTime", parseSingleTypeString("QFileDevice::FileTime")}
|
KnownTypedefs["QFile::FileTime"] = lookupResultTypedef{"qt", CppTypedef{"QFile::FileTime", parseSingleTypeString("QFileDevice::FileTime")}}
|
||||||
|
|
||||||
// n.b. Qt 5 only
|
// n.b. Qt 5 only
|
||||||
KnownTypedefs["QLineF::IntersectionType"] = CppTypedef{"QLineF::IntersectionType", parseSingleTypeString("QLineF::IntersectType")}
|
KnownTypedefs["QLineF::IntersectionType"] = lookupResultTypedef{"qt", CppTypedef{"QLineF::IntersectionType", parseSingleTypeString("QLineF::IntersectType")}}
|
||||||
|
|
||||||
// Not sure the reason for this one
|
// Not sure the reason for this one
|
||||||
KnownTypedefs["QSocketDescriptor::DescriptorType"] = CppTypedef{"QSocketDescriptor::DescriptorType", parseSingleTypeString("QSocketNotifier::Type")}
|
KnownTypedefs["QSocketDescriptor::DescriptorType"] = lookupResultTypedef{"qt", CppTypedef{"QSocketDescriptor::DescriptorType", parseSingleTypeString("QSocketNotifier::Type")}}
|
||||||
|
|
||||||
// QFile doesn't see QFileDevice parent class enum
|
// QFile doesn't see QFileDevice parent class enum
|
||||||
KnownTypedefs["QFile::Permissions"] = CppTypedef{"QFile::Permissions", parseSingleTypeString("QFileDevice::Permissions")}
|
KnownTypedefs["QFile::Permissions"] = lookupResultTypedef{"qt", CppTypedef{"QFile::Permissions", parseSingleTypeString("QFileDevice::Permissions")}}
|
||||||
KnownTypedefs["QFileDevice::Permissions"] = CppTypedef{"QFile::Permissions", parseSingleTypeString("QFlags<QFileDevice::Permission>")}
|
KnownTypedefs["QFileDevice::Permissions"] = lookupResultTypedef{"qt", CppTypedef{"QFile::Permissions", parseSingleTypeString("QFlags<QFileDevice::Permission>")}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AllowHeader(fullpath string) bool {
|
func AllowHeader(fullpath string) bool {
|
||||||
|
@ -5,16 +5,30 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type lookupResultClass struct {
|
||||||
|
PackageName string
|
||||||
|
}
|
||||||
|
|
||||||
|
type lookupResultTypedef struct {
|
||||||
|
PackageName string
|
||||||
|
Typedef CppTypedef
|
||||||
|
}
|
||||||
|
|
||||||
|
type lookupResultEnum struct {
|
||||||
|
PackageName string
|
||||||
|
Enum CppEnum
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
KnownClassnames map[string]struct{} // Entries of the form QFoo::Bar if it is an inner class
|
KnownClassnames map[string]lookupResultClass // Entries of the form QFoo::Bar if it is an inner class
|
||||||
KnownTypedefs map[string]CppTypedef
|
KnownTypedefs map[string]lookupResultTypedef
|
||||||
KnownEnums map[string]CppEnum
|
KnownEnums map[string]lookupResultEnum
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
KnownClassnames = make(map[string]struct{})
|
KnownClassnames = make(map[string]lookupResultClass)
|
||||||
KnownTypedefs = make(map[string]CppTypedef)
|
KnownTypedefs = make(map[string]lookupResultTypedef)
|
||||||
KnownEnums = make(map[string]CppEnum)
|
KnownEnums = make(map[string]lookupResultEnum)
|
||||||
}
|
}
|
||||||
|
|
||||||
type CppParameter struct {
|
type CppParameter struct {
|
||||||
|
@ -18,6 +18,15 @@ const (
|
|||||||
BaseModule = "github.com/mappu/miqt"
|
BaseModule = "github.com/mappu/miqt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func importPathForQtPackage(packageName string) string {
|
||||||
|
switch packageName {
|
||||||
|
case "qt":
|
||||||
|
return BaseModule + "/qt"
|
||||||
|
default:
|
||||||
|
return BaseModule + "/qt/" + packageName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func cacheFilePath(inputHeader string) string {
|
func cacheFilePath(inputHeader string) string {
|
||||||
return filepath.Join("cachedir", strings.Replace(inputHeader, `/`, `__`, -1)+".json")
|
return filepath.Join("cachedir", strings.Replace(inputHeader, `/`, `__`, -1)+".json")
|
||||||
}
|
}
|
||||||
@ -80,24 +89,45 @@ func cleanGeneratedFilesInDir(dirpath string) {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
clang := flag.String("clang", "clang", "Custom path to clang")
|
clang := flag.String("clang", "clang", "Custom path to clang")
|
||||||
cflags := flag.String("cflags", `-DQT_WIDGETS_LIB -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtCore -DQT_GUI_LIB -I/usr/include/x86_64-linux-gnu/qt5/QtGui -DQT_CORE_LIB`, "Cflags to pass to clang (e.g. `pkg-config --cflags Qt5Widgets`)")
|
outDir := flag.String("outdir", "../../", "Output directory for generated gen_** files")
|
||||||
outDir := flag.String("outdir", "../../qt", "Output directory for generated gen_** files")
|
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
var includeFiles []string
|
generate(
|
||||||
|
"qt",
|
||||||
|
[]string{
|
||||||
|
"/usr/include/x86_64-linux-gnu/qt5/QtCore",
|
||||||
|
"/usr/include/x86_64-linux-gnu/qt5/QtGui",
|
||||||
|
"/usr/include/x86_64-linux-gnu/qt5/QtWidgets",
|
||||||
|
},
|
||||||
|
*clang,
|
||||||
|
// pkg-config --cflags Qt5Widgets
|
||||||
|
strings.Fields(`-DQT_WIDGETS_LIB -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtCore -DQT_GUI_LIB -I/usr/include/x86_64-linux-gnu/qt5/QtGui -DQT_CORE_LIB`),
|
||||||
|
filepath.Join(*outDir, "qt"),
|
||||||
|
)
|
||||||
|
|
||||||
for _, srcDir := range []string{
|
generate(
|
||||||
"/usr/include/x86_64-linux-gnu/qt5/QtCore",
|
"qprintsupport",
|
||||||
"/usr/include/x86_64-linux-gnu/qt5/QtGui",
|
[]string{
|
||||||
"/usr/include/x86_64-linux-gnu/qt5/QtWidgets",
|
"/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport",
|
||||||
} {
|
},
|
||||||
|
*clang,
|
||||||
|
// pkg-config --cflags Qt5PrintSupport
|
||||||
|
strings.Fields(`-DQT_PRINTSUPPORT_LIB -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I/usr/include/x86_64-linux-gnu/qt5/QtGui -DQT_WIDGETS_LIB -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -DQT_GUI_LIB -DQT_CORE_LIB`),
|
||||||
|
filepath.Join(*outDir, "qt/qprintsupport"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generate(packageName string, srcDirs []string, clangBin string, cflags []string, outDir string) {
|
||||||
|
|
||||||
|
var includeFiles []string
|
||||||
|
for _, srcDir := range srcDirs {
|
||||||
includeFiles = append(includeFiles, findHeadersInDir(srcDir)...)
|
includeFiles = append(includeFiles, findHeadersInDir(srcDir)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Found %d header files to process.", len(includeFiles))
|
log.Printf("Found %d header files to process.", len(includeFiles))
|
||||||
|
|
||||||
cleanGeneratedFilesInDir(*outDir)
|
cleanGeneratedFilesInDir(outDir)
|
||||||
|
|
||||||
var processHeaders []*CppParsedHeader
|
var processHeaders []*CppParsedHeader
|
||||||
atr := astTransformRedundant{
|
atr := astTransformRedundant{
|
||||||
@ -110,7 +140,7 @@ func main() {
|
|||||||
// PASS 0 (Fill clang cache)
|
// PASS 0 (Fill clang cache)
|
||||||
//
|
//
|
||||||
|
|
||||||
generateClangCaches(includeFiles, *clang, strings.Fields(*cflags))
|
generateClangCaches(includeFiles, clangBin, cflags)
|
||||||
|
|
||||||
// The cache should now be fully populated.
|
// The cache should now be fully populated.
|
||||||
|
|
||||||
@ -153,15 +183,14 @@ func main() {
|
|||||||
atr.Process(parsed)
|
atr.Process(parsed)
|
||||||
|
|
||||||
// Update global state tracker (AFTER astTransformChildClasses)
|
// Update global state tracker (AFTER astTransformChildClasses)
|
||||||
// Currently, this is only used for inner classes
|
|
||||||
for _, c := range parsed.Classes {
|
for _, c := range parsed.Classes {
|
||||||
KnownClassnames[c.ClassName] = struct{}{}
|
KnownClassnames[c.ClassName] = lookupResultClass{packageName}
|
||||||
}
|
}
|
||||||
for _, td := range parsed.Typedefs {
|
for _, td := range parsed.Typedefs {
|
||||||
KnownTypedefs[td.Alias] = td // copy
|
KnownTypedefs[td.Alias] = lookupResultTypedef{packageName, td /* copy */}
|
||||||
}
|
}
|
||||||
for _, en := range parsed.Enums {
|
for _, en := range parsed.Enums {
|
||||||
KnownEnums[en.EnumName] = en // copy
|
KnownEnums[en.EnumName] = lookupResultEnum{packageName, en /* copy */}
|
||||||
}
|
}
|
||||||
|
|
||||||
processHeaders = append(processHeaders, parsed)
|
processHeaders = append(processHeaders, parsed)
|
||||||
@ -199,9 +228,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Emit 3 code files from the intermediate format
|
// Emit 3 code files from the intermediate format
|
||||||
outputName := filepath.Join(*outDir, "gen_"+strings.TrimSuffix(filepath.Base(parsed.Filename), `.h`))
|
outputName := filepath.Join(outDir, "gen_"+strings.TrimSuffix(filepath.Base(parsed.Filename), `.h`))
|
||||||
|
|
||||||
goSrc, err := emitGo(parsed, filepath.Base(parsed.Filename))
|
goSrc, err := emitGo(parsed, filepath.Base(parsed.Filename), packageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -221,7 +250,7 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingHSrc, err := emitBindingHeader(parsed, filepath.Base(parsed.Filename))
|
bindingHSrc, err := emitBindingHeader(parsed, filepath.Base(parsed.Filename), packageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ func applyTypedefs(p CppParameter) CppParameter {
|
|||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p.ApplyTypedef(td.UnderlyingType)
|
p.ApplyTypedef(td.Typedef.UnderlyingType)
|
||||||
}
|
}
|
||||||
|
|
||||||
if t, ok := p.QListOf(); ok {
|
if t, ok := p.QListOf(); ok {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user