Skip to content

Commit

Permalink
Merge pull request #53 from mappu/miqt-fedora40-qt6.7
Browse files Browse the repository at this point in the history
Qt 6.7 support
  • Loading branch information
mappu authored Oct 26, 2024
2 parents db2f367 + 34525ed commit 2a8b59e
Show file tree
Hide file tree
Showing 48 changed files with 669 additions and 478 deletions.
33 changes: 26 additions & 7 deletions .github/workflows/miqt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
uses: actions/checkout@v4

- name: Linux64 docker build
run: docker build -t miqt/linux64:latest -f docker/linux64-go1.19-qt5.15-dynamic.Dockerfile .
run: docker build -t miqt/linux64:qt5 -f docker/linux64-go1.19-qt5.15-dynamic.Dockerfile .

- name: Cache GOCACHE
uses: actions/cache@v4
Expand All @@ -46,28 +46,47 @@ jobs:
key: linux64-gocache

- name: Linux64 bindings compile and test
run: docker run -v ~/.cache/go-build:/root/.cache/go-build -v $PWD:/src -w /src miqt/linux64:latest /bin/bash -c 'cd qt && go build && cd ../examples/marshalling && env QT_QPA_PLATFORM=offscreen go test -v'
run: docker run -v ~/.cache/go-build:/root/.cache/go-build -v $PWD:/src -w /src miqt/linux64:qt5 /bin/bash -c 'cd qt && go build && cd ../examples/marshalling && env QT_QPA_PLATFORM=offscreen go test -v'

miqt_linux64_qt6:
miqt_linux64_qt6_4:
runs-on: ubuntu-24.04

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Linux64 docker build
run: docker build -t miqt/linux64:latest -f docker/linux64-go1.19-qt6.4-dynamic.Dockerfile .
run: docker build -t miqt/linux64:qt64 -f docker/linux64-go1.19-qt6.4-dynamic.Dockerfile .

- name: Cache GOCACHE
uses: actions/cache@v4
with:
path: ~/.cache/go-build
key: linux64-qt6-gocache
key: linux64-qt64-gocache

- name: Linux64 bindings compile
run: docker run -v ~/.cache/go-build:/root/.cache/go-build -v $PWD:/src -w /src miqt/linux64:latest /bin/bash -c 'cd qt6 && go build'
run: docker run -v ~/.cache/go-build:/root/.cache/go-build -v $PWD:/src -w /src miqt/linux64:qt64 /bin/bash -c 'cd qt6 && go build'

miqt_win64:
miqt_linux64_qt6_7:
runs-on: ubuntu-24.04

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Linux64 docker build
run: docker build -t miqt/linux64:qt67 -f docker/linux64-go1.22-qt6.7-dynamic.Dockerfile .

- name: Cache GOCACHE
uses: actions/cache@v4
with:
path: ~/.cache/go-build
key: linux64-qt67-gocache

- name: Linux64 bindings compile
run: docker run -v ~/.cache/go-build:/root/.cache/go-build -v $PWD:/src -w /src miqt/linux64:qt67 /bin/bash -c 'cd qt6 && go build'

miqt_win64_qt5:
runs-on: ubuntu-24.04

steps:
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,21 @@ You can replace the import path in two ways:

*Tested with Debian 12 / Qt 5.15 / Qt 6.4 / GCC 12*

*Tested with Fedora 40 / Qt 6.7 / GCC 14*

For dynamic linking, with the system Qt (Qt 5):

```bash
apt install qtbase5-dev build-essential
apt install qtbase5-dev build-essential # Debian / Ubuntu
go build -ldflags '-s -w'
```

For dynamic linking, with the system Qt (Qt 6):

```bash
apt install qt6-base-dev build-essential
apt install qt6-base-dev build-essential # Debian / Ubuntu
dnf install qt6-qtbase-devel golang # Fedora

go build -ldflags '-s -w'
```

