From 2323c12b5535905c06025d86100f9c05f38bc3af Mon Sep 17 00:00:00 2001 From: mappu Date: Sun, 1 Sep 2024 17:50:58 +1200 Subject: [PATCH] support marking data types as linux-only --- cmd/genbindings/emitcabi.go | 18 +++++++++++++ cmd/genbindings/emitgo.go | 40 +++++++++++++++++++++++++--- cmd/genbindings/exceptions.go | 14 ++++++++++ cmd/genbindings/intermediate.go | 6 +---- cmd/genbindings/transformtypedefs.go | 20 ++++++++++++-- qt/gen_qprocess.cpp | 4 +++ qt/gen_qprocess.go | 9 +++++-- qt/gen_qsocketnotifier.cpp | 4 +++ qt/gen_qsocketnotifier.go | 9 +++++-- 9 files changed, 110 insertions(+), 14 deletions(-) diff --git a/cmd/genbindings/emitcabi.go b/cmd/genbindings/emitcabi.go index 453967db..f9780098 100644 --- a/cmd/genbindings/emitcabi.go +++ b/cmd/genbindings/emitcabi.go @@ -511,6 +511,11 @@ extern "C" { cClassName := cabiClassName(c.ClassName) for i, ctor := range c.Ctors { + + if ctor.LinuxOnly { + ret.WriteString("#ifdef Q_OS_LINUX\n\n") + } + preamble, forwarding := emitParametersCABI2CppForwarding(ctor.Parameters) ret.WriteString(fmt.Sprintf( "%s* %s_new%s(%s) {\n"+ @@ -522,6 +527,10 @@ extern "C" { preamble, c.ClassName, forwarding, )) + + if ctor.LinuxOnly { + ret.WriteString("#endif /* Q_OS_LINUX */\n\n") + } } for _, m := range c.Methods { @@ -657,6 +666,10 @@ extern "C" { callTarget = "const_cast(self)->" } + if m.LinuxOnly { + ret.WriteString("#ifdef Q_OS_LINUX\n\n") + } + ret.WriteString(fmt.Sprintf( "%s %s_%s(%s) {\n"+ "%s"+ @@ -682,6 +695,11 @@ extern "C" { "\n", ) } + + if m.LinuxOnly { + ret.WriteString("#endif /* Q_OS_LINUX */\n\n") + } + } // Delete diff --git a/cmd/genbindings/emitgo.go b/cmd/genbindings/emitgo.go index 500cf320..35bdf4fb 100644 --- a/cmd/genbindings/emitgo.go +++ b/cmd/genbindings/emitgo.go @@ -347,7 +347,23 @@ import "C" for i, ctor := range c.Ctors { preamble, forwarding := gfs.emitParametersGo2CABIForwarding(ctor) - ret.WriteString(` + + if ctor.LinuxOnly { + 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 + ` { + if runtime.GOOS == "linux" { + ` + preamble + ` ret := C.` + goClassName + `_new` + maybeSuffix(i) + `(` + forwarding + `) + return new` + goClassName + `(ret) + } else { + panic("Unsupported OS") + } + } + + `) + } else { + ret.WriteString(` // New` + goClassName + maybeSuffix(i) + ` constructs a new ` + c.ClassName + ` object. func New` + goClassName + maybeSuffix(i) + `(` + emitParametersGo(ctor.Parameters) + `) *` + goClassName + ` { ` + preamble + ` ret := C.` + goClassName + `_new` + maybeSuffix(i) + `(` + forwarding + `) @@ -355,6 +371,7 @@ import "C" } `) + } } for _, m := range c.Methods { @@ -478,14 +495,31 @@ import "C" receiverAndMethod = goClassName + `_` + m.SafeMethodName() } - ret.WriteString(` + if m.LinuxOnly { + gfs.imports["runtime"] = struct{}{} + ret.WriteString(` + func ` + receiverAndMethod + `(` + emitParametersGo(m.Parameters) + `) ` + returnTypeDecl + ` { + if runtime.GOOS == "linux" { + ` + preamble + + shouldReturn + ` C.` + goClassName + `_` + m.SafeMethodName() + `(` + forwarding + `) +` + afterword + ` + } else { + panic("Unsupported OS") + } + } + + `) + } else { + ret.WriteString(` func ` + receiverAndMethod + `(` + emitParametersGo(m.Parameters) + `) ` + returnTypeDecl + ` { ` + preamble + - shouldReturn + ` C.` + goClassName + `_` + m.SafeMethodName() + `(` + forwarding + `) + shouldReturn + ` C.` + goClassName + `_` + m.SafeMethodName() + `(` + forwarding + `) ` + afterword + `} `) + } + // Add Connect() wrappers for signal functions if m.IsSignal && !m.HasHiddenParams { gfs.imports["unsafe"] = struct{}{} diff --git a/cmd/genbindings/exceptions.go b/cmd/genbindings/exceptions.go index 690b7e3f..08d640e6 100644 --- a/cmd/genbindings/exceptions.go +++ b/cmd/genbindings/exceptions.go @@ -225,3 +225,17 @@ func CheckComplexity(p CppParameter, isReturnType bool) error { // Should be OK return nil } + +// LinuxWindowsCompatCheck checks if the parameter is incompatible between the +// generated headers (generated on Linux) with other OSes such as Windows. +// These methods will be blocked on non-Linux OSes. +func LinuxWindowsCompatCheck(p CppParameter) bool { + if p.TypeAlias == "Q_PID" { + return true // int64 on Linux, _PROCESS_INFORMATION* on Windows + } + + if p.ParameterType == "QSocketDescriptor::DescriptorType" { + return true // uintptr_t-compatible on Linux, void* on Windows + } + return false +} diff --git a/cmd/genbindings/intermediate.go b/cmd/genbindings/intermediate.go index ab93668b..3556de35 100644 --- a/cmd/genbindings/intermediate.go +++ b/cmd/genbindings/intermediate.go @@ -20,11 +20,6 @@ func init() { KnownTypedefs["WId"] = CppTypedef{"WId", parseSingleTypeString("uintptr_t")} - // This is a uint64 PID on Linux/mac and a PROCESS_INFORMATION* on Windows - // A uintptr should be tolerable for both cases until we do better - // @ref https://doc.qt.io/qt-5/qprocess.html#Q_PID-typedef - KnownTypedefs["Q_PID"] = CppTypedef{"WId", parseSingleTypeString("uintptr_t")} - // QString is deleted from this binding KnownTypedefs["QStringList"] = CppTypedef{"QStringList", parseSingleTypeString("QList")} @@ -186,6 +181,7 @@ type CppMethod struct { IsSignal bool IsConst bool HasHiddenParams bool // Set to true if there is an overload with more parameters + LinuxOnly bool } func IsArgcArgv(params []CppParameter, pos int) bool { diff --git a/cmd/genbindings/transformtypedefs.go b/cmd/genbindings/transformtypedefs.go index fb0118a3..b0cd786e 100644 --- a/cmd/genbindings/transformtypedefs.go +++ b/cmd/genbindings/transformtypedefs.go @@ -33,17 +33,33 @@ func astTransformTypedefs(parsed *CppParsedHeader) { for j, m := range c.Methods { for k, p := range m.Parameters { - m.Parameters[k] = applyTypedefs(p) + transformed := applyTypedefs(p) + m.Parameters[k] = transformed + + if LinuxWindowsCompatCheck(transformed) { + m.LinuxOnly = true + } } m.ReturnType = applyTypedefs(m.ReturnType) + + // Also apply OS compatibility rules + if LinuxWindowsCompatCheck(m.ReturnType) { + m.LinuxOnly = true + } + c.Methods[j] = m } for j, m := range c.Ctors { for k, p := range m.Parameters { - m.Parameters[k] = applyTypedefs(p) + transformed := applyTypedefs(p) + m.Parameters[k] = transformed + + if LinuxWindowsCompatCheck(transformed) { + m.LinuxOnly = true + } } c.Ctors[j] = m diff --git a/qt/gen_qprocess.cpp b/qt/gen_qprocess.cpp index f82d00a7..9d751a45 100644 --- a/qt/gen_qprocess.cpp +++ b/qt/gen_qprocess.cpp @@ -352,10 +352,14 @@ uintptr_t QProcess_State(QProcess* self) { return static_cast(ret); } +#ifdef Q_OS_LINUX + int64_t QProcess_Pid(QProcess* self) { return const_cast(self)->pid(); } +#endif /* Q_OS_LINUX */ + long long QProcess_ProcessId(QProcess* self) { return const_cast(self)->processId(); } diff --git a/qt/gen_qprocess.go b/qt/gen_qprocess.go index 8f28ca9f..7ec09aa1 100644 --- a/qt/gen_qprocess.go +++ b/qt/gen_qprocess.go @@ -450,8 +450,13 @@ func (this *QProcess) State() uintptr { } func (this *QProcess) Pid() int64 { - ret := C.QProcess_Pid(this.h) - return (int64)(ret) + if runtime.GOOS == "linux" { + ret := C.QProcess_Pid(this.h) + return (int64)(ret) + + } else { + panic("Unsupported OS") + } } func (this *QProcess) ProcessId() int64 { diff --git a/qt/gen_qsocketnotifier.cpp b/qt/gen_qsocketnotifier.cpp index cb6b37d4..18543bb0 100644 --- a/qt/gen_qsocketnotifier.cpp +++ b/qt/gen_qsocketnotifier.cpp @@ -108,10 +108,14 @@ QSocketDescriptor* QSocketDescriptor_new2(QSocketDescriptor* param1) { return new QSocketDescriptor(*param1); } +#ifdef Q_OS_LINUX + QSocketDescriptor* QSocketDescriptor_new3(uintptr_t descriptor) { return new QSocketDescriptor(static_cast(descriptor)); } +#endif /* Q_OS_LINUX */ + bool QSocketDescriptor_IsValid(QSocketDescriptor* self) { return const_cast(self)->isValid(); } diff --git a/qt/gen_qsocketnotifier.go b/qt/gen_qsocketnotifier.go index e7092ffd..84495cb5 100644 --- a/qt/gen_qsocketnotifier.go +++ b/qt/gen_qsocketnotifier.go @@ -9,6 +9,7 @@ package qt import "C" import ( + "runtime" "unsafe" ) @@ -185,8 +186,12 @@ func NewQSocketDescriptor2(param1 *QSocketDescriptor) *QSocketDescriptor { // NewQSocketDescriptor3 constructs a new QSocketDescriptor object. func NewQSocketDescriptor3(descriptor uintptr) *QSocketDescriptor { - ret := C.QSocketDescriptor_new3((C.uintptr_t)(descriptor)) - return newQSocketDescriptor(ret) + if runtime.GOOS == "linux" { + ret := C.QSocketDescriptor_new3((C.uintptr_t)(descriptor)) + return newQSocketDescriptor(ret) + } else { + panic("Unsupported OS") + } } func (this *QSocketDescriptor) IsValid() bool {