experimental support for the msvc builds to get the webengine/webview modules working on windows

* Go 1.13 related fixes for js/wasm
* fix windows docker deployment issue
* new 3rdparty/UGlobalHotkey example
* fix webengine module on arch linux
* support for the prebuilt Qt wasm builds
* make use of -trimpath if available
* bump Go version in docker images to 1.12.9
This commit is contained in:
therecipe 2019-09-10 20:17:30 +02:00
parent d6c64b2b90
commit 33ee7b247d
49 changed files with 747 additions and 64 deletions

2
go.sum
View file

@ -2,6 +2,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
github.com/golang/net v0.0.0-20190420063019-afa5a82059c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
github.com/golang/sys v0.0.0-20190419153524-e8e3143a4f4a h1:5bYuhgnDII4NSAAw1wRU+pCovYhB/AqYVmsK2JDnK2k=
github.com/golang/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
github.com/golang/text v0.3.1-0.20190410012825-f4905fbd45b6/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
github.com/golang/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@ -9,6 +10,7 @@ github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORR
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

View file

@ -84,7 +84,7 @@ func GoInputParametersForJS(function *parser.Function) string {
}
} else {
alloc := GoInputJS(parameter.Name, parameter.Value, function, parameter.PureGoType)
if gType := GoType(function, parameter.Value, parameter.PureGoType); (parser.UseWasm() && strings.Contains(alloc, "js.TypedArrayOf(")) || gType == "*bool" || gType == "*int" {
if gType := GoType(function, parameter.Value, parameter.PureGoType); (parser.UseWasm() && strings.Contains(alloc, ".TypedArrayOf(")) || gType == "*bool" || gType == "*int" {
input = append(input, fmt.Sprintf("%vC", parser.CleanName(parameter.Name, parameter.Value)))
} else {
input = append(input, alloc)
@ -113,7 +113,7 @@ func GoInputParametersForJSAlloc(function *parser.Function) []string {
continue
}
//TODO: make it possible to pass nil strings; fix this on C side instead
input = append(input, fmt.Sprintf("var %v js.Value\nif %v != \"\" || true {\n%v = %v\ndefer (*js.TypedArray)(unsafe.Pointer(uintptr(%v.Get(\"data_ptr\").Int()))).Release()\n}\n", name, parser.CleanName(parameter.Name, parameter.Value), name, alloc, name))
input = append(input, fmt.Sprintf("var %v js.Value\nif %v != \"\" || true {\n%v = %v\ndefer qt.ReleaseTypedArray(unsafe.Pointer(uintptr(%v.Get(\"data_ptr\").Int())))\n}\n", name, parser.CleanName(parameter.Name, parameter.Value), name, alloc, name))
}
case "[]byte":
@ -122,7 +122,7 @@ func GoInputParametersForJSAlloc(function *parser.Function) []string {
continue
}
//TODO: make it possible to pass nil []bytes; fix this on C side instead
input = append(input, fmt.Sprintf("var %v js.Value\nif len(%v) != 0 || true {\n%v = %v\ndefer (*js.TypedArray)(unsafe.Pointer(uintptr(%v.Get(\"data_ptr\").Int()))).Release()\n}\n", name, parser.CleanName(parameter.Name, parameter.Value), name, alloc, name))
input = append(input, fmt.Sprintf("var %v js.Value\nif len(%v) != 0 || true {\n%v = %v\ndefer qt.ReleaseTypedArray(unsafe.Pointer(uintptr(%v.Get(\"data_ptr\").Int())))\n}\n", name, parser.CleanName(parameter.Name, parameter.Value), name, alloc, name))
}
case "*string", "[]string", "error":
@ -130,12 +130,12 @@ func GoInputParametersForJSAlloc(function *parser.Function) []string {
if !parser.UseWasm() {
continue
}
input = append(input, fmt.Sprintf("%v := %v\ndefer (*js.TypedArray)(unsafe.Pointer(uintptr(%v.Get(\"data_ptr\").Int()))).Release()\n", name, alloc, name))
input = append(input, fmt.Sprintf("%v := %v\ndefer qt.ReleaseTypedArray(unsafe.Pointer(uintptr(%v.Get(\"data_ptr\").Int())))\n", name, alloc, name))
}
case "*bool":
{
input = append(input, fmt.Sprintf("var %v %v\nif %v != nil {\n%v = qt.WASM.Call(\"_malloc\", 1)\nqt.WASM.Call(\"setValue\", %v, qt.GoBoolToInt(*%v), \"i8\")\ndefer func(){*%v = int8(qt.WASM.Call(\"getValue\", %v, \"i8\").Int()) != 0\nqt.WASM.Call(\"_free\", %v)\n}()\n}\n", name, func() string {
input = append(input, fmt.Sprintf("var %v %v\nif %v != nil {\n%v = qt.Module.Call(\"_malloc\", 1)\nqt.Module.Call(\"setValue\", %v, qt.GoBoolToInt(*%v), \"i8\")\ndefer func(){*%v = int8(qt.Module.Call(\"getValue\", %v, \"i8\").Int()) != 0\nqt.Module.Call(\"_free\", %v)\n}()\n}\n", name, func() string {
if parser.UseWasm() {
return "js.Value"
}
@ -145,7 +145,7 @@ func GoInputParametersForJSAlloc(function *parser.Function) []string {
case "*int":
{
input = append(input, fmt.Sprintf("var %v %v\nif %v != nil {\n%v = qt.WASM.Call(\"_malloc\", 4)\nqt.WASM.Call(\"setValue\", %v, *%v, \"i32\")\ndefer func(){*%v = int(int32(qt.WASM.Call(\"getValue\", %v, \"i32\").Int()))\nqt.WASM.Call(\"_free\", %v)\n}()\n}\n", name,
input = append(input, fmt.Sprintf("var %v %v\nif %v != nil {\n%v = qt.Module.Call(\"_malloc\", 4)\nqt.Module.Call(\"setValue\", %v, *%v, \"i32\")\ndefer func(){*%v = int(int32(qt.Module.Call(\"getValue\", %v, \"i32\").Int()))\nqt.Module.Call(\"_free\", %v)\n}()\n}\n", name,
func() string {
if parser.UseWasm() {
return "js.Value"

View file

@ -20,9 +20,9 @@ func GoEnum(n string, v string, e *parser.Enum) string {
e.NoConst = true
if parser.UseJs() {
if parser.UseWasm() {
return fmt.Sprintf("int64(qt.WASM.Call(\"_%v_%v_Type\").Int())", strings.Split(e.Fullname, "::")[0], n)
return fmt.Sprintf("int64(qt.Module.Call(\"_%v_%v_Type\").Int())", strings.Split(e.Fullname, "::")[0], n)
}
return fmt.Sprintf("qt.WASM.Call(\"_%v_%v_Type\").Int64()", strings.Split(e.Fullname, "::")[0], n)
return fmt.Sprintf("qt.Module.Call(\"_%v_%v_Type\").Int64()", strings.Split(e.Fullname, "::")[0], n)
}
return fmt.Sprintf("C.%v_%v_Type()", strings.Split(e.Fullname, "::")[0], n)
}

View file

@ -323,3 +323,14 @@ func variantWrapper(f *parser.Function, value string, p string) (string, string,
return p, "", fmt.Sprintf(".ToInterface().(%v)", strings.TrimSpace(vs[1]))
}
func lambda(i string) string {
if !utils.QT_MSVC() || !strings.HasPrefix(i, "({") {
return i
}
i = strings.TrimSuffix(strings.TrimPrefix(i, "("), ")")
i = "[&]" + i + "()"
is := strings.Split(i, ";")
is[len(is)-2] = "return " + is[len(is)-2]
return strings.Join(is, ";")
}

View file

@ -246,7 +246,7 @@ func CppInput(name, value string, f *parser.Function) string {
}
return fmt.Sprintf("({ emscripten::val tempVal = %v; %v ret = %v; ret; })", name, parser.CleanValue(value), cppInput("tempVal", value, f))
}
return fmt.Sprintf("({ %v_PackedString tempVal = %v; %v ret = %v; free(tempVal.data); ret; })", strings.Title(parser.State.ClassMap[f.ClassName()].Module), name, parser.CleanValue(value), cppInput("tempVal", value, f))
return lambda(fmt.Sprintf("({ %v_PackedString tempVal = %v; %v ret = %v; free(tempVal.data); ret; })", strings.Title(parser.State.ClassMap[f.ClassName()].Module), name, parser.CleanValue(value), cppInput("tempVal", value, f)))
}
out := cppInput(name, value, f)
@ -506,7 +506,7 @@ func cppInput(name, value string, f *parser.Function) string {
return fmt.Sprintf("*static_cast<%v*>(%v)", value, name)
}
return fmt.Sprintf("({ %v* tmpP = static_cast<%v*>(%v); %v tmpV = *tmpP; tmpP->~%v(); free(tmpP); tmpV; })", parser.CleanValue(value), value, name, parser.CleanValue(value), strings.Split(parser.CleanValue(value), "<")[0])
return lambda(fmt.Sprintf("({ %v* tmpP = static_cast<%v*>(%v); %v tmpV = *tmpP; tmpP->~%v(); free(tmpP); tmpV; })", parser.CleanValue(value), value, name, parser.CleanValue(value), strings.Split(parser.CleanValue(value), "<")[0]))
}
}
@ -529,7 +529,7 @@ func GoInputJS(name, value string, f *parser.Function, p string) string {
if strings.Contains(vOld, "**") {
if parser.UseWasm() {
return fmt.Sprintf("func() js.Value {\ntmp := js.TypedArrayOf([]byte(strings.Join(%v, \"|\")))\nreturn js.ValueOf(map[string]interface{}{\"data\": tmp, \"data_ptr\": unsafe.Pointer(&tmp)})\n}()", name)
return fmt.Sprintf("func() js.Value {\ntmp := qt.TypedArrayOf([]byte(strings.Join(%v, \"|\")))\nreturn js.ValueOf(map[string]interface{}{\"data\": tmp, \"data_ptr\": unsafe.Pointer(&tmp)})\n}()", name)
}
if f.SignalMode != parser.CALLBACK {
return fmt.Sprintf("func() *js.Object {\ntmp := new(js.Object)\nif js.InternalObject(%v).Get(\"$val\") == js.Undefined {\ntmp.Set(\"data\", []byte(js.InternalObject(%v).Call(\"join\", \"|\").String()))\n} else {\ntmp.Set(\"data\", []byte(strings.Join(%v, \"|\")))\n}\nreturn tmp\n}()", name, name, name) //needed for indirect exported pure js call -> can be ommited if build without js support
@ -540,7 +540,7 @@ func GoInputJS(name, value string, f *parser.Function, p string) string {
/* TODO: if value == "char" && strings.Count(vOld, "*") == 1 && f.Name == "readData" {} */
if parser.UseWasm() {
return fmt.Sprintf("func() js.Value {\ntmp := js.TypedArrayOf([]byte(%v))\nreturn js.ValueOf(map[string]interface{}{\"data\": tmp, \"data_ptr\": unsafe.Pointer(&tmp)})\n}()", name)
return fmt.Sprintf("func() js.Value {\ntmp := qt.TypedArrayOf([]byte(%v))\nreturn js.ValueOf(map[string]interface{}{\"data\": tmp, \"data_ptr\": unsafe.Pointer(&tmp)})\n}()", name)
}
return fmt.Sprintf("func() *js.Object {\ntmp := new(js.Object)\ntmp.Set(\"data\", []byte(%v))\nreturn tmp\n}()", name)
}
@ -548,7 +548,7 @@ func GoInputJS(name, value string, f *parser.Function, p string) string {
case "QStringList":
{
if parser.UseWasm() {
return fmt.Sprintf("func() js.Value {\ntmp := js.TypedArrayOf([]byte(strings.Join(%v, \"¡¦!\")))\nreturn js.ValueOf(map[string]interface{}{\"data\": tmp, \"data_ptr\": unsafe.Pointer(&tmp)})\n}()", name)
return fmt.Sprintf("func() js.Value {\ntmp := qt.TypedArrayOf([]byte(strings.Join(%v, \"¡¦!\")))\nreturn js.ValueOf(map[string]interface{}{\"data\": tmp, \"data_ptr\": unsafe.Pointer(&tmp)})\n}()", name)
}
if f.SignalMode != parser.CALLBACK {
return fmt.Sprintf("func() *js.Object {\ntmp := new(js.Object)\nif js.InternalObject(%v).Get(\"$val\") == js.Undefined {\ntmp.Set(\"data\", []byte(js.InternalObject(%v).Call(\"join\", \"¡¦!\").String()))\n} else {\ntmp.Set(\"data\", []byte(strings.Join(%v, \"¡¦!\")))\n}\nreturn tmp\n}()", name, name, name) //needed for indirect exported pure js call -> can be ommited if build without js support

View file

@ -9,6 +9,7 @@ import (
"strings"
"github.com/therecipe/qt/internal/binding/parser"
"github.com/therecipe/qt/internal/utils"
)
func GoOutput(name, value string, f *parser.Function, p string) string {
@ -587,7 +588,7 @@ func cppOutputPack(name, value string, f *parser.Function) string {
out = strings.Replace(out, "ret.", fmt.Sprintf("%vPacked.", parser.CleanName(name, value)), -1)
return out
}
} else {
} else if !utils.QT_MSVC() {
if strings.Contains(out, "_PackedString") {
out = strings.Replace(out, "({ ", "", -1)
out = strings.Replace(out, " })", "", -1)
@ -611,7 +612,7 @@ func cppOutputPacked(name, value string, f *parser.Function) string {
}
return "reinterpret_cast<uintptr_t>(" + out + ")"
}
} else {
} else if !utils.QT_MSVC() {
if strings.Contains(out, "_PackedString") {
return fmt.Sprintf("%vPacked", parser.CleanName(name, value))
}
@ -637,6 +638,10 @@ func cppOutputPackingListForJs(hash string) string {
}
func cppOutput(name, value string, f *parser.Function) string {
return lambda(_cppOutput(lambda(name), value, f))
}
func _cppOutput(name, value string, f *parser.Function) string {
var vOld = value
var tHash = sha1.New()

View file

@ -175,7 +175,7 @@ func (c *Class) fixGeneral_Version() {
}
}
case "QWebEnginePage", "QWebEngineView":
case "QWebEnginePage", "QWebEngineView", "QWebEngineClientCertificateSelection":
{
for _, f := range c.Functions {
if !((f.Name == "QWebEnginePage" && f.OverloadNumber == "3") ||

View file

@ -424,7 +424,7 @@ func GetLibs() []string {
for i := len(libs) - 1; i >= 0; i-- {
switch {
case !(runtime.GOOS == "darwin" || runtime.GOOS == "linux" || runtime.GOOS == "freebsd") && (libs[i] == "WebEngine" || libs[i] == "WebView"),
case !(runtime.GOOS == "darwin" || runtime.GOOS == "linux" || runtime.GOOS == "freebsd" || (runtime.GOOS == "windows" && utils.QT_MSVC())) && (libs[i] == "WebEngine" || libs[i] == "WebView"),
runtime.GOOS != "windows" && libs[i] == "WinExtras",
runtime.GOOS != "darwin" && libs[i] == "MacExtras",
!(runtime.GOOS == "linux" || runtime.GOOS == "freebsd") && libs[i] == "X11Extras":

View file

@ -117,7 +117,7 @@ func goFunctionBody(function *parser.Function) string {
var body string
if UseJs() {
body = converter.GoJSOutputParametersFromC(function, fmt.Sprintf("qt.WASM.Call(\"_%v\", %v)", converter.CppHeaderName(function), converter.GoInputParametersForJS(function)))
body = converter.GoJSOutputParametersFromC(function, fmt.Sprintf("qt.Module.Call(\"_%v\", %v)", converter.CppHeaderName(function), converter.GoInputParametersForJS(function)))
} else {
body = converter.GoOutputParametersFromC(function, fmt.Sprintf("C.%v(%v)", converter.CppHeaderName(function), converter.GoInputParametersForC(function)))
}
@ -328,9 +328,9 @@ func goFunctionBody(function *parser.Function) string {
if pType := converter.GoType(function, p.Value, p.PureGoType); pType == "*bool" || pType == "*int" {
if UseJs() {
if pType == "*int" {
fmt.Fprintf(bb, "var %[1]vR int\nif %[1]v != 0 {\n%[1]vR = int(int32(qt.WASM.Call(\"getValue\", %[1]v, \"i32\").Int()))\ndefer func(){qt.WASM.Call(\"setValue\", %[1]v, %[1]vR, \"i32\")}()\n}\n", parser.CleanName(p.Name, p.Value))
fmt.Fprintf(bb, "var %[1]vR int\nif %[1]v != 0 {\n%[1]vR = int(int32(qt.Module.Call(\"getValue\", %[1]v, \"i32\").Int()))\ndefer func(){qt.Module.Call(\"setValue\", %[1]v, %[1]vR, \"i32\")}()\n}\n", parser.CleanName(p.Name, p.Value))
} else { //TODO: make empty *bool callbacks safe?
fmt.Fprintf(bb, "%[1]vR := int8(qt.WASM.Call(\"getValue\", %[1]v, \"i8\").Int()) != 0\ndefer func(){qt.WASM.Call(\"setValue\", %[1]v, qt.GoBoolToInt(%[1]vR), \"i8\")}()\n", parser.CleanName(p.Name, p.Value))
fmt.Fprintf(bb, "%[1]vR := int8(qt.Module.Call(\"getValue\", %[1]v, \"i8\").Int()) != 0\ndefer func(){qt.Module.Call(\"setValue\", %[1]v, qt.GoBoolToInt(%[1]vR), \"i8\")}()\n", parser.CleanName(p.Name, p.Value))
}
} else {
if pType == "*int" {

View file

@ -138,12 +138,12 @@ func isAlreadyCached(module, path, target string, mode int, libs []string) bool
switch target {
case "windows":
if utils.QT_DEBUG_CONSOLE() {
if strings.Contains(file, "subsystem,windows") {
if strings.Contains(file, "subsystem,windows") || strings.Contains(file, "/SUBSYSTEM:WINDOWS") {
utils.Log.Debugln("wrong subsystem: have windows and want console, re-creating ...")
return false
}
} else {
if strings.Contains(file, "subsystem,console") {
if strings.Contains(file, "subsystem,console") || strings.Contains(file, "/SUBSYSTEM:CONSOLE") {
utils.Log.Debugln("wrong subsystem: have console and want windows, re-creating ...")
return false
}
@ -290,7 +290,11 @@ func createMakefile(module, path, target string, mode int) {
if utils.QT_DEBUG_CONSOLE() {
subsystem = "console"
}
cmd.Args = append(cmd.Args, []string{"-spec", "win32-g++", "CONFIG+=" + subsystem}...)
spec := "win32-g++"
if utils.QT_MSVC() {
spec = "win32-msvc"
}
cmd.Args = append(cmd.Args, []string{"-spec", spec, "CONFIG+=" + subsystem}...)
case "linux":
cmd.Args = append(cmd.Args, []string{"-spec", "linux-g++"}...)
case "freebsd":
@ -544,7 +548,9 @@ func createCgo(module, path, target string, mode int, ipkg, tags string) string
case "android", "android-emulator":
fmt.Fprint(bb, "#cgo LDFLAGS: -Wl,--allow-shlib-undefined\n")
case "windows":
if !utils.QT_MSVC() {
fmt.Fprint(bb, "#cgo LDFLAGS: -Wl,--allow-multiple-definition\n")
}
case "ios":
fmt.Fprintf(bb, "#cgo CXXFLAGS: -isysroot %v/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/%v -miphoneos-version-min=11.0\n", utils.XCODE_DIR(), utils.IPHONEOS_SDK_DIR())
fmt.Fprintf(bb, "#cgo LDFLAGS: -Wl,-syslibroot,%v/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/%v -miphoneos-version-min=11.0\n", utils.XCODE_DIR(), utils.IPHONEOS_SDK_DIR())
@ -555,8 +561,10 @@ func createCgo(module, path, target string, mode int, ipkg, tags string) string
fmt.Fprint(bb, "#cgo CFLAGS: -s EXTRA_EXPORTED_RUNTIME_METHODS=['getValue','setValue']\n")
}
if !utils.QT_MSVC() {
fmt.Fprint(bb, "#cgo CFLAGS: -Wno-unused-parameter -Wno-unused-variable -Wno-return-type\n")
fmt.Fprint(bb, "#cgo CXXFLAGS: -Wno-unused-parameter -Wno-unused-variable -Wno-return-type\n")
}
fmt.Fprint(bb, "*/\nimport \"C\"\n")
@ -621,6 +629,15 @@ func createCgo(module, path, target string, mode int, ipkg, tags string) string
tmp = strings.Replace(tmp, "-fdata-sections", "", -1)
tmp = strings.Replace(tmp, "-Wl,-dead_strip", "", -1)
case "windows":
if utils.QT_MSVC() {
tmp = strings.Replace(tmp, "-DUNICODE", "-D_ALLOW_KEYWORD_MACROS -DUNICODE", -1)
tmp = strings.Replace(tmp, "-wd4467", "-wd4467 -wd4716", -1)
tmp = strings.Replace(tmp, `"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'"`, "", -1) //TODO:
tmp = strings.Replace(tmp, " CFLAGS:", " MSCFLAGS:", -1)
tmp = strings.Replace(tmp, " CXXFLAGS:", " MSCXXFLAGS:", -1)
tmp = strings.Replace(tmp, " LDFLAGS:", " MSLDFLAGS:", -1)
}
if utils.QT_MSYS2() {
tmp = strings.Replace(tmp, ",--relax,--gc-sections", "", -1)
if utils.QT_MSYS2_STATIC() {
@ -640,8 +657,10 @@ func createCgo(module, path, target string, mode int, ipkg, tags string) string
}
if utils.QT_DEBUG_CONSOLE() { //TODO: necessary at all?
tmp = strings.Replace(tmp, "subsystem,windows", "subsystem,console", -1)
tmp = strings.Replace(tmp, "/SUBSYSTEM:WINDOWS", "/SUBSYSTEM:CONSOLE", -1)
} else {
tmp = strings.Replace(tmp, "subsystem,console", "subsystem,windows", -1)
tmp = strings.Replace(tmp, "/SUBSYSTEM:CONSOLE", "/SUBSYSTEM:WINDOWS", -1)
}
if utils.QT_MXE() {
if li := fmt.Sprintf("-L %v", filepath.Join(utils.QT_MXE_DIR(), "usr", utils.QT_MXE_TRIPLET(), "qt5", "lib")); !strings.Contains(tmp, li) {

View file

@ -541,9 +541,9 @@ func (ptr *%[1]v) Destroy%[1]v() {
for _, l := range strings.Split(bb.String(), "\n") {
if strings.HasPrefix(l, "//export") {
if parser.UseWasm() {
fmt.Fprintf(bb, "qt.WASM.Set(\"_%[1]v\", js.FuncOf(%[1]v))\n", strings.TrimPrefix(l, "//export "))
fmt.Fprintf(bb, "qt.Module.Set(\"_%[1]v\", js.FuncOf(%[1]v))\n", strings.TrimPrefix(l, "//export "))
} else {
fmt.Fprintf(bb, "qt.WASM.Set(\"_%[1]v\", %[1]v)\n", strings.TrimPrefix(l, "//export "))
fmt.Fprintf(bb, "qt.Module.Set(\"_%[1]v\", %[1]v)\n", strings.TrimPrefix(l, "//export "))
}
}
}

View file

@ -113,6 +113,20 @@ func InitEnv(target string) {
}
defer func() {
if utils.QT_MSVC() {
utils.SaveExec(filepath.Join(utils.GOBIN(), "qtenvexc.bat"), fmt.Sprintf("call \"%v\"\r\nset", utils.GOVSVARSPATH()))
for _, s := range strings.Split(utils.RunCmdOptional(exec.Command(".\\qtenvexc.bat"), fmt.Sprintf("run qtenvexc for %v on %v", target, runtime.GOOS)), "\r\n") {
if !strings.Contains(s, "=") {
continue
}
es := strings.Split(s, "=")
os.Setenv(es[0], strings.Join(es[1:], "="))
}
utils.RemoveAll(filepath.Join(utils.GOBIN(), "qtenvexc.bat"))
}
QT_MSVC := utils.QT_MSVC()
os.Unsetenv("QT_MSVC")
qtenvPath := filepath.Join(filepath.Dir(utils.ToolPath("qmake", target)), "qtenv2.bat")
for _, s := range strings.Split(utils.Load(qtenvPath), "\r\n") {
if strings.HasPrefix(s, "set PATH") {
@ -120,6 +134,9 @@ func InitEnv(target string) {
break
}
}
if QT_MSVC {
os.Setenv("QT_MSVC", "true")
}
for i, dPath := range []string{filepath.Join(runtime.GOROOT(), "bin", "qtenv.bat"), filepath.Join(utils.GOBIN(), "qtenv.bat")} {
sPath := qtenvPath
@ -713,6 +730,12 @@ func BuildEnv(target, name, depPath string) (map[string]string, []string, []stri
}
env["PATH"] = path + ";" + env["PATH"]
}
if utils.QT_MSVC() {
env["CC_FOR_CGO"] = "gcc"
env["CC"] = "cl"
}
} else {
delete(env, "TMP")
delete(env, "TEMP")
@ -911,13 +934,19 @@ func BuildEnv(target, name, depPath string) (map[string]string, []string, []stri
env["CGO_LDFLAGS_ALLOW"] = utils.CGO_LDFLAGS_ALLOW()
}
if utils.QT_MSVC() {
env["CGO_MSCFLAGS_ALLOW"] = utils.CGO_MSCFLAGS_ALLOW()
env["CGO_MSCXXFLAGS_ALLOW"] = utils.CGO_MSCXXFLAGS_ALLOW()
env["CGO_MSLDFLAGS_ALLOW"] = utils.CGO_MSLDFLAGS_ALLOW()
}
if flags := utils.GOFLAGS(); len(flags) != 0 {
env["GOFLAGS"] = flags
}
for _, e := range os.Environ() {
es := strings.Split(e, "=")
if _, ok := env[es[0]]; !ok {
if _, ok := env[es[0]]; !ok || es[0] == "PATH" {
env[es[0]] = strings.Join(es[1:], "=")
}
}

View file

@ -68,6 +68,9 @@ func build(mode, target, path, ldFlagsCustom, tagsCustom, name, depPath string,
cmd.Args = append(cmd.Args, fmt.Sprintf("-ldflags=%v%v", pattern, escapeFlags(ldFlags, ldFlagsCustom)))
}
}
if utils.GOVERSION_NUM() >= 113 {
cmd.Args = append(cmd.Args, "-trimpath")
}
cmd.Args = append(cmd.Args, "-o", out+ending)
cmd.Dir = path

View file

@ -321,7 +321,7 @@ func bundle(mode, target, path, name, depPath string, tagsCustom string, fast bo
}
var libraryPath = filepath.Join(utils.QT_MXE_DIR(), "usr", utils.QT_MXE_TRIPLET(), "bin")
for _, d := range []string{"libbz2", "libfreetype-6", "libglib-2.0-0", "libharfbuzz-0", "libiconv-2", "libintl-8", "libpcre-1", "libpcre16-0", "libpng16-16", "libstdc++-6", "libwinpthread-1", "zlib1", "libgraphite2", "libeay32", "ssleay32", "libcrypto-1_1-x64", "libpcre2-16-0", "libssl-1_1-x64"} {
for _, d := range []string{"libbz2", "libfreetype-6", "libglib-2.0-0", "libharfbuzz-0", "libiconv-2", "libintl-8", "libpcre-1", "libpcre16-0", "libpng16-16", "libstdc++-6", "libwinpthread-1", "zlib1", "libgraphite2", "libeay32", "ssleay32", "libcrypto-1_1-x64", "libpcre2-16-0", "libssl-1_1-x64", "libzstd"} {
if utils.QT_MXE_ARCH() == "386" {
d = strings.TrimSuffix(d, "-x64")
}
@ -451,13 +451,12 @@ func bundle(mode, target, path, name, depPath string, tagsCustom string, fast bo
}
}
var walkFn = func(path string, info os.FileInfo, err error) error {
filepath.Walk(depPath, func(path string, info os.FileInfo, err error) error {
if strings.HasSuffix(info.Name(), "d.dll") {
utils.RemoveAll(path)
}
return nil
}
filepath.Walk(depPath, walkFn)
})
default:
@ -494,6 +493,10 @@ func bundle(mode, target, path, name, depPath string, tagsCustom string, fast bo
dep := exec.Command(utils.ToolPath("windeployqt", target))
dep.Args = append(dep.Args, "--verbose=2", "--force", fmt.Sprintf("--qmldir=%v", path), filepath.Join(depPath, name+".exe"))
utils.RunCmd(dep, fmt.Sprintf("deploy for %v on %v", target, runtime.GOOS))
if utils.QT_MSVC() {
cmd.PatchBinary(filepath.Join(depPath, name+".exe"))
}
}
//<--
@ -774,7 +777,13 @@ func bundle(mode, target, path, name, depPath string, tagsCustom string, fast bo
utils.Save(filepath.Join(depPath, "index.html"), strings.Replace(index, " </body>", " <script type=\"text/javascript\" src=\"go.js\"></script>\n </body>", -1))
if parser.UseWasm() {
utils.Save(filepath.Join(depPath, "go.js"), strings.Replace(utils.Load(filepath.Join(depPath, "go.js")), "})();", wasm_js(), -1))
gojs := utils.Load(filepath.Join(depPath, "go.js"))
if utils.GOVERSION_NUM() >= 113 {
gojs = strings.Replace(gojs, "\"syscall/js.valueCall\": (sp) => {", "\"syscall/js.valueCall\": (sp) => {\n\t\t\t\t\t\t\tconst s = loadString(sp + 16); if (s.search(\"_Exec\") != -1) { const v = loadValue(sp + 8); Reflect.apply(Reflect.get(v, s), v, loadSliceOfValues(sp + 32)); }", -1)
gojs = strings.Replace(gojs, "v, loadString(sp + 16));", "v, s);", -1)
}
gojs = strings.Replace(gojs, "})();", wasm_js(), -1)
utils.Save(filepath.Join(depPath, "go.js"), gojs)
} else {
gojs := utils.Load(filepath.Join(depPath, "go.js"))
gojs = strings.Replace(gojs, "(function() {", "Module._goMain = function() {", -1)

View file

@ -103,6 +103,11 @@ func Deploy(mode, target, path string, docker bool, ldFlags, tags string, fast b
if fn := filepath.Join(depPath, name+".app", "Contents", "Info.plist"); !utils.ExistsFile(fn) {
utils.Save(fn, darwin_plist(name))
}
case "windows":
if utils.QT_MSVC() {
_, _, _, out := cmd.BuildEnv(target, name, depPath)
cmd.PatchBinary(out + ".exe")
}
}
}
}

View file

@ -80,7 +80,7 @@ func run(target, name, depPath, device string) {
case "js", "wasm": //TODO: REVIEW and use emscripten wrapper instead
if runtime.GOOS == "darwin" {
exec.Command("/Applications/Firefox Nightly.app/Contents/MacOS/firefox", filepath.Join(depPath, "index.html")).Start()
exec.Command("/Applications/Firefox.app/Contents/MacOS/firefox", filepath.Join(depPath, "index.html")).Start()
}
}
}

View file

@ -115,6 +115,17 @@ func Check(target string, docker, vagrant bool) {
}...)
}
if utils.QT_MSVC() {
vars = append(vars, [][]string{
{"QT_MSVC", fmt.Sprint(utils.QT_MSVC())},
{"GOVSVARSPATH", utils.GOVSVARSPATH()},
}...)
if _, err := exec.LookPath("cl"); err != nil {
utils.Log.WithError(err).Panic("failed to find cl, did you start the MSVC shell?")
}
}
if _, err := exec.LookPath("g++"); err != nil && !utils.QT_MSYS2() {
utils.Log.WithError(err).Panic("failed to find g++, did you start the MinGW shell?")
}

View file

@ -6,6 +6,7 @@ import (
"path/filepath"
"runtime"
"github.com/therecipe/qt/internal/cmd"
"github.com/therecipe/qt/internal/utils"
)
@ -69,4 +70,8 @@ func Prep(target string) {
utils.Save(filepath.Join(utils.QT_INSTALL_PREFIX(target), file), utils.Load(f))
}
}
if runtime.GOOS == "windows" && target == runtime.GOOS && utils.QT_MSVC() {
cmd.PatchLibs()
}
}

166
internal/cmd/utils_msvc.go Normal file
View file

@ -0,0 +1,166 @@
package cmd
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/therecipe/qt/internal/utils"
)
var rep = map[string]string{
"@@MEAA": "@@UEAA",
"@@MEBA": "@@UEBA",
"@@IEAA": "@@QEAA",
"@@AEBA": "@@QEBA",
"@@EEBA": "@@UEBA",
"@@EEAA": "@@UEAA",
"@@IEBA": "@@QEBA",
"@@AEAA": "@@QEAA",
"@@CA": "@@SA",
"@@KA": "@@SA",
"@@1U": "@@2U",
"@QCoreApplication@@0PEAV": "@QCoreApplication@@2PEAV",
}
var block = map[string]string{"@@AEBA": "@Connection@QMetaObject"}
func libs() (libs []string) {
filepath.Walk(filepath.Join(utils.QT_INSTALL_PREFIX("windows"), "lib"), func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() {
return err
}
if filepath.Ext(info.Name()) == ".lib" && strings.HasPrefix(info.Name(), "Qt5") && !strings.Contains(info.Name(), "lib.orig") &&
(!strings.Contains(info.Name(), "d.lib") || strings.HasSuffix(info.Name(), "board.lib")) {
libs = append(libs, path)
}
return nil
})
return
}
func PatchLibs() {
for _, l := range libs() {
patchLib(l)
}
}
func patchLib(l string) {
utils.Log.WithField("lib", l).Debugln("patching lib")
if utils.ExistsFile(strings.Replace(l, ".lib", "lib.orig", -1)) {
utils.RemoveAll(l)
os.Rename(strings.Replace(l, ".lib", "lib.orig", -1), l)
}
data, _ := ioutil.ReadFile(l)
for _, prr := range symbolsSliceFor(l, false, true) {
for pr, pa := range rep {
if !bytes.Contains(prr, []byte(pr)) {
continue
}
data = bytes.Replace(data, prr, bytes.Replace(prr, []byte(pr), []byte(pa), -1), -1)
if pref, ok := block[pr]; ok && bytes.Contains(prr, []byte(pref)) {
data = bytes.Replace(data, append([]byte(pref), pa...), append([]byte(pref), pr...), -1)
}
}
}
utils.SaveBytes(l, data)
}
func PatchBinary(fn string) {
utils.Log.WithField("file", fn).Debugln("patching binary")
data, err := ioutil.ReadFile(fn)
if err != nil {
utils.Log.WithError(err).Errorln("failed to load binary")
}
for _, l := range libs() {
sb := symbolsSliceFor(strings.Replace(l, ".lib", "lib.orig", -1), true, false)
for i, s := range symbolsSliceFor(l, true, false) {
if bytes.Equal(s, sb[i]) {
continue
}
if bytes.Contains(data, s) {
//println(string(s), "patch->", string(sb[i]))
data = bytes.Replace(data, s, sb[i], -1)
}
}
}
utils.SaveBytes(fn, data)
}
func symbolsSliceFor(fn string, skipDll bool, backup bool) (symbols [][]byte) {
data, err := ioutil.ReadFile(fn)
if err != nil {
utils.Log.WithError(err).Debugln("failed to load")
return nil
}
if backup {
utils.SaveBytes(strings.Replace(fn, ".lib", "lib.orig", -1), data)
}
for _, s := range bytes.Split(data, []byte("?")) {
if !bytes.Contains(s, []byte("@@")) || (skipDll && bytes.Contains(s, []byte(".dll"))) {
continue
}
if bytes.Contains(s, []byte("__")) {
symbols = append(symbols, bytes.Split(s, []byte("__"))[0])
} else {
symbols = append(symbols, s)
}
}
return
}
func testLibs() {
for _, l := range libs() {
test(l)
}
}
func test(fn string) {
skipDll := true
patchLib(fn)
PatchBinary(fn)
var j int
sb := symbolsSliceFor(strings.Replace(fn, ".lib", "lib.orig", -1), skipDll, false)
for i, s := range symbolsSliceFor(fn, skipDll, false) {
if bytes.Equal(s, sb[i]) {
continue
}
j++
}
if j != 0 {
println("symbol diff", j)
}
c, _ := ioutil.ReadFile(fn)
a := sha256.New()
a.Write(c)
ch := hex.EncodeToString(a.Sum(nil))
c, _ = ioutil.ReadFile(strings.Replace(fn, ".lib", "lib.orig", -1))
a = sha256.New()
a.Write(c)
bh := hex.EncodeToString(a.Sum(nil))
if ch != bh {
println("hash diff", ch, bh)
}
}

View file

@ -48,7 +48,7 @@ RUN rm /usr/bin/strip && ln -s /osxcross/target/bin/x86_64-apple-darwin18-strip
RUN ln -s /osxcross/target/bin/x86_64-apple-darwin18-otool /usr/bin/otool
RUN ln -s /osxcross/target/bin/x86_64-apple-darwin18-install_name_tool /usr/bin/install_name_tool
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN go get github.com/therecipe/qt/cmd/...
RUN go get github.com/therecipe/env_darwin_amd64_513 && DST=$GOPATH/src/github.com/therecipe/env_darwin_amd64_513/5.13.0/clang_64/bin && rm -r $DST && cp -r $GOPATH/src/github.com/therecipe/env_linux_amd64_513/5.13.0/gcc_64/bin $DST

View file

@ -48,7 +48,7 @@ RUN rm /usr/bin/strip && ln -s /osxcross/target/bin/x86_64-apple-darwin18-strip
RUN ln -s /osxcross/target/bin/x86_64-apple-darwin18-otool /usr/bin/otool
RUN ln -s /osxcross/target/bin/x86_64-apple-darwin18-install_name_tool /usr/bin/install_name_tool
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN go get -tags=no_env github.com/therecipe/qt/cmd/... && go get github.com/therecipe/env_linux_amd64_512
RUN go get github.com/therecipe/env_darwin_amd64_512 && DST=$GOPATH/src/github.com/therecipe/env_darwin_amd64_512/5.12.0/clang_64/bin && rm -r $DST && cp -r $GOPATH/src/github.com/therecipe/env_linux_amd64_512/5.12.0/gcc_64/bin $DST

View file

@ -5,7 +5,7 @@ ENV HOME /home/$USER
ENV GOPATH $HOME/work
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install dbus fontconfig libx11-6 libx11-xcb1

View file

@ -5,7 +5,7 @@ ENV HOME /home/$USER
ENV GOPATH $HOME/work
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install dbus fontconfig libx11-6 libx11-xcb1

View file

@ -5,7 +5,7 @@ ENV HOME /home/$USER
ENV GOPATH $HOME/work
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install dbus fontconfig libx11-6 libx11-xcb1

View file

@ -5,7 +5,7 @@ ENV HOME /home/$USER
ENV GOPATH $HOME/work
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install dbus fontconfig libx11-6 libx11-xcb1

View file

@ -6,7 +6,7 @@ ENV GOPATH $HOME/work
RUN pacman -Syyu --quiet || true
RUN pacman -S --noconfirm --needed --noprogressbar --quiet ca-certificates curl git tar
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
FROM archlinux/base

View file

@ -5,7 +5,7 @@ ENV HOME /home/$USER
ENV GOPATH $HOME/work
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
FROM debian:10.0

View file

@ -5,7 +5,7 @@ ENV HOME /home/$USER
ENV GOPATH $HOME/work
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
FROM debian:9.0

View file

@ -5,7 +5,7 @@ ENV HOME /home/$USER
ENV GOPATH $HOME/work
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...

View file

@ -3,7 +3,7 @@ FROM opensuse/leap:latest as base
ENV GOPATH $HOME/work
RUN zypper -q ref && zypper -n -q install --no-recommends curl git gzip tar
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
FROM opensuse/leap:latest

View file

@ -3,7 +3,7 @@ FROM opensuse/tumbleweed:latest as base
ENV GOPATH $HOME/work
RUN zypper -q ref && zypper -n -q install --no-recommends curl git gzip tar
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
FROM opensuse/tumbleweed:latest

View file

@ -5,7 +5,7 @@ ENV HOME /home/$USER
ENV GOPATH $HOME/work
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
FROM ubuntu:16.04

View file

@ -5,7 +5,7 @@ ENV HOME /home/$USER
ENV GOPATH $HOME/work
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...
FROM ubuntu:18.04

View file

@ -5,7 +5,7 @@ ENV HOME /home/$USER
ENV GOPATH $HOME/work
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
RUN GO=go1.12.6.linux-386.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN GO=go1.12.9.linux-386.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local
RUN /usr/local/go/bin/go get -tags=no_env github.com/therecipe/qt/cmd/...

View file

@ -7,7 +7,7 @@ ENV GOPATH $HOME/.wine/drive_c/gopath
ENV WINEDEBUG -all
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git && apt-get -qq clean
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local && rm -f $GO
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local && rm -f $GO
RUN GOOS=windows /usr/local/go/bin/go get -d -tags=no_env github.com/therecipe/qt/cmd/...
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install software-properties-common apt-transport-https && apt-get -qq clean

View file

@ -7,7 +7,7 @@ ENV GOPATH $HOME/.wine/drive_c/gopath
ENV WINEDEBUG -all
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git && apt-get -qq clean
RUN GO=go1.12.6.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local && rm -f $GO
RUN GO=go1.12.9.linux-amd64.tar.gz && curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && tar -xzf $GO -C /usr/local && rm -f $GO
RUN GOOS=windows /usr/local/go/bin/go get -d -tags=no_env github.com/therecipe/qt/cmd/...
RUN apt-get -qq update && apt-get --no-install-recommends -qq -y install software-properties-common apt-transport-https && apt-get -qq clean

View file

@ -0,0 +1,27 @@
package main
import (
"os"
"github.com/therecipe/qt/widgets"
"github.com/therecipe/qt/internal/examples/3rdparty/uglobalhotkey/UGlobalHotkey"
)
func main() {
widgets.NewQApplication(len(os.Args), os.Args)
hk := UGlobalHotkey.NewUGlobalHotkeys(nil)
hk.RegisterHotkey("Ctrl+Shift+A", 1)
hk.ConnectActivated(func(id uint) {
println("Activated:", id)
})
hk = UGlobalHotkey.NewUGlobalHotkeys(nil)
hk.RegisterHotkey("Ctrl+Shift+B", 2)
hk.ConnectActivated(func(id uint) {
println("Activated:", id)
})
widgets.QApplication_Exec()
}

View file

@ -0,0 +1,85 @@
// +build ignore
package main
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
)
func main() {
if _, ok := os.LookupEnv("QT_DIR"); !ok {
println("please export QT_DIR")
os.Exit(1)
}
pwd, pwdErr := os.Getwd()
if pwdErr != nil {
println("failed to get PWD", pwdErr.Error())
os.Exit(1)
}
if _, err := os.Stat("UGlobalHotkey"); err == nil {
println("UGlobalHotkey already cloned")
} else {
if out, err := exec.Command("git", "clone", "--depth=1", "https://github.com/falceeffect/UGlobalHotkey.git").CombinedOutput(); err != nil {
println("failed to clone UGlobalHotkey", err.Error())
println(string(out))
os.Exit(1)
}
println("cloned UGlobalHotkey")
}
for _, target := range []string{runtime.GOOS} {
var qmake string
switch target {
case "darwin":
qmake = filepath.Join(os.Getenv("QT_DIR"), "5.13.0", "clang_64", "bin", "qmake")
case "linux":
qmake = filepath.Join(os.Getenv("QT_DIR"), "5.13.0", "gcc_64", "bin", "qmake")
case "windows":
if _, ok := os.LookupEnv("QT_MSVC"); ok {
qmake = filepath.Join(os.Getenv("QT_DIR"), "5.13.0", "msvc2017_64", "bin", "qmake")
} else {
qmake = filepath.Join(os.Getenv("QT_DIR"), "5.13.0", "mingw73_64", "bin", "qmake")
}
}
qCmd := exec.Command(qmake, filepath.Join(pwd, "UGlobalHotkey", "uglobalhotkey.pri"))
qCmd.Dir = filepath.Join(pwd, "UGlobalHotkey")
if out, err := qCmd.CombinedOutput(); err != nil {
println("failed to generate makefile for", target, err.Error())
println(string(out))
os.Exit(1)
}
println("generated makefile for", target)
iCmd := exec.Command("make", "mocables")
iCmd.Dir = filepath.Join(pwd, "UGlobalHotkey")
if out, err := iCmd.CombinedOutput(); err != nil {
println("failed to run moc for", target)
println(string(out))
os.Exit(1)
}
println("ran moc for", target)
files, err := ioutil.ReadDir(filepath.Join(pwd, "patch"))
if err != nil {
println("failed to read patch dir", err.Error())
os.Exit(1)
}
for _, file := range files {
exec.Command("cp", filepath.Join(pwd, "patch", file.Name()), filepath.Join(pwd, "UGlobalHotkey", file.Name())).Run()
}
println("copied patch files into UGlobalHotkey for", target)
exec.Command("qtmoc", target, filepath.Join(pwd, "UGlobalHotkey")).Run()
exec.Command("go", "install", filepath.Join(pwd, "UGlobalHotkey")).Run()
}
}

View file

@ -0,0 +1,56 @@
#include "ugh.h"
#include "_cgo_export.h"
#include <QString>
#include <QWidget>
#include "uglobalhotkeys.h"
class MyUGlobalHotkeys: public UGlobalHotkeys
{
public:
MyUGlobalHotkeys(QWidget *parent) : UGlobalHotkeys(parent) {};
void Signal_Activated(unsigned long id) { callbackUGlobalHotkeys_Activated(this, id); };
};
void* UGlobalHotkeys_NewUGlobalHotkeys(void* parent)
{
return new MyUGlobalHotkeys(static_cast<QWidget*>(parent));
}
void UGlobalHotkeys_RegisterHotkey(void* ptr, struct UGlobalHotkeys_PackedString keySeq, unsigned long id)
{
static_cast<UGlobalHotkeys*>(ptr)->registerHotkey(QString::fromUtf8(keySeq.data, keySeq.len), id);
}
void UGlobalHotkeys_UnregisterHotkey(void* ptr, unsigned long id)
{
static_cast<UGlobalHotkeys*>(ptr)->unregisterHotkey(id);
}
void UGlobalHotkeys_UnregisterAllHotkeys(void* ptr)
{
static_cast<UGlobalHotkeys*>(ptr)->unregisterAllHotkeys();
}
void UGlobalHotkeys_DestroyUGlobalHotkeys(void* ptr)
{
static_cast<UGlobalHotkeys*>(ptr)->~UGlobalHotkeys();
}
void UGlobalHotkeys_ConnectActivated(void* ptr)
{
QObject::connect(static_cast<UGlobalHotkeys*>(ptr), &UGlobalHotkeys::activated, static_cast<MyUGlobalHotkeys*>(ptr), &MyUGlobalHotkeys::Signal_Activated);
}
void UGlobalHotkeys_DisconnectActivated(void* ptr)
{
QObject::disconnect(static_cast<UGlobalHotkeys*>(ptr), &UGlobalHotkeys::activated, static_cast<MyUGlobalHotkeys*>(ptr), &MyUGlobalHotkeys::Signal_Activated);
}
void UGlobalHotkeys_Activated(void* ptr, unsigned long id)
{
static_cast<UGlobalHotkeys*>(ptr)->activated(id);
}

View file

@ -0,0 +1,132 @@
package UGlobalHotkey
//#include "ugh.h"
//#include <stdlib.h>
import "C"
import (
"runtime"
"unsafe"
"github.com/therecipe/qt"
"github.com/therecipe/qt/core"
"github.com/therecipe/qt/widgets"
)
type UGlobalHotkeys struct {
QWidget widgets.QWidget
}
type UGlobalHotkeys_ITF interface {
widgets.QWidget_ITF
UGlobalHotkeys_PTR() *UGlobalHotkeys
}
func (ptr *UGlobalHotkeys) UGlobalHotkeys_PTR() *UGlobalHotkeys {
return ptr
}
func (ptr *UGlobalHotkeys) Pointer() unsafe.Pointer {
if ptr != nil {
return ptr.QWidget.QWidget_PTR().Pointer()
}
return nil
}
func (ptr *UGlobalHotkeys) SetPointer(p unsafe.Pointer) {
if ptr != nil {
ptr.QWidget.QWidget_PTR().SetPointer(p)
}
}
func PointerFromUGlobalHotkeys(ptr UGlobalHotkeys_ITF) unsafe.Pointer {
if ptr != nil {
return ptr.UGlobalHotkeys_PTR().Pointer()
}
return nil
}
func NewUGlobalHotkeysFromPointer(ptr unsafe.Pointer) (n *UGlobalHotkeys) {
n = new(UGlobalHotkeys)
n.SetPointer(ptr)
return
}
func NewUGlobalHotkeys(parent widgets.QWidget_ITF) *UGlobalHotkeys {
tmpValue := NewUGlobalHotkeysFromPointer(C.UGlobalHotkeys_NewUGlobalHotkeys(widgets.PointerFromQWidget(parent)))
if !qt.ExistsSignal(tmpValue.Pointer(), "destroyed") {
tmpValue.QWidget.ConnectDestroyed(func(*core.QObject) { tmpValue.SetPointer(nil) })
}
return tmpValue
}
func (ptr *UGlobalHotkeys) RegisterHotkey(keySeq string, id uint) {
if ptr.Pointer() != nil {
var keySeqC *C.char
if keySeq != "" {
keySeqC = C.CString(keySeq)
defer C.free(unsafe.Pointer(keySeqC))
}
C.UGlobalHotkeys_RegisterHotkey(ptr.Pointer(), C.struct_UGlobalHotkeys_PackedString{data: keySeqC, len: C.longlong(len(keySeq))}, C.ulong(uint32(id)))
}
}
func (ptr *UGlobalHotkeys) UnregisterHotkey(id uint) {
if ptr.Pointer() != nil {
C.UGlobalHotkeys_UnregisterHotkey(ptr.Pointer(), C.ulong(uint32(id)))
}
}
func (ptr *UGlobalHotkeys) UnregisterAllHotkeys() {
if ptr.Pointer() != nil {
C.UGlobalHotkeys_UnregisterAllHotkeys(ptr.Pointer())
}
}
func (ptr *UGlobalHotkeys) DestroyUGlobalHotkeys() {
if ptr.Pointer() != nil {
C.UGlobalHotkeys_DestroyUGlobalHotkeys(ptr.Pointer())
ptr.SetPointer(nil)
runtime.SetFinalizer(ptr, nil)
}
}
//export callbackUGlobalHotkeys_Activated
func callbackUGlobalHotkeys_Activated(ptr unsafe.Pointer, id C.ulong) {
if signal := qt.GetSignal(ptr, "activated"); signal != nil {
(*(*func(uint))(signal))(uint(uint32(id)))
}
}
func (ptr *UGlobalHotkeys) ConnectActivated(f func(id uint)) {
if ptr.Pointer() != nil {
if !qt.ExistsSignal(ptr.Pointer(), "activated") {
C.UGlobalHotkeys_ConnectActivated(ptr.Pointer())
}
if signal := qt.LendSignal(ptr.Pointer(), "activated"); signal != nil {
f := func(id uint) {
(*(*func(uint))(signal))(id)
f(id)
}
qt.ConnectSignal(ptr.Pointer(), "activated", unsafe.Pointer(&f))
} else {
qt.ConnectSignal(ptr.Pointer(), "activated", unsafe.Pointer(&f))
}
}
}
func (ptr *UGlobalHotkeys) DisconnectActivated() {
if ptr.Pointer() != nil {
C.UGlobalHotkeys_DisconnectActivated(ptr.Pointer())
qt.DisconnectSignal(ptr.Pointer(), "activated")
}
}
func (ptr *UGlobalHotkeys) Activated(id uint) {
if ptr.Pointer() != nil {
C.UGlobalHotkeys_Activated(ptr.Pointer(), C.ulong(uint32(id)))
}
}

View file

@ -0,0 +1,25 @@
#pragma once
#ifndef GO_UGH_H
#define GO_UGH_H
#ifdef __cplusplus
extern "C" {
#endif
struct UGlobalHotkeys_PackedString { char* data; long long len; };
void* UGlobalHotkeys_NewUGlobalHotkeys(void* parent);
void UGlobalHotkeys_RegisterHotkey(void* ptr, struct UGlobalHotkeys_PackedString keySeq, unsigned long id);
void UGlobalHotkeys_UnregisterHotkey(void* ptr, unsigned long id);
void UGlobalHotkeys_UnregisterAllHotkeys(void* ptr);
void UGlobalHotkeys_DestroyUGlobalHotkeys(void* ptr);
void UGlobalHotkeys_ConnectActivated(void* ptr);
void UGlobalHotkeys_DisconnectActivated(void* ptr);
void UGlobalHotkeys_Activated(void* ptr, unsigned long id);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,19 @@
package UGlobalHotkey
/*
#cgo CXXFLAGS: -DUGLOBALHOTKEY_LIBRARY
#cgo linux CXXFLAGS: -I/opt/Qt/5.13.0/gcc_64/include/QtGui/5.13.0/QtGui
#cgo linux LDFLAGS: -lxcb -lxcb-keysyms
#cgo darwin LDFLAGS: -framework Carbon
#cgo windows,!msvc LDFLAGS: -luser32
#cgo windows,msvc MSLDFLAGS: user32.lib
#cgo windows,msvc MSCXXFLAGS: -DUGLOBALHOTKEY_LIBRARY
*/
import "C"
import "github.com/therecipe/qt/widgets"
type stub struct{ widgets.QWidget }

View file

@ -13,9 +13,9 @@ var (
BYTES_PER_ELEMENT := 4 //Float32Array.BYTES_PER_ELEMENT
data := []float32{1, 0, 0, 0, 1, 0, 0, 0, 1}
alloc := qt.WASM.Call("_malloc", len(data)*BYTES_PER_ELEMENT, "float")
alloc := qt.Module.Call("_malloc", len(data)*BYTES_PER_ELEMENT, "float")
for i, v := range data {
qt.WASM.Call("setValue", alloc.Int()+(i*BYTES_PER_ELEMENT), v, "float")
qt.Module.Call("setValue", alloc.Int()+(i*BYTES_PER_ELEMENT), v, "float")
}
return unsafe.Pointer(uintptr(alloc.Int()))
}()
@ -24,9 +24,9 @@ var (
BYTES_PER_ELEMENT := 4 //Float32Array.BYTES_PER_ELEMENT
data := []float32{0, 0.707, -0.5, -0.5, 0.5, -0.5}
alloc := qt.WASM.Call("_malloc", len(data)*BYTES_PER_ELEMENT, "float")
alloc := qt.Module.Call("_malloc", len(data)*BYTES_PER_ELEMENT, "float")
for i, v := range data {
qt.WASM.Call("setValue", alloc.Int()+(i*BYTES_PER_ELEMENT), v, "float")
qt.Module.Call("setValue", alloc.Int()+(i*BYTES_PER_ELEMENT), v, "float")
}
return unsafe.Pointer(uintptr(alloc.Int()))
}()

View file

@ -254,6 +254,8 @@ func ToolPath(tool, target string) string {
//TODO:
case "rp1", "rpi2", "rpi3":
return filepath.Join(QT_DIR(), QT_VERSION_MAJOR(), target, "bin", tool)
case "wasm", "js":
return filepath.Join(QT_DIR(), QT_VERSION_MAJOR(), "wasm_32", "bin", tool)
}
return ""
}
@ -284,6 +286,27 @@ func CGO_LDFLAGS_ALLOW() string {
return ".*"
}
func CGO_MSCFLAGS_ALLOW() string {
if allowed, ok := os.LookupEnv("CGO_MSCFLAGS_ALLOW"); ok {
return allowed
}
return ".*"
}
func CGO_MSCXXFLAGS_ALLOW() string {
if allowed, ok := os.LookupEnv("CGO_MSCXXFLAGS_ALLOW"); ok {
return allowed
}
return ".*"
}
func CGO_MSLDFLAGS_ALLOW() string {
if allowed, ok := os.LookupEnv("CGO_MSLDFLAGS_ALLOW"); ok {
return allowed
}
return ".*"
}
func GOARCH() string {
if arch, ok := os.LookupEnv("GOARCH"); ok {
return arch
@ -410,6 +433,12 @@ var (
)
func GOVERSION() (r string) {
if v, ok := os.LookupEnv("GOVERSION"); ok {
return v
}
if QT_MSVC() {
return "go1.10"
}
goVersionCacheMutex.Lock()
if goVersionCache == "" {
goVersionCache = strings.Split(RunCmd(exec.Command("go", "version"), "get go version"), " ")[2]

View file

@ -71,6 +71,12 @@ func windowsSystemDrive() string {
}
func MINGWDIR() string {
if QT_MSVC() {
if GOARCH() == "386" {
return "msvc2017_32"
}
return "msvc2017_64"
}
if QT_VERSION_NUM() >= 5122 {
if GOARCH() == "386" {
return "mingw73_32"
@ -87,3 +93,18 @@ func MINGWTOOLSDIR() string {
}
return "mingw730_64"
}
func QT_MSVC() bool {
return os.Getenv("QT_MSVC") == "true"
}
func GOVSVARSPATH() string {
if p, ok := os.LookupEnv("GOVSVARSPATH"); ok {
return p
}
bits := "64"
if GOARCH() == "386" {
bits = "32"
}
return fmt.Sprintf(`%v\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars%v.bat`, windowsSystemDrive(), bits)
}

View file

@ -25,5 +25,3 @@ func MakeWrapper(i interface{}) *js.Object {
}
//
var WASM = Module //TODO: remove

View file

@ -8,8 +8,8 @@ import (
)
func init() {
WASM.Set("_callbackReleaseTypedArray", js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
(*js.TypedArray)(unsafe.Pointer(uintptr(args[0].Int()))).Release()
Module.Set("_callbackReleaseTypedArray", js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
ReleaseTypedArray(unsafe.Pointer(uintptr(args[0].Int())))
return nil
}))
}
@ -18,7 +18,3 @@ var Global = js.Global()
var Module = Global.Call("eval", "Module")
//TODO: func MakeWrapper(i interface{}) *js.Value
//
var WASM = Module //TODO: remove

13
qt_wasm_112.go Normal file
View file

@ -0,0 +1,13 @@
// +build js,wasm
// +build go1.12,!go1.13,!go1.14
package qt
import (
"syscall/js"
"unsafe"
)
func TypedArrayOf(src []byte) js.TypedArray { return js.TypedArrayOf(src) }
func ReleaseTypedArray(p unsafe.Pointer) { (*js.TypedArray)(p).Release() }

17
qt_wasm_113.go Normal file
View file

@ -0,0 +1,17 @@
// +build js,wasm
// +build go1.13
package qt
import (
"syscall/js"
"unsafe"
)
func TypedArrayOf(src []byte) js.Value {
dst := Global.Get("Uint8Array").New(len(src))
js.CopyBytesToJS(dst, src)
return dst
}
func ReleaseTypedArray(unsafe.Pointer) {}