Expand Down
9 changes: 3 additions & 6 deletions cmd/genbindings/clang2il.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,6 @@ func processClassType(node map[string]interface{}, addNamePrefix string) (CppCla

log.Printf("-> Processing class %q...\n", nodename)

// Also skip over any custom exceptions
if !AllowClass(nodename) {
return CppClass{}, ErrNoContent
}

// Skip over forward class declarations
// This is determined in two ways:
// 1. If the class has no inner nodes
Expand Down Expand Up @@ -458,7 +453,7 @@ nextMethod:

// Once all processing is complete, pass to exceptions for final decision

if err := AllowMethod(mm); err != nil {
if err := AllowMethod(ret.ClassName, mm); err != nil {
if errors.Is(err, ErrTooComplex) {
log.Printf("Skipping method %q with complex type", mm.MethodName)
continue nextMethod
Expand All @@ -468,6 +463,8 @@ nextMethod:
return CppClass{}, err
}

ApplyQuirks(ret.ClassName, &mm)

ret.Methods = append(ret.Methods, mm)

default:
Expand Down
46 changes: 38 additions & 8 deletions cmd/genbindings/config-allowlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func ImportHeaderForClass(className string) bool {
"QTextEngine", // qtextlayout.h
"QText", // e.g. qtextcursor.h
"QVLABaseBase", // e.g. Qt 6 qvarlengtharray.h
"QAdoptSharedDataTag", // Qt 6 qshareddata.h
"____last____":
return false
}
Expand All @@ -127,7 +128,7 @@ func ImportHeaderForClass(className string) bool {

func AllowClass(className string) bool {

if strings.HasSuffix(className, "Private") {
if strings.HasSuffix(className, "Private") || strings.HasSuffix(className, "PrivateShared") {
return false
}

Expand Down Expand Up @@ -156,6 +157,9 @@ func AllowClass(className string) bool {
"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
"QDeferredDeleteEvent", // Qt 6. Hidden/undocumented class in Qt 6.4, moved to private header in Qt 6.7. Intended for test use only

"QUntypedPropertyData::InheritsQUntypedPropertyData", // qpropertyprivate.h . Hidden/undocumented class in Qt 6.4, removed in 6.7
"____last____":
return false
}
Expand All @@ -179,7 +183,7 @@ func AllowSignal(mm CppMethod) bool {
}
}

func AllowMethod(mm CppMethod) error {
func AllowMethod(className string, mm CppMethod) error {

for _, p := range mm.Parameters {
if strings.HasSuffix(p.ParameterType, "Private") {
Expand All @@ -195,10 +199,21 @@ func AllowMethod(mm CppMethod) error {
return ErrTooComplex
}

if className == "QBitArray" && mm.MethodName == "operator~" {
return ErrTooComplex // Present in Qt 5.15 and 6.4, missing in Qt 6.7
}

if className == "QTimeZone" && (mm.MethodName == "operator==" || mm.MethodName == "operator!=") {
return ErrTooComplex // Present in Qt 5.15 and 6.4, missing in Qt 6.7
}

return nil // OK, allow
}

func CheckComplexity(p CppParameter, isReturnType bool) error {
// AllowType controls whether to permit binding of a method, if a method uses
// this type in its parameter list or return type.
// Any type not permitted by AllowClass is also not permitted by this method.
func AllowType(p CppParameter, isReturnType bool) error {

if p.QMapOf() {
return ErrTooComplex // Example???
Expand All @@ -207,12 +222,12 @@ func CheckComplexity(p CppParameter, isReturnType bool) error {
return ErrTooComplex // e.g. QGradientStop
}
if t, ok := p.QSetOf(); ok {
if err := CheckComplexity(t, isReturnType); err != nil {
if err := AllowType(t, isReturnType); err != nil {
return err
}
}
if t, ok := p.QListOf(); ok {
if err := CheckComplexity(t, isReturnType); err != nil { // e.g. QGradientStops is a QVector<> (OK) of QGradientStop (not OK)
if err := AllowType(t, isReturnType); err != nil { // e.g. QGradientStops is a QVector<> (OK) of QGradientStop (not OK)
return err
}

Expand All @@ -222,6 +237,9 @@ func CheckComplexity(p CppParameter, isReturnType bool) error {
return ErrTooComplex
}
}
if !AllowClass(p.ParameterType) {
return ErrTooComplex // This whole class type has been blocked, not only as a parameter/return type
}

if strings.Contains(p.ParameterType, "(*)") { // Function pointer.
return ErrTooComplex // e.g. QAccessible_InstallFactory
Expand Down Expand Up @@ -356,9 +374,6 @@ func CheckComplexity(p CppParameter, isReturnType bool) error {
"QtMsgType", // e.g. qdebug.h TODO Defined in qlogging.h, but omitted because it's predefined in qglobal.h, and our clangexec is too agressive
"QTextStreamFunction", // e.g. qdebug.h
"QFactoryInterface", // qfactoryinterface.h
"QItemSelection", // used by qabstractproxymodel.h, also blocked in AllowClass above, class extends a List<T>
"QTextStreamManipulator", // used by qdebug.h, also blocked in AllowClass above
"QException", // used by qfutureinterface.h, also blocked in AllowClass above
"QTextEngine", // used by qtextlayout.h, also blocked in ImportHeaderForClass above
"QVulkanInstance", // e.g. qwindow.h. Not tackling vulkan yet
"QPlatformNativeInterface", // e.g. QGuiApplication::platformNativeInterface(). Private type, could probably expose as uintptr. n.b. Changes in Qt6
Expand Down Expand Up @@ -395,3 +410,18 @@ func LinuxWindowsCompatCheck(p CppParameter) bool {
}
return false
}

func ApplyQuirks(className string, mm *CppMethod) {
if className == "QArrayData" && mm.MethodName == "needsDetach" && mm.IsConst {
mm.BecomesNonConstInVersion = addr("6.7")
}

if className == "QFileDialog" && mm.MethodName == "saveFileContent" && mm.IsStatic {
// The prototype was changed from
// [Qt 5 - 6.6] void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &fileNameHint = QString())
// [Qt 6.7] void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &fileNameHint, QWidget *parent = nullptr)
// The 2nd parameter is no longer optional
// As a compromise, make it non-optional everywhere
mm.Parameters[1].Optional = false
}
}
17 changes: 17 additions & 0 deletions cmd/genbindings/emitcabi.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,23 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
m.ReturnType.RenderTypeCabi(),
))

} else if m.BecomesNonConstInVersion != nil {

nonConstCallTarget := "const_cast<" + cClassName + "*>(self)->" + m.CppCallTarget() + "(" + forwarding + ")"

ret.WriteString("" +
m.ReturnType.RenderTypeCabi() + " " + cClassName + "_" + m.SafeMethodName() + "(" + emitParametersCabi(m, ifv(m.IsConst, "const ", "")+cClassName+"*") + ") {\n" +
preamble + "\n" +
"// This method was changed from const to non-const in Qt " + *m.BecomesNonConstInVersion + "\n" +
"#if QT_VERSION < QT_VERSION_CHECK(" + strings.Replace(*m.BecomesNonConstInVersion, `.`, `,`, -1) + ",0)\n" +
emitAssignCppToCabi("\treturn ", m.ReturnType, callTarget) +
"#else\n" +
emitAssignCppToCabi("\treturn ", m.ReturnType, nonConstCallTarget) +
"#endif\n" +
"}\n" +
"\n",
)

} else {

ret.WriteString(fmt.Sprintf(
Expand Down
5 changes: 4 additions & 1 deletion cmd/genbindings/intermediate.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,10 @@ type CppMethod struct {
IsSignal bool
IsConst bool
HiddenParams []CppParameter // Populated if there is an overload with more parameters
LinuxOnly bool

// Special quirks
LinuxOnly bool
BecomesNonConstInVersion *string // "6,7"
}

func (m CppMethod) CppCallTarget() string {
Expand Down
25 changes: 21 additions & 4 deletions cmd/genbindings/transformblocklist.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,36 @@ package main
// and entire classes that may be disallowed.
func astTransformBlocklist(parsed *CppParsedHeader) {

// Whole-classes

j := 0
for _, c := range parsed.Classes {
if !AllowClass(c.ClassName) {
continue
}

// Keep
parsed.Classes[j] = c
j++
}
parsed.Classes = parsed.Classes[:j] // reslice

// For the kept classes, filter ctors and methods within the class, based
// on the parameter types and return types

for i, c := range parsed.Classes {

// Constructors

j := 0
nextCtor:
for _, m := range c.Ctors {
if err := CheckComplexity(m.ReturnType, true); err != nil {
if err := AllowType(m.ReturnType, true); err != nil {
continue nextCtor
}

for _, p := range m.Parameters {
if err := CheckComplexity(p, false); err != nil {
if err := AllowType(p, false); err != nil {
continue nextCtor
}
}
Expand All @@ -32,12 +49,12 @@ func astTransformBlocklist(parsed *CppParsedHeader) {
j = 0
nextMethod:
for _, m := range c.Methods {
if err := CheckComplexity(m.ReturnType, true); err != nil {
if err := AllowType(m.ReturnType, true); err != nil {
continue nextMethod
}

for _, p := range m.Parameters {
if err := CheckComplexity(p, false); err != nil {
if err := AllowType(p, false); err != nil {
continue nextMethod
}
}
Expand Down
6 changes: 5 additions & 1 deletion cmd/genbindings/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ func ifv[T any](condition bool, trueval T, falseval T) T {
return trueval
}
return falseval
}
}

func addr[T any](s T) *T {
return &s
}
6 changes: 6 additions & 0 deletions docker/linux64-go1.22-qt6.7-dynamic.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM fedora:40

RUN dnf -y --setopt=install_weak_deps=False install \
qt6-qtbase-devel.x86_64 \
golang.x86_64

6 changes: 6 additions & 0 deletions qt-extras/scintillaedit/gen_ScintillaEdit.go
Original file line number Diff line number Diff line change
Expand Up @@ -1662,6 +1662,12 @@ const (
Scintilla__Message__SetBidirectional Scintilla__Message = 2709
)

type std__nullopt_t___Construct int

const (
Std__nullopt_t___Token std__nullopt_t___Construct = 0
)

type Scintilla__Internal__Surface__Ends int

const (
Expand Down
4 changes: 0 additions & 4 deletions qt/gen_qbitarray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,6 @@ void QBitArray_OperatorBitwiseNotAssign(QBitArray* self, QBitArray* param1) {
self->operator^=(*param1);
}

QBitArray* QBitArray_OperatorBitwiseXor(const QBitArray* self) {
return new QBitArray(self->operator~());
}

bool QBitArray_OperatorEqual(const QBitArray* self, QBitArray* other) {
return self->operator==(*other);
}
Expand Down
7 changes: 0 additions & 7 deletions qt/gen_qbitarray.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,6 @@ func (this *QBitArray) OperatorBitwiseNotAssign(param1 *QBitArray) {
C.QBitArray_OperatorBitwiseNotAssign(this.h, param1.cPointer())
}

func (this *QBitArray) OperatorBitwiseXor() *QBitArray {
_ret := C.QBitArray_OperatorBitwiseXor(this.h)
_goptr := newQBitArray(_ret)
_goptr.GoGC() // Qt uses pass-by-value semantics for this type. Mimic with finalizer
return _goptr
}

func (this *QBitArray) OperatorEqual(other *QBitArray) bool {
return (bool)(C.QBitArray_OperatorEqual(this.h, other.cPointer()))
}
Expand Down
1 change: 0 additions & 1 deletion qt/gen_qbitarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ bool QBitArray_OperatorSubscript2(const QBitArray* self, unsigned int i);
void QBitArray_OperatorBitwiseAndAssign(QBitArray* self, QBitArray* param1);
void QBitArray_OperatorBitwiseOrAssign(QBitArray* self, QBitArray* param1);
void QBitArray_OperatorBitwiseNotAssign(QBitArray* self, QBitArray* param1);
QBitArray* QBitArray_OperatorBitwiseXor(const QBitArray* self);
bool QBitArray_OperatorEqual(const QBitArray* self, QBitArray* other);
bool QBitArray_OperatorNotEqual(const QBitArray* self, QBitArray* other);
bool QBitArray_Fill(QBitArray* self, bool val);
Expand Down
Loading

0 comments on commit 2a8b59e

Please sign in to comment.