qt6: initial support

This commit is contained in:
mappu 2024-10-20 18:19:37 +13:00
parent aed94883cf
commit ab84c70f03
8 changed files with 146 additions and 22 deletions

View File

@ -10,7 +10,7 @@
MIQT is MIT-licensed Qt bindings for Go. MIQT is MIT-licensed Qt bindings for Go.
This is a straightforward binding of the Qt API using CGO. You must have a working Qt C++ development toolchain to use this Go binding. This is a straightforward binding of the Qt 5.15 / Qt 6.4+ API using CGO. You must have a working Qt C++ development toolchain to use this Go binding.
These bindings were newly started in August 2024. The bindings are functional for all of QtCore, QtGui, and QtWidgets, and there is a uic/rcc implementation. But, the bindings may be immature in some ways. Please try out the bindings and raise issues if you have trouble. These bindings were newly started in August 2024. The bindings are functional for all of QtCore, QtGui, and QtWidgets, and there is a uic/rcc implementation. But, the bindings may be immature in some ways. Please try out the bindings and raise issues if you have trouble.

View File

@ -5,25 +5,56 @@ import (
"strings" "strings"
) )
func InsertTypedefs() { func InsertTypedefs(qt6 bool) {
// Seed well-known typedefs // Seed well-known typedefs
pp := "qt"
if qt6 {
pp = "qt6"
}
// QString is deleted from this binding // QString is deleted from this binding
KnownTypedefs["QStringList"] = lookupResultTypedef{"qt", CppTypedef{"QStringList", parseSingleTypeString("QList<QString>")}} KnownTypedefs["QStringList"] = lookupResultTypedef{pp, 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"] = lookupResultTypedef{"qt", CppTypedef{"QFile::FileTime", parseSingleTypeString("QFileDevice::FileTime")}} KnownTypedefs["QFile::FileTime"] = lookupResultTypedef{pp, CppTypedef{"QFile::FileTime", parseSingleTypeString("QFileDevice::FileTime")}}
// n.b. Qt 5 only if !qt6 {
KnownTypedefs["QLineF::IntersectionType"] = lookupResultTypedef{"qt", CppTypedef{"QLineF::IntersectionType", parseSingleTypeString("QLineF::IntersectType")}} // n.b. Qt 5 only
KnownTypedefs["QLineF::IntersectionType"] = lookupResultTypedef{pp, CppTypedef{"QLineF::IntersectionType", parseSingleTypeString("QLineF::IntersectType")}}
} else {
// Must be removed for Qt 6
}
// Not sure the reason for this one // Not sure the reason for this one
KnownTypedefs["QSocketDescriptor::DescriptorType"] = lookupResultTypedef{"qt", CppTypedef{"QSocketDescriptor::DescriptorType", parseSingleTypeString("QSocketNotifier::Type")}} KnownTypedefs["QSocketDescriptor::DescriptorType"] = lookupResultTypedef{pp, 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"] = lookupResultTypedef{"qt", CppTypedef{"QFile::Permissions", parseSingleTypeString("QFileDevice::Permissions")}} KnownTypedefs["QFile::Permissions"] = lookupResultTypedef{pp, CppTypedef{"QFile::Permissions", parseSingleTypeString("QFileDevice::Permissions")}}
KnownTypedefs["QFileDevice::Permissions"] = lookupResultTypedef{"qt", CppTypedef{"QFile::Permissions", parseSingleTypeString("QFlags<QFileDevice::Permission>")}} KnownTypedefs["QFileDevice::Permissions"] = lookupResultTypedef{pp, CppTypedef{"QFile::Permissions", parseSingleTypeString("QFlags<QFileDevice::Permission>")}}
KnownTypedefs["QIODevice::OpenMode"] = lookupResultTypedef{pp, CppTypedef{"QIODevice::OpenMode", parseSingleTypeString("QIODeviceBase::OpenMode")}}
if qt6 {
// Qt 6 QVariant helper types - needs investigation
KnownTypedefs["QVariantHash"] = lookupResultTypedef{"qt6", CppTypedef{"QVariantHash", parseSingleTypeString("QHash<QString,QVariant>")}}
KnownTypedefs["QVariantList"] = lookupResultTypedef{"qt6", CppTypedef{"QVariantList", parseSingleTypeString("QList<QVariant>")}}
KnownTypedefs["QVariantMap"] = lookupResultTypedef{"qt6", CppTypedef{"QVariantMap", parseSingleTypeString("QMap<QString,QVariant>")}}
// Qt 6 renamed the enum to LibraryPath, but left some uses of LibraryLocation with a typedef
// We don't find the typedef - needs investigation
// ONLY add this on Qt 6 builds, breaks Qt 5
KnownTypedefs["QLibraryInfo::LibraryLocation"] = lookupResultTypedef{"qt6", CppTypedef{"QLibraryInfo::LibraryLocation", parseSingleTypeString("QLibraryInfo::LibraryPath")}}
// Enums
// QSysInfo.h is being truncated and not finding any content
KnownEnums["QSysInfo::Endian"] = lookupResultEnum{"qt6", CppEnum{
EnumName: "QSysInfo::Endian",
UnderlyingType: CppParameter{
ParameterType: "int",
},
}}
}
} }
@ -50,7 +81,13 @@ func AllowHeader(fullpath string) bool {
"qstring.h", // QString does not exist in this binding "qstring.h", // QString does not exist in this binding
"qbytearray.h", // QByteArray does not exist in this binding "qbytearray.h", // QByteArray does not exist in this binding
"qlist.h", // QList does not exist in this binding "qlist.h", // QList does not exist in this binding
"qvector.h": // QVector does not exist in this binding "qvector.h", // QVector does not exist in this binding
"qtcoreexports.h", // Nothing bindable here and has Q_CORE_EXPORT definition issues
"q20algorithm.h", // Qt 6 unstable header
"q20functional.h", // Qt 6 unstable header
"q20iterator.h", // Qt 6 unstable header
"q23functional.h", // Qt 6 unstable header
"____last____":
return false return false
} }
@ -79,7 +116,9 @@ func ImportHeaderForClass(className string) bool {
case "QGraphicsEffectSource", // e.g. qgraphicseffect.h case "QGraphicsEffectSource", // e.g. qgraphicseffect.h
"QAbstractConcatenable", // qstringbuilder.h "QAbstractConcatenable", // qstringbuilder.h
"QTextEngine", // qtextlayout.h "QTextEngine", // qtextlayout.h
"QText": // e.g. qtextcursor.h "QText", // e.g. qtextcursor.h
"QVLABaseBase", // e.g. Qt 6 qvarlengtharray.h
"____last____":
return false return false
} }
@ -102,12 +141,22 @@ func AllowClass(className string) bool {
switch className { switch className {
case case
"QTextStreamManipulator", // Only seems to contain garbage methods "QTextStreamManipulator", // Only seems to contain garbage methods
"QException", // Extends std::exception, too hard "QException", // Extends std::exception, too hard
"QUnhandledException", // As above (child class) "QUnhandledException", // As above (child class)
"QItemSelection", // Extends a QList<>, too hard "QItemSelection", // Extends a QList<>, too hard
"QXmlStreamAttributes", // Extends a QList<>, too hard "QXmlStreamAttributes", // Extends a QList<>, too hard
"QPolygon", "QPolygonF": // Extends a QVector<QPoint> template class, too hard "QPolygon", // Extends a QVector<QPoint> template class, too hard
"QPolygonF", // Extends a QVector<QPoint> template class, too hard
"QAssociativeIterator", // Qt 6. Extends a QIterator<>, too hard
"QAssociativeConstIterator", // Qt 6. Extends a QIterator<>, too hard
"QAssociativeIterable", // Qt 6. Extends a QIterator<>, too hard
"QSequentialIterator", // Qt 6. Extends a QIterator<>, too hard
"QSequentialConstIterator", // Qt 6. Extends a QIterator<>, too hard
"QSequentialIterable", // Qt 6. Extends a QIterator<>, too hard
"QBrushDataPointerDeleter", // Qt 6 qbrush.h. Appears in header but cannot be linked
"QPropertyBindingPrivatePtr", // Qt 6 qpropertyprivate.h. Appears in header but cannot be linked
"____last____":
return false return false
} }
@ -115,8 +164,15 @@ func AllowClass(className string) bool {
} }
func AllowSignal(mm CppMethod) bool { func AllowSignal(mm CppMethod) bool {
if mm.ReturnType.ParameterType != "void" {
// This affects how we cast the signal function pointer for connect
// It would be fixable, but, real signals always have void return types anyway
return false
}
switch mm.MethodName { switch mm.MethodName {
case `metaObject`, `qt_metacast`: case `metaObject`, `qt_metacast`,
`clone`: // Qt 6 - qcoreevent.h
return false return false
default: default:
return true return true
@ -194,6 +250,19 @@ func CheckComplexity(p CppParameter, isReturnType bool) error {
if strings.HasPrefix(p.ParameterType, "FillResult<") { if strings.HasPrefix(p.ParameterType, "FillResult<") {
return ErrTooComplex // Scintilla return ErrTooComplex // Scintilla
} }
if strings.HasPrefix(p.ParameterType, "QBindable<") {
return ErrTooComplex // e.g. Qt 6 qabstractanimation.h
}
if strings.HasPrefix(p.ParameterType, "QRgbaFloat<") {
return ErrTooComplex // e.g. Qt 6 qcolortransform.h
}
if strings.HasPrefix(p.ParameterType, "QPointer<") {
return ErrTooComplex // e.g. Qt 6 qevent.h . It should be possible to support this
}
if strings.HasPrefix(p.ParameterType, "EncodedData<") {
return ErrTooComplex // e.g. Qt 6 qstringconverter.h
}
if strings.HasPrefix(p.ParameterType, "std::") { if strings.HasPrefix(p.ParameterType, "std::") {
// std::initializer e.g. qcborarray.h // std::initializer e.g. qcborarray.h
// std::string QByteArray->toStdString(). There are QString overloads already // std::string QByteArray->toStdString(). There are QString overloads already
@ -212,12 +281,21 @@ func CheckComplexity(p CppParameter, isReturnType bool) error {
if strings.Contains(p.GetQtCppType().ParameterType, `::DataPtr`) { if strings.Contains(p.GetQtCppType().ParameterType, `::DataPtr`) {
return ErrTooComplex // e.g. QImage::data_ptr() return ErrTooComplex // e.g. QImage::data_ptr()
} }
if strings.Contains(p.ParameterType, `::DataPointer`) {
return ErrTooComplex // Qt 6 qbytearray.h. This could probably be made to work
}
if strings.HasPrefix(p.ParameterType, `QArrayDataPointer<`) {
return ErrTooComplex // Qt 6 qbytearray.h. This could probably be made to work
}
// Some QFoo constructors take a QFooPrivate // Some QFoo constructors take a QFooPrivate
// QIcon also returns a QIconPrivate // QIcon also returns a QIconPrivate
if p.ParameterType[0] == 'Q' && strings.HasSuffix(p.ParameterType, "Private") { if p.ParameterType[0] == 'Q' && strings.HasSuffix(p.ParameterType, "Private") {
return ErrTooComplex return ErrTooComplex
} }
if strings.HasPrefix(p.ParameterType, "QtPrivate::") {
return ErrTooComplex // e.g. Qt 6 qbindingstorage.h
}
// If any parameters are QString*, skip the method // If any parameters are QString*, skip the method
// QDebug constructor // QDebug constructor
@ -260,6 +338,8 @@ func CheckComplexity(p CppParameter, isReturnType bool) error {
"QPolygon", "QPolygonF", // QPolygon extends a template type "QPolygon", "QPolygonF", // QPolygon extends a template type
"QGenericMatrix", "QMatrix3x3", // extends a template type "QGenericMatrix", "QMatrix3x3", // extends a template type
"QLatin1String", "QStringView", // e.g. QColor constructors and QColor::SetNamedColor() overloads. These are usually optional alternatives to QString "QLatin1String", "QStringView", // e.g. QColor constructors and QColor::SetNamedColor() overloads. These are usually optional alternatives to QString
"QLatin1StringView", // Qt 6 - used in qanystringview
"QUtf8StringView", // Qt 6 - used in qdebug
"QStringRef", // e.g. QLocale::toLongLong and similar overloads. As above "QStringRef", // e.g. QLocale::toLongLong and similar overloads. As above
"qfloat16", // e.g. QDataStream - there is no such half-float type in C or Go "qfloat16", // e.g. QDataStream - there is no such half-float type in C or Go
"char16_t", // e.g. QChar() constructor overload, just unnecessary "char16_t", // e.g. QChar() constructor overload, just unnecessary
@ -289,7 +369,12 @@ func CheckComplexity(p CppParameter, isReturnType bool) error {
"QPlatformScreen", // e.g. qscreen.h. as below "QPlatformScreen", // e.g. qscreen.h. as below
"QPlatformWindow", // e.g. qwindow.h, as below "QPlatformWindow", // e.g. qwindow.h, as below
"QPlatformSurface", // e.g. qsurface.h. as below "QPlatformSurface", // e.g. qsurface.h. as below
"QPlatformMenu": // e.g. QMenu_PlatformMenu. Defined in the QPA, could probably expose as uintptr "QPlatformMenu", // e.g. QMenu_PlatformMenu. Defined in the QPA, could probably expose as uintptr
"struct _XDisplay", // Qt 6 QGuiApplication_platform
"xcb_connection_t", // Qt 6 QGuiApplication_platform
"QTextDocument::ResourceProvider", // Qt 6 typedef for unsupported std::function<QVariant(const QUrl&)>
"QTransform::Affine", // Qt 6 qtransform.h - public method returning private type
"____last____":
return ErrTooComplex return ErrTooComplex
} }

View File

@ -25,7 +25,7 @@ var (
KnownEnums map[string]lookupResultEnum KnownEnums map[string]lookupResultEnum
) )
func init() { func flushKnownTypes() {
KnownClassnames = make(map[string]lookupResultClass) KnownClassnames = make(map[string]lookupResultClass)
KnownTypedefs = make(map[string]lookupResultTypedef) KnownTypedefs = make(map[string]lookupResultTypedef)
KnownEnums = make(map[string]lookupResultEnum) KnownEnums = make(map[string]lookupResultEnum)

View File

@ -99,6 +99,9 @@ func main() {
flag.Parse() flag.Parse()
flushKnownTypes()
InsertTypedefs(false)
generate( generate(
"qt", "qt",
[]string{ []string{
@ -146,6 +149,25 @@ func main() {
*outDir, *outDir,
(&clangMatchUnderPath{filepath.Join(*extraLibsDir, "scintilla")}).Match, (&clangMatchUnderPath{filepath.Join(*extraLibsDir, "scintilla")}).Match,
) )
// FLUSH all known typedefs / ...
flushKnownTypes()
InsertTypedefs(true)
// Qt 6
generate(
"qt6",
[]string{
"/usr/include/x86_64-linux-gnu/qt6/QtCore",
"/usr/include/x86_64-linux-gnu/qt6/QtGui",
"/usr/include/x86_64-linux-gnu/qt6/QtWidgets",
},
*clang,
strings.Fields("--std=c++17 "+pkgConfigCflags("Qt6Widgets")),
*outDir,
ClangMatchSameHeaderDefinitionOnly,
)
} }
func generate(packageName string, srcDirs []string, clangBin string, cflags []string, outDir string, matcher ClangMatcher) { func generate(packageName string, srcDirs []string, clangBin string, cflags []string, outDir string, matcher ClangMatcher) {
@ -170,8 +192,6 @@ func generate(packageName string, srcDirs []string, clangBin string, cflags []st
preserve: make(map[string]*CppEnum), preserve: make(map[string]*CppEnum),
} }
InsertTypedefs()
// //
// PASS 0 (Fill clang cache) // PASS 0 (Fill clang cache)
// //

View File

@ -4,6 +4,7 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
apt-get install --no-install-recommends -qyy \ apt-get install --no-install-recommends -qyy \
golang-go \ golang-go \
qtbase5-dev \ qtbase5-dev \
qt6-base-dev \
libqscintilla2-qt5-dev \ libqscintilla2-qt5-dev \
clang \ clang \
git \ git \

View File

@ -0,0 +1,6 @@
FROM debian:bookworm
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
apt-get install -qyy golang-go qt6-base-dev && \
apt-get clean

3
qt6/binding.go Normal file
View File

@ -0,0 +1,3 @@
package qt6
type QSysInfo__Endian int

9
qt6/cflags_linux.go Normal file
View File

@ -0,0 +1,9 @@
// +build linux,!android
package qt6
/*
#cgo CFLAGS: -fPIC
#cgo pkg-config: Qt6Widgets
*/
import "C"