cgo-less interop related changes

This commit is contained in:
therecipe 2020-08-17 18:37:48 +02:00
parent 550ceb9a59
commit 494d2f8c1e
9 changed files with 90 additions and 27 deletions

1
.gitignore vendored
View file

@ -9,6 +9,7 @@
*.vagrant
.DS_Store
Mfile*
qtbox
*/*-minimal.*
*/*.o

View file

@ -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.
[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.
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
-----------
@ -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)
#### (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)
```powershell

View file

@ -95,6 +95,23 @@ func goFunctionBody(function *parser.Function) string {
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
for _, p := range function.Parameters {
input = append(input, parser.CleanName(p.Name, p.Value))
@ -110,7 +127,9 @@ func goFunctionBody(function *parser.Function) string {
ret_pre = "return "
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_suf = ".(float64))"
}

View file

@ -1456,7 +1456,7 @@ import "C"
var dartInput []string
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)
if strings.Contains(inputString, fmt.Sprintf(" %v.", mlow)) ||
strings.Contains(inputString, fmt.Sprintf("\t%v.", mlow)) ||
@ -1480,6 +1480,9 @@ import "C"
case "internal":
fmt.Fprintln(bb, "\"github.com/therecipe/qt/internal\"")
case "gow":
fmt.Fprintln(bb, "\"github.com/therecipe/qt/interop/gow\"")
case "js":
if parser.UseWasm() {
fmt.Fprintln(bb, "\"syscall/js\"")

View file

@ -289,7 +289,7 @@ func Minimal(path, target, tags string, skipSetup bool) {
if utils.QT_STATIC() {
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)
exportFunction(parser.State.ClassMap["QCoreApplication"].GetFunction("instance"), files)
}

View file

@ -55,7 +55,7 @@ func Check(target string, docker, vagrant bool) {
{"QT_QMAKE_DIR", utils.QT_QMAKE_DIR()},
{"QT_WEBKIT", fmt.Sprint(utils.QT_WEBKIT())},
{"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_QUICK_EXTRAS", fmt.Sprint(utils.QT_GEN_QUICK_EXTRAS())},
{"QT_RESOURCES_BIG", fmt.Sprint(utils.QT_RESOURCES_BIG())},

View file

@ -36,7 +36,7 @@ func Generate(target string, docker, vagrant bool) {
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")
}
@ -53,8 +53,7 @@ func Generate(target string, docker, vagrant bool) {
}
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")) ||
(utils.QT_STATIC() || utils.QT_MXE_STATIC()) && utils.QT_DOCKER() { //TODO: REVIEW
if target == runtime.GOOS || utils.QT_FAT() || (mode == "full" && (target == "js" || target == "wasm")) { //TODO: REVIEW
templater.GenModule(module, target, templater.NONE)
} else {
templater.CgoTemplate(module, "", target, templater.MINIMAL, "", "") //TODO: collect errors

View file

@ -15,7 +15,7 @@ jobs:
template: docker_showcase_template.yml
parameters:
tag: box
# dep: windows_64_static
dep: windows_64_shared_wine
-
template: docker_windows_ci_template.yml
parameters:

View file

@ -62,13 +62,15 @@ func handleCallback(message string) string {
var msg []interface{}
json.Unmarshal([]byte(message), &msg)
meth := reflect.ValueOf(callbackTable[uintptr(msg[0].(float64))][msg[1].(string)])
rv := make([]reflect.Value, len(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
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()))
}
@ -154,17 +156,25 @@ func convertToJson(i interface{}) interface{} {
return convertMapToJson(i.(map[string]interface{}))
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:
return map[string]interface{}{
"___pointer": uintptr(reflect.ValueOf(i).MethodByName("Pointer").Call(nil)[0].Interface().(unsafe.Pointer)),
"___className": reflect.ValueOf(i).MethodByName("ClassNameInternalF").Call(nil)[0].Interface(),
}
default:
return i
}
return i
}
var inited = false
@ -222,8 +232,13 @@ var Config = &InteropServerConfig{
"",
}
var (
proc *exec.Cmd
stderr io.ReadCloser
)
// TODO: NewQApplication
func InitProcess() (*exec.Cmd, io.ReadCloser) {
func InitProcess() {
var runPath string
@ -258,7 +273,11 @@ func InitProcess() (*exec.Cmd, io.ReadCloser) {
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 {
tee := io.TeeReader(r, w)
@ -306,16 +325,21 @@ func InitProcess() (*exec.Cmd, io.ReadCloser) {
fw.Close()
} else {
dst := filepath.Dir(runPath)
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() {
os.MkdirAll(filepath.Join(dst, f.Name), f.Mode())
continue
}
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)
} else {
fn = f.Name
@ -337,8 +361,6 @@ func InitProcess() (*exec.Cmd, io.ReadCloser) {
fr.Close()
}
os.Rename(filepath.Join(dst, r.File[0].Name), filepath.Join(dst, "qtbox"))
runPath = filepath.Join(dst, "qtbox", "qtbox"+ending)
}
}
@ -355,13 +377,16 @@ func InitProcess() (*exec.Cmd, io.ReadCloser) {
println(err.Error())
}
process.Start()
time.Sleep(3 * time.Second) //TODO:
return process, rc
proc = process
stderr = rc
}
// TODO: QApplication_Exec
func Exec(p *exec.Cmd, rc io.ReadCloser) {
scanner := bufio.NewScanner(rc)
func Exec() {
scanner := bufio.NewScanner(stderr)
go func() {
for scanner.Scan() {
@ -376,5 +401,5 @@ func Exec(p *exec.Cmd, rc io.ReadCloser) {
}
}()
p.Wait()
proc.Wait()
}