diff --git a/cmd/genbindings/emitcabi.go b/cmd/genbindings/emitcabi.go index 3fa0fb10..24e217d9 100644 --- a/cmd/genbindings/emitcabi.go +++ b/cmd/genbindings/emitcabi.go @@ -70,13 +70,13 @@ func (p CppParameter) RenderTypeCabi() string { if ft, ok := p.QFlagsOf(); ok { if e, ok := KnownEnums[ft.ParameterType]; ok { - ret = e.UnderlyingType.RenderTypeCabi() + ret = e.Enum.UnderlyingType.RenderTypeCabi() } else { ret = "int" } } 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 { - 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 + 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 = " - 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 + "int " + namePrefix + "_ctr = 0;\n" afterCall += indent + "QSetIterator<" + t.RenderTypeQtCpp() + "> " + namePrefix + "_itr(" + namePrefix + "_ret);\n" @@ -448,7 +448,7 @@ func getReferencedTypes(src *CppParsedHeader) []string { // Convert to sorted list foundTypesList := make([]string, 0, len(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 } if strings.HasSuffix(ft, "Private") { // qbrush.h finds QGradientPrivate @@ -475,12 +475,16 @@ func cabiClassName(className string) string { 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{} includeGuard := "GEN_" + strings.ToUpper(strings.Replace(filename, `.`, `_`, -1)) bindingInclude := "../libmiqt/libmiqt.h" + if packageName != "qt" { + bindingInclude = "../" + bindingInclude + } + ret.WriteString(`#ifndef ` + includeGuard + ` #define ` + includeGuard + ` @@ -592,7 +596,7 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) { ret.WriteString(`#include <` + ref + ">\n") } - ret.WriteString(`#include "` + filename + "\"\n") + ret.WriteString(`#include <` + filename + ">\n") ret.WriteString(`#include "gen_` + filename + "\"\n") ret.WriteString("#include \"_cgo_export.h\"\n\n") diff --git a/cmd/genbindings/emitgo.go b/cmd/genbindings/emitgo.go index 1f5367cd..229928cc 100644 --- a/cmd/genbindings/emitgo.go +++ b/cmd/genbindings/emitgo.go @@ -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" { return "string" } @@ -28,11 +28,11 @@ func (p CppParameter) RenderTypeGo() string { } if t, ok := p.QListOf(); ok { - return "[]" + t.RenderTypeGo() + return "[]" + t.RenderTypeGo(gfs) } if t, ok := p.QSetOf(); ok { - return "map[" + t.RenderTypeGo() + "]struct{}" + return "map[" + t.RenderTypeGo(gfs) + "]struct{}" } if p.ParameterType == "void" && p.Pointer { @@ -40,10 +40,6 @@ func (p CppParameter) RenderTypeGo() string { } ret := "" - if p.ByRef || p.Pointer { - ret += "*" - } - switch p.ParameterType { case "unsigned char", "uchar", "quint8": // Go byte is unsigned @@ -101,10 +97,25 @@ func (p CppParameter) RenderTypeGo() string { default: if ft, ok := p.QFlagsOf(); ok { - ret += cabiClassName(ft.ParameterType) - } else if p.IsKnownEnum() { - ret += cabiClassName(p.ParameterType) + if enumInfo, ok := KnownEnums[ft.ParameterType]; ok && enumInfo.PackageName != gfs.currentPackageName { + // 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, `::`) { // 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 } @@ -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)) skipNext := false @@ -171,7 +191,7 @@ func emitParametersGo(params []CppParameter) string { } else { // 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 { - imports map[string]struct{} + imports map[string]struct{} + currentPackageName 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() { // The C++ type is a pointer to Qt class // 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" { 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 = " - 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 += "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 = " - 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 += "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 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 { 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 { // 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 // 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" // 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 { // Need to cast Cgo type to Go int type // Optimize assignment to avoid temporary - return assignExpr + "(" + rt.RenderTypeGo() + ")(" + rvalue + ")\n" + return assignExpr + "(" + rt.RenderTypeGo(gfs) + ")(" + rvalue + ")\n" } 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.WriteString(`package qt + ret.WriteString(`package ` + packageName + ` /* @@ -413,7 +455,8 @@ import "C" `) gfs := goFileState{ - imports: map[string]struct{}{}, + imports: map[string]struct{}{}, + currentPackageName: packageName, } // Check if short-named enums are allowed. @@ -457,7 +500,7 @@ import "C" } ret.WriteString(` - type ` + goEnumName + ` ` + e.UnderlyingType.RenderTypeGo() + ` + type ` + goEnumName + ` ` + e.UnderlyingType.RenderTypeGo(&gfs) + ` `) if len(e.Entries) > 0 { @@ -483,7 +526,16 @@ import "C" // Embed all inherited types to directly allow calling inherited methods 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(` @@ -496,12 +548,26 @@ import "C" 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" for _, base := range c.Inherits { 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(` @@ -520,7 +586,7 @@ import "C" // that never happens in Go's type system. gfs.imports["unsafe"] = struct{}{} ret.WriteString(` - func new` + goClassName + `_U(h unsafe.Pointer) *` + goClassName + ` { + func UnsafeNew` + goClassName + `(h unsafe.Pointer) *` + goClassName + ` { return new` + goClassName + `( (*C.` + goClassName + `)(h) ) } @@ -533,7 +599,7 @@ import "C" gfs.imports["runtime"] = struct{}{} ret.WriteString(` // 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" { ` + preamble + ` ret := C.` + goClassName + `_new` + maybeSuffix(i) + `(` + forwarding + `) return new` + goClassName + `(ret) @@ -546,7 +612,7 @@ import "C" } else { ret.WriteString(` // 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 + `) return new` + goClassName + `(ret) } @@ -558,7 +624,7 @@ import "C" for _, m := range c.Methods { preamble, forwarding := gfs.emitParametersGo2CABIForwarding(m) - returnTypeDecl := m.ReturnType.RenderTypeGo() + returnTypeDecl := m.ReturnType.RenderTypeGo(&gfs) if returnTypeDecl == "void" { returnTypeDecl = "" } @@ -580,7 +646,7 @@ import "C" } ret.WriteString(` - func ` + receiverAndMethod + `(` + emitParametersGo(m.Parameters) + `) ` + returnTypeDecl + ` {`) + func ` + receiverAndMethod + `(` + gfs.emitParametersGo(m.Parameters) + `) ` + returnTypeDecl + ` {`) if m.LinuxOnly { gfs.imports["runtime"] = struct{}{} ret.WriteString(` @@ -613,13 +679,13 @@ import "C" 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)) ) } //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, `, `) + `) { - gofunc, ok := cgo.Handle(cb).Value().(func(` + emitParametersGo(m.Parameters) + `)) + gofunc, ok := cgo.Handle(cb).Value().(func(` + gfs.emitParametersGo(m.Parameters) + `)) if !ok { panic("miqt: callback of non-callback type (heap corruption?)") } diff --git a/cmd/genbindings/exceptions.go b/cmd/genbindings/exceptions.go index 27ddc6cb..085b2ad7 100644 --- a/cmd/genbindings/exceptions.go +++ b/cmd/genbindings/exceptions.go @@ -10,20 +10,20 @@ func InsertTypedefs() { // Seed well-known typedefs // QString is deleted from this binding - KnownTypedefs["QStringList"] = CppTypedef{"QStringList", parseSingleTypeString("QList")} + KnownTypedefs["QStringList"] = lookupResultTypedef{"qt", CppTypedef{"QStringList", parseSingleTypeString("QList")}} // 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 - 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 - 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 - KnownTypedefs["QFile::Permissions"] = CppTypedef{"QFile::Permissions", parseSingleTypeString("QFileDevice::Permissions")} - KnownTypedefs["QFileDevice::Permissions"] = CppTypedef{"QFile::Permissions", parseSingleTypeString("QFlags")} + KnownTypedefs["QFile::Permissions"] = lookupResultTypedef{"qt", CppTypedef{"QFile::Permissions", parseSingleTypeString("QFileDevice::Permissions")}} + KnownTypedefs["QFileDevice::Permissions"] = lookupResultTypedef{"qt", CppTypedef{"QFile::Permissions", parseSingleTypeString("QFlags")}} } func AllowHeader(fullpath string) bool { diff --git a/cmd/genbindings/intermediate.go b/cmd/genbindings/intermediate.go index 1a3328ba..7f384963 100644 --- a/cmd/genbindings/intermediate.go +++ b/cmd/genbindings/intermediate.go @@ -5,16 +5,30 @@ import ( "strings" ) +type lookupResultClass struct { + PackageName string +} + +type lookupResultTypedef struct { + PackageName string + Typedef CppTypedef +} + +type lookupResultEnum struct { + PackageName string + Enum CppEnum +} + var ( - KnownClassnames map[string]struct{} // Entries of the form QFoo::Bar if it is an inner class - KnownTypedefs map[string]CppTypedef - KnownEnums map[string]CppEnum + KnownClassnames map[string]lookupResultClass // Entries of the form QFoo::Bar if it is an inner class + KnownTypedefs map[string]lookupResultTypedef + KnownEnums map[string]lookupResultEnum ) func init() { - KnownClassnames = make(map[string]struct{}) - KnownTypedefs = make(map[string]CppTypedef) - KnownEnums = make(map[string]CppEnum) + KnownClassnames = make(map[string]lookupResultClass) + KnownTypedefs = make(map[string]lookupResultTypedef) + KnownEnums = make(map[string]lookupResultEnum) } type CppParameter struct { diff --git a/cmd/genbindings/main.go b/cmd/genbindings/main.go index 0416bc56..45fe6286 100644 --- a/cmd/genbindings/main.go +++ b/cmd/genbindings/main.go @@ -18,6 +18,15 @@ const ( 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 { return filepath.Join("cachedir", strings.Replace(inputHeader, `/`, `__`, -1)+".json") } @@ -80,24 +89,45 @@ func cleanGeneratedFilesInDir(dirpath string) { func main() { 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", "../../qt", "Output directory for generated gen_** files") + outDir := flag.String("outdir", "../../", "Output directory for generated gen_** files") 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{ - "/usr/include/x86_64-linux-gnu/qt5/QtCore", - "/usr/include/x86_64-linux-gnu/qt5/QtGui", - "/usr/include/x86_64-linux-gnu/qt5/QtWidgets", - } { + generate( + "qprintsupport", + []string{ + "/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)...) } log.Printf("Found %d header files to process.", len(includeFiles)) - cleanGeneratedFilesInDir(*outDir) + cleanGeneratedFilesInDir(outDir) var processHeaders []*CppParsedHeader atr := astTransformRedundant{ @@ -110,7 +140,7 @@ func main() { // PASS 0 (Fill clang cache) // - generateClangCaches(includeFiles, *clang, strings.Fields(*cflags)) + generateClangCaches(includeFiles, clangBin, cflags) // The cache should now be fully populated. @@ -153,15 +183,14 @@ func main() { atr.Process(parsed) // Update global state tracker (AFTER astTransformChildClasses) - // Currently, this is only used for inner classes for _, c := range parsed.Classes { - KnownClassnames[c.ClassName] = struct{}{} + KnownClassnames[c.ClassName] = lookupResultClass{packageName} } for _, td := range parsed.Typedefs { - KnownTypedefs[td.Alias] = td // copy + KnownTypedefs[td.Alias] = lookupResultTypedef{packageName, td /* copy */} } for _, en := range parsed.Enums { - KnownEnums[en.EnumName] = en // copy + KnownEnums[en.EnumName] = lookupResultEnum{packageName, en /* copy */} } processHeaders = append(processHeaders, parsed) @@ -199,9 +228,9 @@ func main() { } // 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 { panic(err) } @@ -221,7 +250,7 @@ func main() { panic(err) } - bindingHSrc, err := emitBindingHeader(parsed, filepath.Base(parsed.Filename)) + bindingHSrc, err := emitBindingHeader(parsed, filepath.Base(parsed.Filename), packageName) if err != nil { panic(err) } diff --git a/cmd/genbindings/transformtypedefs.go b/cmd/genbindings/transformtypedefs.go index f5691f9f..eb111809 100644 --- a/cmd/genbindings/transformtypedefs.go +++ b/cmd/genbindings/transformtypedefs.go @@ -11,7 +11,7 @@ func applyTypedefs(p CppParameter) CppParameter { if !ok { break } - p.ApplyTypedef(td.UnderlyingType) + p.ApplyTypedef(td.Typedef.UnderlyingType) } if t, ok := p.QListOf(); ok {