mirror of
https://github.com/bluszcz/cutego.git
synced 2024-09-28 13:15:17 +03:00
cgo-less interop related changes
This commit is contained in:
parent
550ceb9a59
commit
494d2f8c1e
9 changed files with 90 additions and 27 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -9,6 +9,7 @@
|
||||||
*.vagrant
|
*.vagrant
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Mfile*
|
Mfile*
|
||||||
|
qtbox
|
||||||
|
|
||||||
*/*-minimal.*
|
*/*-minimal.*
|
||||||
*/*.o
|
*/*.o
|
||||||
|
|
20
README.md
20
README.md
|
@ -5,11 +5,11 @@ Introduction
|
||||||
|
|
||||||
[Go](https://en.wikipedia.org/wiki/Go_(programming_language)), also known as Golang, is a programming language designed at Google.
|
[Go](https://en.wikipedia.org/wiki/Go_(programming_language)), also known as Golang, is a programming language designed at Google.
|
||||||
|
|
||||||
[therecipe/qt](https://github.com/therecipe/qt) allows you to write Qt applications entirely in Go or JavaScript.
|
[therecipe/qt](https://github.com/therecipe/qt) allows you to write Qt applications entirely in Go, [JavaScript/TypeScript](https://github.com/therecipe/entry), [Dart/Flutter](https://github.com/therecipe/flutter), [Haxe](https://github.com/therecipe/haxe) and [Swift](https://github.com/therecipe/swift)
|
||||||
|
|
||||||
Beside the language bindings provided, `therecipe/qt` also greatly simplifies the deployment of Qt applications to various software and hardware platforms.
|
Beside the language bindings provided, `therecipe/qt` also greatly simplifies the deployment of Qt applications to various software and hardware platforms.
|
||||||
|
|
||||||
At the time of writing, almost all Qt functions and classes are accessible from Go and JavaScript, and you should be able to find everything you need to build fully featured Qt applications.
|
At the time of writing, almost all Qt functions and classes are accessible, and you should be able to find everything you need to build fully featured Qt applications.
|
||||||
|
|
||||||
Impressions
|
Impressions
|
||||||
-----------
|
-----------
|
||||||
|
@ -23,6 +23,22 @@ Installation
|
||||||
|
|
||||||
The following instructions assume that you already installed [Go](https://golang.org/dl/) and [Git](https://git-scm.com/downloads)
|
The following instructions assume that you already installed [Go](https://golang.org/dl/) and [Git](https://git-scm.com/downloads)
|
||||||
|
|
||||||
|
#### (Experimental) cgo-less version (try this first, if you are new and want to test this binding)
|
||||||
|
|
||||||
|
##### Windows
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
go get -ldflags="-w" github.com/therecipe/examples/basic/widgets && for /f %v in ('go env GOPATH') do %v\bin\widgets.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
##### macOS/Linux
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get -ldflags="-w" github.com/therecipe/examples/basic/widgets && $(go env GOPATH)/bin/widgets
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Default version
|
||||||
|
|
||||||
##### Windows [(more info)](https://github.com/therecipe/qt/wiki/Installation-on-Windows)
|
##### Windows [(more info)](https://github.com/therecipe/qt/wiki/Installation-on-Windows)
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
|
|
|
@ -95,6 +95,23 @@ func goFunctionBody(function *parser.Function) string {
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
|
//TODO:
|
||||||
|
if class.IsSubClassOf("QCoreApplication") {
|
||||||
|
if function.Meta == parser.CONSTRUCTOR {
|
||||||
|
return fmt.Sprintf("\ngow.InitProcess()\nreturn New%vFromPointer(%vQCoreApplication_Instance().Pointer())", class.Name, func() string {
|
||||||
|
if goModule(class.Module) != "core" {
|
||||||
|
return "core."
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}())
|
||||||
|
}
|
||||||
|
|
||||||
|
if function.Name == "exec" {
|
||||||
|
return "\ngow.Exec()\nreturn 0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
var input []string
|
var input []string
|
||||||
for _, p := range function.Parameters {
|
for _, p := range function.Parameters {
|
||||||
input = append(input, parser.CleanName(p.Name, p.Value))
|
input = append(input, parser.CleanName(p.Name, p.Value))
|
||||||
|
@ -110,7 +127,9 @@ func goFunctionBody(function *parser.Function) string {
|
||||||
ret_pre = "return "
|
ret_pre = "return "
|
||||||
ret_suf = fmt.Sprintf(".(%v)", out)
|
ret_suf = fmt.Sprintf(".(%v)", out)
|
||||||
|
|
||||||
if strings.Contains(ret_suf, "__") && !strings.Contains(ret_suf, "[") { //TODO: support for slices and maps containing enums
|
//TODO: is there some better way ?
|
||||||
|
//TODO: support for slices and maps as well
|
||||||
|
if (strings.Contains(ret_suf, "__") || strings.HasPrefix(ret_suf, ".(int") || strings.HasPrefix(ret_suf, ".(uint")) && !strings.Contains(ret_suf, "[") {
|
||||||
ret_pre += out + "("
|
ret_pre += out + "("
|
||||||
ret_suf = ".(float64))"
|
ret_suf = ".(float64))"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1456,7 +1456,7 @@ import "C"
|
||||||
|
|
||||||
var dartInput []string
|
var dartInput []string
|
||||||
fmt.Fprint(bb, "import (\n")
|
fmt.Fprint(bb, "import (\n")
|
||||||
for _, m := range append(parser.GetLibs(), "qt", "strings", "unsafe", "log", "runtime", "fmt", "errors", "js", "time", "hex", "reflect", "math", "sync", "strconv", "internal") {
|
for _, m := range append(parser.GetLibs(), "qt", "strings", "unsafe", "log", "runtime", "fmt", "errors", "js", "time", "hex", "reflect", "math", "sync", "strconv", "internal", "gow") {
|
||||||
mlow := strings.ToLower(m)
|
mlow := strings.ToLower(m)
|
||||||
if strings.Contains(inputString, fmt.Sprintf(" %v.", mlow)) ||
|
if strings.Contains(inputString, fmt.Sprintf(" %v.", mlow)) ||
|
||||||
strings.Contains(inputString, fmt.Sprintf("\t%v.", mlow)) ||
|
strings.Contains(inputString, fmt.Sprintf("\t%v.", mlow)) ||
|
||||||
|
@ -1480,6 +1480,9 @@ import "C"
|
||||||
case "internal":
|
case "internal":
|
||||||
fmt.Fprintln(bb, "\"github.com/therecipe/qt/internal\"")
|
fmt.Fprintln(bb, "\"github.com/therecipe/qt/internal\"")
|
||||||
|
|
||||||
|
case "gow":
|
||||||
|
fmt.Fprintln(bb, "\"github.com/therecipe/qt/interop/gow\"")
|
||||||
|
|
||||||
case "js":
|
case "js":
|
||||||
if parser.UseWasm() {
|
if parser.UseWasm() {
|
||||||
fmt.Fprintln(bb, "\"syscall/js\"")
|
fmt.Fprintln(bb, "\"syscall/js\"")
|
||||||
|
|
|
@ -289,7 +289,7 @@ func Minimal(path, target, tags string, skipSetup bool) {
|
||||||
if utils.QT_STATIC() {
|
if utils.QT_STATIC() {
|
||||||
exportClass(parser.State.ClassMap["QSvgWidget"], files)
|
exportClass(parser.State.ClassMap["QSvgWidget"], files)
|
||||||
}
|
}
|
||||||
if utils.QT_FELGO() {
|
if utils.QT_FELGO() || utils.QT_GEN_GO_WRAPPER() {
|
||||||
exportClass(parser.State.ClassMap["QCoreApplication"], files)
|
exportClass(parser.State.ClassMap["QCoreApplication"], files)
|
||||||
exportFunction(parser.State.ClassMap["QCoreApplication"].GetFunction("instance"), files)
|
exportFunction(parser.State.ClassMap["QCoreApplication"].GetFunction("instance"), files)
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ func Check(target string, docker, vagrant bool) {
|
||||||
{"QT_QMAKE_DIR", utils.QT_QMAKE_DIR()},
|
{"QT_QMAKE_DIR", utils.QT_QMAKE_DIR()},
|
||||||
{"QT_WEBKIT", fmt.Sprint(utils.QT_WEBKIT())},
|
{"QT_WEBKIT", fmt.Sprint(utils.QT_WEBKIT())},
|
||||||
{"QT_STATIC", fmt.Sprint(utils.QT_STATIC())},
|
{"QT_STATIC", fmt.Sprint(utils.QT_STATIC())},
|
||||||
{"QT_GEN_TSD", fmt.Sprint(utils.QT_GEN_TSD())},
|
{"QT_GEN_GO", fmt.Sprint(utils.QT_GEN_GO_WRAPPER())},
|
||||||
{"QT_GEN_OPENGL", fmt.Sprint(utils.QT_GEN_OPENGL())},
|
{"QT_GEN_OPENGL", fmt.Sprint(utils.QT_GEN_OPENGL())},
|
||||||
{"QT_GEN_QUICK_EXTRAS", fmt.Sprint(utils.QT_GEN_QUICK_EXTRAS())},
|
{"QT_GEN_QUICK_EXTRAS", fmt.Sprint(utils.QT_GEN_QUICK_EXTRAS())},
|
||||||
{"QT_RESOURCES_BIG", fmt.Sprint(utils.QT_RESOURCES_BIG())},
|
{"QT_RESOURCES_BIG", fmt.Sprint(utils.QT_RESOURCES_BIG())},
|
||||||
|
|
|
@ -36,7 +36,7 @@ func Generate(target string, docker, vagrant bool) {
|
||||||
mode = "stub"
|
mode = "stub"
|
||||||
}
|
}
|
||||||
|
|
||||||
if target == "windows" && runtime.GOOS == target {
|
if target == "windows" && runtime.GOOS == target && os.Getenv("QT_DEBUG_CONSOLE") != "false" {
|
||||||
os.Setenv("QT_DEBUG_CONSOLE", "true")
|
os.Setenv("QT_DEBUG_CONSOLE", "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +53,7 @@ func Generate(target string, docker, vagrant bool) {
|
||||||
}
|
}
|
||||||
utils.Log.Infof("generating %v qt/%v%v", mode, strings.ToLower(module), license)
|
utils.Log.Infof("generating %v qt/%v%v", mode, strings.ToLower(module), license)
|
||||||
|
|
||||||
if target == runtime.GOOS || utils.QT_FAT() || (mode == "full" && (target == "js" || target == "wasm")) ||
|
if target == runtime.GOOS || utils.QT_FAT() || (mode == "full" && (target == "js" || target == "wasm")) { //TODO: REVIEW
|
||||||
(utils.QT_STATIC() || utils.QT_MXE_STATIC()) && utils.QT_DOCKER() { //TODO: REVIEW
|
|
||||||
templater.GenModule(module, target, templater.NONE)
|
templater.GenModule(module, target, templater.NONE)
|
||||||
} else {
|
} else {
|
||||||
templater.CgoTemplate(module, "", target, templater.MINIMAL, "", "") //TODO: collect errors
|
templater.CgoTemplate(module, "", target, templater.MINIMAL, "", "") //TODO: collect errors
|
||||||
|
|
|
@ -15,7 +15,7 @@ jobs:
|
||||||
template: docker_showcase_template.yml
|
template: docker_showcase_template.yml
|
||||||
parameters:
|
parameters:
|
||||||
tag: box
|
tag: box
|
||||||
# dep: windows_64_static
|
dep: windows_64_shared_wine
|
||||||
-
|
-
|
||||||
template: docker_windows_ci_template.yml
|
template: docker_windows_ci_template.yml
|
||||||
parameters:
|
parameters:
|
||||||
|
|
|
@ -62,13 +62,15 @@ func handleCallback(message string) string {
|
||||||
var msg []interface{}
|
var msg []interface{}
|
||||||
json.Unmarshal([]byte(message), &msg)
|
json.Unmarshal([]byte(message), &msg)
|
||||||
|
|
||||||
|
meth := reflect.ValueOf(callbackTable[uintptr(msg[0].(float64))][msg[1].(string)])
|
||||||
|
|
||||||
rv := make([]reflect.Value, len(msg)-2)
|
rv := make([]reflect.Value, len(msg)-2)
|
||||||
for i, v := range convertList(msg[2:]) {
|
for i, v := range convertList(msg[2:]) {
|
||||||
rv[i] = reflect.ValueOf(v)
|
rv[i] = reflect.ValueOf(v).Convert(meth.Type().In(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
var output []byte
|
var output []byte
|
||||||
if ret := reflect.ValueOf(callbackTable[uintptr(msg[0].(float64))][msg[1].(string)]).Call(rv); len(ret) > 0 {
|
if ret := meth.Call(rv); len(ret) > 0 {
|
||||||
output, _ = json.Marshal(convertToJson(ret[0].Interface()))
|
output, _ = json.Marshal(convertToJson(ret[0].Interface()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,17 +156,25 @@ func convertToJson(i interface{}) interface{} {
|
||||||
return convertMapToJson(i.(map[string]interface{}))
|
return convertMapToJson(i.(map[string]interface{}))
|
||||||
|
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
return convertListToJson(i.([]interface{}))
|
switch i.(type) {
|
||||||
|
//TODO:
|
||||||
|
case []string:
|
||||||
|
case []uint, []uint8, []uint16, []uint32, []uint64:
|
||||||
|
case []int, []int8, []int16, []int32, []int64:
|
||||||
|
//
|
||||||
|
//case []*qml.QQmlError:
|
||||||
|
|
||||||
|
default:
|
||||||
|
return convertListToJson(i.([]interface{}))
|
||||||
|
}
|
||||||
|
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"___pointer": uintptr(reflect.ValueOf(i).MethodByName("Pointer").Call(nil)[0].Interface().(unsafe.Pointer)),
|
"___pointer": uintptr(reflect.ValueOf(i).MethodByName("Pointer").Call(nil)[0].Interface().(unsafe.Pointer)),
|
||||||
"___className": reflect.ValueOf(i).MethodByName("ClassNameInternalF").Call(nil)[0].Interface(),
|
"___className": reflect.ValueOf(i).MethodByName("ClassNameInternalF").Call(nil)[0].Interface(),
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
return i
|
|
||||||
}
|
}
|
||||||
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
var inited = false
|
var inited = false
|
||||||
|
@ -222,8 +232,13 @@ var Config = &InteropServerConfig{
|
||||||
"",
|
"",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
proc *exec.Cmd
|
||||||
|
stderr io.ReadCloser
|
||||||
|
)
|
||||||
|
|
||||||
// TODO: NewQApplication
|
// TODO: NewQApplication
|
||||||
func InitProcess() (*exec.Cmd, io.ReadCloser) {
|
func InitProcess() {
|
||||||
|
|
||||||
var runPath string
|
var runPath string
|
||||||
|
|
||||||
|
@ -258,7 +273,11 @@ func InitProcess() (*exec.Cmd, io.ReadCloser) {
|
||||||
|
|
||||||
println("final qtbox location:", runPath)
|
println("final qtbox location:", runPath)
|
||||||
|
|
||||||
if _, err := os.Stat(runPath); err == nil && Config.Override || err != nil {
|
dst := filepath.Dir(runPath)
|
||||||
|
_, err := os.Stat(runPath)
|
||||||
|
_, errF := os.Stat(filepath.Join(dst, "qtbox"))
|
||||||
|
|
||||||
|
if Config.Override || (err != nil && errF != nil) {
|
||||||
|
|
||||||
var copyWithProgress = func(w io.Writer, r io.Reader, callback func(off int64)) error {
|
var copyWithProgress = func(w io.Writer, r io.Reader, callback func(off int64)) error {
|
||||||
tee := io.TeeReader(r, w)
|
tee := io.TeeReader(r, w)
|
||||||
|
@ -306,16 +325,21 @@ func InitProcess() (*exec.Cmd, io.ReadCloser) {
|
||||||
fw.Close()
|
fw.Close()
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
dst := filepath.Dir(runPath)
|
|
||||||
|
|
||||||
for _, f := range r.File {
|
for _, f := range r.File {
|
||||||
|
|
||||||
|
//TODO: pack runtimes with correct name
|
||||||
|
fns := strings.Split(f.Name, "/")
|
||||||
|
fns[0] = "qtbox"
|
||||||
|
f.Name = strings.Join(fns, "/")
|
||||||
|
//
|
||||||
|
|
||||||
if f.FileInfo().IsDir() {
|
if f.FileInfo().IsDir() {
|
||||||
os.MkdirAll(filepath.Join(dst, f.Name), f.Mode())
|
os.MkdirAll(filepath.Join(dst, f.Name), f.Mode())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
dn, fn := filepath.Split(f.Name)
|
dn, fn := filepath.Split(f.Name)
|
||||||
if strings.HasPrefix(fn, "full") {
|
if strings.HasPrefix(fn, "full") { //TODO: pack runtimes with correct name
|
||||||
fn = filepath.Join(dn, "qtbox"+ending)
|
fn = filepath.Join(dn, "qtbox"+ending)
|
||||||
} else {
|
} else {
|
||||||
fn = f.Name
|
fn = f.Name
|
||||||
|
@ -337,8 +361,6 @@ func InitProcess() (*exec.Cmd, io.ReadCloser) {
|
||||||
fr.Close()
|
fr.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Rename(filepath.Join(dst, r.File[0].Name), filepath.Join(dst, "qtbox"))
|
|
||||||
|
|
||||||
runPath = filepath.Join(dst, "qtbox", "qtbox"+ending)
|
runPath = filepath.Join(dst, "qtbox", "qtbox"+ending)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,13 +377,16 @@ func InitProcess() (*exec.Cmd, io.ReadCloser) {
|
||||||
println(err.Error())
|
println(err.Error())
|
||||||
}
|
}
|
||||||
process.Start()
|
process.Start()
|
||||||
|
|
||||||
time.Sleep(3 * time.Second) //TODO:
|
time.Sleep(3 * time.Second) //TODO:
|
||||||
return process, rc
|
|
||||||
|
proc = process
|
||||||
|
stderr = rc
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: QApplication_Exec
|
// TODO: QApplication_Exec
|
||||||
func Exec(p *exec.Cmd, rc io.ReadCloser) {
|
func Exec() {
|
||||||
scanner := bufio.NewScanner(rc)
|
scanner := bufio.NewScanner(stderr)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
|
@ -376,5 +401,5 @@ func Exec(p *exec.Cmd, rc io.ReadCloser) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
p.Wait()
|
proc.Wait()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue