I love that the author provides docker images for cross compilation. Cross compilation environments are such a pain to setup and maintain - having docker images with all that stuff in is a major step forward.
Next time I want to build a desktop app I'll have a go with this for definite.
author here;
Using Docker saved me from creating the code to cross compile from windows->linux, darwin->linux/windows, ...
And this alone was worth it, but being able to ship something that works out of the box is nice a nice bonus :)
edit: I'm also planning to create macOS and iOS target images.
Docker will only let you cross-compile to OSes with the same kernel, which is relatively limited. A full set of say vagrant files would be slower, but a lot more polyvalent (but even then it would not let you, say, compile a windows binary from linux).
You can cross-compile to completely different environments. It just can be tricky to set up, so prepared docker images with e.g. the toolchain to build a Windows executable on Linux are great to have, and what is provided here.
I think it's a nice idea in theory to provide cross-compilation support by means of emulating all possible target architectures on the compiling machine.
Then I remember that I'd be managing a custom heterogenous compute cluster just to compile some code.
It's not emulation, it's cross-compilation which has existed basically forever. You don't have to target the same instruction set as the one you're compiling on.
Go doesn't really use libc all that much. Syscalls are also implemented in pure go + as, so there aren't really header files to provide. That makes for a great cross-compilation story.
Not only a joy, it would be the best way we currently have to make desktop applications. Currently the easiest alternative is JS+Electron, but that's just horrible because of all the waste of resources. Python is hard to package, so something statically compiled would be great.
I would prefer Rust for this (or, well, I would prefer Python with a better packaging story), but Go is much better than the alternatives too.
While not very modern, Lazarus (http://www.lazarus-ide.org/) is a Delphi-compatible Pascal implementation for cross-platform GUI apps. While I've not coded in it I've used a couple of Lazarus apps, and it seems quite mature and works well.
was thinking this also. The language seems very well suited to GUI applications based on its internals and I would love to see what comes of it in this regard. moar bindings pls
Once I have been building Qt Widgets application in Python with PySide bindings. I needed to do some simple processing in several SLOTs and decided to use lambdas as an easy replacement. Kids, do not even think about attempting to do this at home, seriously.
I have run into some extremely evasive random crashes and stuff. I did not dig to the bottom of the issue, although my guess is that Python lambdas are executed in main (constructing) thread context and that causes race conditions.
My question: how do Golang's goroutines interact with native threads spawned by Qt?
Usually these kinds of errors are due to weird interaction of the python GC and the parent/child lifecycle used internally by QObject (and derived classes).
In this case, you're depending on the Qt side (signal/slot management) to keep your lambda alive along with its entire call stack. But python doesn't know anything about QObject pointers, and will happily GC it. The next time that signal is fired, crash is extremely likely.
This used to be a much bigger problem in PyQt and PySide 4 and earlier, but it appears to have gotten better recently in PyQt at least.
Yeah, I recently found some sample code written with a weird (non-standard) mechanism of moving data between Python and Qt and it had all sorts of problems. For example, they had a Python thread that was running a timer and when Qt shut down, it tried to deliver a Python callback afterwards and things got messed up.
In general, the best way to work with Qt is to let it assume control, and it use its mechanisms for lifecycle-management. I converted the code so that it used a QThread-derived Python class and QTimer. Works great.
You basically have to understand the Deep Magic that makes Python work under the hood, and ditto for Qt, too.
author here;
The main golang thread lives in the same thread as Qt's main event loop.
If you now want to "cross" threads from a goroutines (which may lives in another thread), you can use Qt's signals and slots to safely "cross" threads.
Take a look at the "quick/bridge" examples to see how Go is interacting with QML, and therefore has to "cross" threads several time.
edit: can't comment any further currently, I will try to answer everything once I'm unblocked.
Ugh, sorry about that. New accounts are rate limited to try to cut down on spammers and trolls. It's really bad that this also cuts down on participation by the creator of a project showing up to comment on it, which is one of the best things that can happen here.
We've marked your account legit so it won't happen again. Welcome to HN!
I have some experience building PyQt apps and can confirm random crashes (segfaults, sigaborts and such). I suspect this has nothing to do with lambdas. It may likely be something happening between Python and QT - remember that all things happening in QT/C++ world are invisible to Python. For example if your Python routine returns None (as many Python methods, functions do) instead of some other object that is expected by C++ (say QNetworkRequest) it may crash and die without any traceback. I spend hours on things like this - QT method must return something but in some cases was not returning expected object and whole thing was crashing. Python being Python doesn't care about return types, there is no Python traceback, you're left in the dark groping, browsing codebase trying to find what might get wrong, no debugger will help you.
Working with QT bindings is very difficult. Debuging things is not easy. I'm not sure if using bindings is worth it. I suspect doing things in plain C++ QT might be easier to debug and maintain.
In C++ one gets a compilation error if the wrong type is returned from a function.
Qt is generally type safe, but it uses quite a lot of pointer types and also a rather unusual for C++ parent-child resource cleanup rule for QObjects (e.g. all widgets).
When something does crash, C++ doesn't offer any tracebacks, but if one has a core dump or can reproduce the crash under a debugger, a traceback can be easily obtained in the majority of cases.
> but if one has a core dump or can reproduce the crash under a debugger, a traceback can be easily obtained in the majority of cases.
how do you create core dump? starting program under some debugger? I tried debugging with valgrind but the output contained so much noise it took my ages to find something. I also had to recompile QT used by PyQT because QT because QT requires some flags to be able to debug. What's the best way to debug things like this?
A core dump is a file that's generated by the OS and includes a snapshot of the process state. It's useful when e.g. one is not able to run the program under a debugger.
Enabling it depends on the OS, I would just search for enable core dumps on "my OS".
If one can run the target program under a debugger, a core dump is not so helpful because it's a static snapshot, whereas a debugger can modify program state.
I am guessing that one has to run the python process itself under the debugger and pass the parameters such as the script path.
There will probably be a signal or exception condition at one point and one can take a look at the call stack. The call stack will probably be messy, as it will include python internals.
An alternative way to debug this is to understand the lifetimes and preconditions of C++ widgets and signals and slots and review one's python code.
Unless there's a bug in Qt itself, PyQt and Qt might have a misunderstanding about lifetimes and something gets cleaned up too soon or there's a dangling refrence to a cleaned up object
It should create a coredump on crash by default (either in the current directory or in a OS specific system directory, try /var/cores for example). If it doesn't, try 'ulimit -c unlimited' in your shell to enable coredumps for that session.
Valgrind is not really useful for debugging crashes. Running under gdb would work though.
This is a very interesting question (to which I don't know the answer), I'm curious how the coroutines will interact with the Qt events.
Sidenote: It's also possible to build Qt applications in Python using AsyncIO (using quamash), by integrating the Qt event loop as an AsyncIO event loop. This can be helpful to avoid race conditions, as much more interactions can be handled without thread concurrency.
I've run into this problem too. I think it has more to do with object lifetimes. Suppose you define your lambda in a method of a QWidget that's later destroyed. The underlying C++ object has been cleaned up already, but the signal's reference to the lambda is keeping the Python part of the QWidget alive. Then when the slot is triggered you get weird crashy behavior.
go-qml/qml is just a tiny wrapper around the QML API, which is nothing compared to this. This library covers the whole entire Qt framework (Qt Widgets libraries + QML + everything else).
It for sure is. However QML might also be all you are interested in, since Go already has a very good standard library which covers lots of things. Then the remaining question is which of those Go QML wrappers is of a higher quality and easier to work with.
.NET Core bindings for Qt. .NET Core doesn't have any UI toolkit right now. There are several efforts but they're mostly hobbyist ones and seem to lack funding or major development power, unfortunately.
author here;
Yes, you can create derived classes from any class that is derived from QObject.
Simple anonymously subclass in Go and add your own slots/signals, as shown in the "quick/bridge" and several other examples.
Then run "qtmoc" to generate the need c++ and go code. All functions usually accept interfaces and all classes have their corresponding interface, which itself inherits all the derived interfaces.
author here;
It's needed by `go install` to provide pre-compiled packages, which will then speedup the compilation of your applications down to 10sec.
But you can also use the STUB setting, before running the setup and then use the binding with only 1gb ram as well. (the necessary c++ code will be compiled later with qtdeploy)
edit: can't comment any further currently, I will try to answer everything once I'm unblocked.
Not Qt, but I'm using https://github.com/gtk-rs/ with Rust, which is pretty cool, I've developed the GUI using Glade, which I load via Rust. I'm also using CSS, to style the interface.
Question. Does QT still have a licensing problem for closed-source apps on mobile platforms?
Last I saw, QT's GPL/LGPL license required you to open-source the code that was statically linked to it. That wasn't much of a problem for desktop platforms, as you could just package up all of QT into its own QT.DLL (or the equivalent) and link to it dynamically. But this isn't allowed on stuff like iOS, so you were required to buy a license for those.
Only parts (non-core) of QT are GPL, most are LGPL
And it's a bit of a misconception that LGPL requires statically linked things to be open sourced: in that area it only requires that the LGPL components be replaceable (and the source for the LGPL components be available). In the context of static linking, that can be done by releasing pre-link binaries (object files) with instructions for linking them.
Of course, that's likely more work than just making the source available under a proprietary license (ie: provide source code so LGPL components can be replaced).
If you're using Qt GPL components, then yes, you'll need to open source your application (or pay for a Qt License)
author here;
IANAL but I think for iOS it's still required to either open-source your code under GPL or to buy a commercial license as you said.
But IIRC there is work being done to bring dynamic linking to iOS as well, since apple allowed it with iOS 8 or so.
edit: can't comment any further currently, I will try to answer everything once I'm unblocked.
Qt itself is LGPL now, so it no longer requires you to open-source code linked to it.
Some of the language bindings that aren't maintained by Digia are still GPL, though. An example of this is PyQt, and the PyQt team's intransigence on the GPL is why PySide exists.
It definitely looks like Qt but I am surprised that Qt is not using any native controls on iOS. It tries to use native controls or at least a native look and feel if possible (it does so on Windows and macOS at least). On the other hand, I don't know anything about mobile app development and apis that iOS gives you so I cannot tell whether such a thing is possible in iOS at all.
a) Qt doesn't use native controls on any platforms (though for half of desktop Linuxes Qt is the native toolkit). Qt has its own controls that are styled to look like native.
b) The screenshot shows Qt widgets. This is not the intended way to do Qt on mobile platforms, and thus no native styling is provided. QML is the official way to do mobile apps with Qt.
Point A is interesting because you can see particularly on OSX that it is not native, despite widespread recommendations to use Qt for cross platform development. I have used wxWidgets on multiple platforms and despite its idiosyncrasies, I have found it performed very well and is obviously truly native on all platforms (unless you choose wxUniversal as a rendered; nobody does) or unless you do "owner drawn" stuff and paint yourself. In any case I would not hesitate recommending wxWidgets for native controls over Qt.
Other minor Qt annoyances include their own scrollbars which ignore the system setting of "jump to where I click the thumb" setting etc.
author here;
Because I used the C++ widgets, which are not intended to be used on mobile platforms.
The proper way to develop mobile apps is in QML/Qt Quick, and those would look great.
You can style them any way you want, and there are also material (google) and universal (microsoft) themes that can be easily plugged in.
I've been using this library for a couple of weeks, and so far I have been very impressed. It's relatively easy to use, and seems to be pretty comprehensive in the amount of the Qt API that it supports.
I raised two small issues, and both were addressed quickly by the author. In one case incredibly quickly.
This is awesome. I was really bummed about the state of QT support in golang. I played with the go-qml project, but it wasn;t everything I needed. This looks amazing.
I don't know as what you define free.
But Qt is as far as I know is available under LGPL, GPL and under a commercial license.
Also they co-operate with the KDE project and made sure that it will stay "free" IIRC.
author here;
The size depends on your platform and the way you build it.
If you used `qtdeploy` instead of `go run/build`, you should get a 2mb binary which includes Go's runtime + only the needed Qt C++ code.
(A normal go binary has the size of 1.5mb or so)
The rest are Qt dynamic libs, which are not all needed, depending on what you build. You can safely remove plugins and maybe whole modules. edit: and you can also compile Qt on your own to strip out ICU and other unnecessary stuff + with Qt 5.8 things will get even more lightweight.
First of all, thank you. The effort of maintaining Qt in any way or form is ... nontrivial.
I've wanted to try this one out, but it looks like I'm maybe trying something too far off from mainstream. I like how the bindings can be built against incomplete Qt releases (iow. just the development packages available in debian sid); the build complains when some modules can't be found but continues nonetheless. Sure, it takes QT_DIR and PKG_CONFIG settings to build like this but I have no problem there.
So far I haven't found a way to build even the sample project against this type of custom build though. I'll try to find more time to dive in as to why this happens but I'm sure this is an error on my end. Once I figure that out, I should be able to provide a documentation update.
As to why? I have an old project which I need to revive, and being stuck in ancient GTK land with dubious bindings and even more dubious upstream practices sounds less appealing than porting things over.
Did you tried to use QT_MISC_DIR (which should contains the "mkspecs" subfolder) and QT_DOC_DIR, which should contain for example (QtCore/qtcore.index)?
Or if you like, open an issue on github and we can try to sort this out :) edit: also if you use PKG_CONFIG=true, the QT_DIR will be ignored
Hum, I hadn't, but in retrospect I should have. I've done my share of Qt builds in the past and mkspecs path was often an amusing detail. Didn't solve the problem though.
But I think I found out at least one thing that goes wrong. I'll provide a github issue report later this weekend but here's the short version:
* The generated #cgo directives for CXXFLAGS are different for desktop and minimal files. Minimal is generated with -I$(QT_INCLUDE_DIR)/QtFoo include paths; desktop is generated with -I$(QT_DIR)/<major.minor>/gcc_64/include/QtFoo paths instead. So headers in desktop build are looked up from library directory paths (and with obviously bad path elements too).
* When building, qtsetup goes for desktop target.
More data coming in via github once I get the exact details sorted out.
hehe, thx for the quick reply. Had some trouble with qtdeploy and since go build worked (and I prefer go build workflow wise) I assumed it would result in the same binary.
The demo application works without any of the libs from the deploy folder, but thats probably because it uses the system libs.
So cool:
- Option 1: 'go build' creates one large 50mb binary
- Option 2: 'qtdeploy' creates a bundle with a little more than whats required but you can remove what you dont need
- Option 3: just takes the binary and let the system provide the libs
Super cool would be, if that downsizing could be made automatically but since that icu stuff takes alone 24mb, that might be difficult. Anyway, great work. Spend half a day to get it working with system libs, but in the end I had to learn to just follow the tutorial and download qt again.
I should probably mention that Option 1 is still depending on all the system/dynamic libs.
And therefore only usefull to save time during development or if you need more control about the build. If you want to get a smaller binary, run `qtminimal` and `go build/run -tags=minimal` to include only the necessary C++ code, but the binary will still depend on the dynamic/system libs.
I will add full statically linking in the future, but probably only after Qt 5.8 is released.
I think you answered your own question, if it is statically linked to qt then it is statically linked to all/most of it no? I don't think qt or any gui library is divided in many small pieces like javascript libs.
Flat can be fine with shadows (though if it has shadows is it flat?) and other hints but yes I think the desktop UI in particular reached it's peak with Win2k, everything since has been different but not better.
No, it's Qt Quick vs. QWidget. QWidget was created in the pre-mobile days, and while still very useful to make high-quality work horse desktop apps, the mobile platforms are much better served by Qt Quick in terms of theming, animation and touch support.
This fragmentation is frustrating sometimes, but in the end what counts is whether the framework has solutions to your problems, and it usually does. (Meanwhile, Qt Quick is improving on the desktop over time.)
This is why on an application I have done back in the 5.3 days, I decided to throw Qt away and rewrite it using standard C++ for the logic, with Java and C++/CX for the UI.
I was much more productive and I had much better integration with the respective OS APIs.
QML isn't crap. Its much nicer, IMHO, than HTML and CSS and much more intuitive. The animation and states system makes it trivial to make polished looking UI's.
Granted, I wish I didn't have to use JS with it, but QML itself is fantastic.
You can use them from C++, but its definitely not the expected usage and not particularly easy.
I personally much prefer QtQuick to QtWidgets, and really like the QML declarative language as a better HTML/CSS for non-web. But I completely agree with you that I would prefer if I could code all my logic in C++ and not JS.
I've been meaning to play around with two ideas:
1. Construct the QtQick widget scenegraph wholly from C++ (and not using QML/JS at all). Doable, but definitely not intended usecase.
2. Construct the scenegraph using QML, but using it only for setting values (and never any logic) and then manually connecting the signals from the QML-created widgets to C++ slots.
It is not wise to even implement a lot of logic in the JS part of QML, as the JS interpreter there is quite a bit more primitive than something like V8. Your performance will suffer if you attempt to write anything too complicated in JS inside QML.
Oh I know, I've had some complex QML/JS in the past.
Even more so if you're running on iOS where the JS isn't jitted.
It's really easy to write QObjects that are accessible to QML and you can connect your signals/slots with the QML widget ones, so having the logic in C++ isn't hard. It's just not quite as convenient as putting it inline in QML, I guess.
Careful what you wish for. XAML had the whole "no code because we want designers to use it" thing going on and the result was a bazillion of converters with a SNR of <<1.
IIRC Qt Widgets are stylable as well. I guess default distribution does not provide styles for iOS, so it defaults to the Win95 look.
To me Qt Widgets is the most elegant UI API out there.
author here;
Yes, those look awful.
But only because it's build with Qt's C++ widgets (intended for desktop development) and not with the recommended Qt Quick Controls.
I will update the screenshots to something that is build with QML.
So, dang, why is my account rate limited then? I’ve had 2 cases before where a project I participated in was presented here, and I showed up to comment, and couldn’t do so due to the rate limiting.
This is not really helpful, and destroys any chance at meaningful discussion.
(Also, last time you told me that rate limiting couldn’t be undone, and I should just write an email – what’s that about now?)
There are other reasons for rate-limiting besides an account being new—if an account has posted a lot of unsubstantive or uncivil comments, for example. I doubt that I told you it couldn't be undone, because it can be undone. What I probably said was that you should email us because it isn't a good idea to go on about it here.
Next time I want to build a desktop app I'll have a go with this for definite.