Skip to content

Commit

Permalink
cgo-less interop related changes
Browse files Browse the repository at this point in the history
  • Loading branch information
therecipe committed Aug 17, 2020
1 parent 550ceb9 commit 494d2f8
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 27 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*.vagrant
.DS_Store
Mfile*
qtbox

*/*-minimal.*
*/*.o
Expand Down
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
-----------
Expand All @@ -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
Expand Down
21 changes: 20 additions & 1 deletion internal/binding/templater/function_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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))"
}
Expand Down
5 changes: 4 additions & 1 deletion internal/binding/templater/template_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)) ||
Expand All @@ -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\"")
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/minimal/minimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/setup/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())},
Expand Down
5 changes: 2 additions & 3 deletions internal/cmd/setup/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion internal/docker/docker_pipelines_template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
59 changes: 42 additions & 17 deletions internal/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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)
}
}
Expand All @@ -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() {
Expand All @@ -376,5 +401,5 @@ func Exec(p *exec.Cmd, rc io.ReadCloser) {
}
}()

p.Wait()
proc.Wait()
}

0 comments on commit 494d2f8

Please sign in to comment.