COMMUNITY

Shout-out: Qt bindings for multi-target Haxe

Hi, fellow haxers, and a Happy New Haxing year to you all!

Just found this very interesting multi-target Qt bindings library for Haxe:

Seems to be a very ambitious project with an interop solution that serves the frontend application from a go-lang backend (can not say that I undestand very much of that really works). Along with bindings for Haxe, there are Dart, Flutter and Swift bindings aswell, and more seem to be planned.

The Haxe codebase seems to be autogenerated and covers most basic GUI stuff. It uses Haxe 4.2 module level functions, so it’s obviously created by a guy that has some closer insight in Haxe.

Also, the make.sh project file includes a comprehensive Haxe target report, displaying what works and what doesn’t on the ALL different Haxe targets. Interestingly, --interp, jvm, java and cs status is currently “works” or “works-with-warn” while the the others have compile- or runtime errors.

When trying it out (on windows), I get --interp and jvm targets to compile, but they both give runtime error that seems to be caused in the interop message communication bus running at http://127.0.0.1:8000/.
The error message is the following: No connection could be made because the target machine actively refused it. … so I guess it’s related to windows somehow not letting this interop communication through.
(Tried netsh http add iplisten 127.0.0.1:8000 but id doesn’t seem to help.)

Any ideas how to solve this?

Having a multi-target gui solution for Haxe is somewhat of a dream from my perspective, and the mother project https://github.com/therecipe/qt seems to be well maintained spread (8.1k stars, 615 forks). I don’t really have the knowledge to say something about the implications (pros/cons) with this interop approach, but maybe it can be a springboard to Qt development (with quick and easy compilation on --interp for example), later to be converted to fully native Qt applications…?

What do you think?

/ Jonas

the project seems cool.

Why is it trying to communicate to 127.0.0.1:8000 ? Does it expect some server on your local machine? :face_with_raised_eyebrow:

Sometimes the Windows firewall blocks programs (but usually from networks, not localhost… hmm.)

Hi Jeff!

As far as I understand it, it pipes the system calls via http calls to a go backend “interop_server”.
The first line in static public main() kicks off this server

// Main.hx
public static function main():Void {
	final process = initProcess(); // TODO: NewQApplication
	...
}

// TODO: NewQApplication
function initProcess():Process {
	final process = new Process("./interop_server", []); // TODO: supply port or interop com channel info
	Sys.sleep(3.); // TODO: block and check interop availability instead
	return process;
}

After that, all Qt api calls seem to be called to this interop_server as http requests. Here is the complete chain:

// Main.hx main()
...
final quickWidget = NewQQuickWidget(null);

// qt.Quick.hx
function NewQQuickWidget(parent:QWidget_ITF):QQuickWidget {
	Quick.initModule();
	return Internal.callLocalFunction(["", "", "quick.NewQQuickWidget", "", parent]);
}

// qt.Internal.hx
public static function callLocalFunction(l:Array<Any>):Any {
	final msg = haxe.Json.stringify(l);
	final output:Any = haxe.Json.parse(syncCallIntoLocal(msg));
	...
	return convert(output);
}

// qt.Internal.hx
	private static function syncCallIntoLocal(msg:String):String {
		return httpRequest("syncCallIntoLocal", msg);
	}

// qt.Internal.hx
	private static function httpRequest(url:String, msg:String):String {
	trace('request: $url');
	var req = new sys.Http("http://127.0.0.1:8000/" + url);
	req.setPostData(msg);

	var retData:String;
	req.onData = function(data) {
		retData = data;
	}
	req.onError = function(error) {
		trace('httpRequest error: $msg -> $error');
	}
	req.request(true);

	return retData;
}

It seems to boot up a seperate instance of the mother project with sys.io.Process and then pass execution orders through it. One thing I see as potentially an issue is the license being LGPL from the main go repo witch requires dynamic linking, unless the source code is open source it self.

I agree I’ve very much wanted a multi target gui solution for Haxe too, One that has the resources I think needed to support all the edge cases and matience to build fully mature gui applications. I think go is an interesting means to achieve these types of libraries into Haxe and one of the reasons I’ve been working on a transpiler these last couple of months, meaning the library source code of another gui library written in go like fyne (11.7k stars,575 forks) in full Haxe code, except for the places that it links to c/c++ in wich case those bindings could be translated to ammer for instance. This however is a decent ways away.

Overall I think this is a great find and I’d be interested to learn more about the current gui stacks that Haxe has gained acess to or created.

It certainly seems like a novel approach - i dont really get how it all fits together either, but seems like its creating some type of tunnel or something to a Go runtime that “does the stuff”? I wonder how that actually translates to rendering the components etc.

What i dont really understand is why this is better than just using Qt directly from hxcpp? Is the point that then you can use Qt from haxe but compile the haxe to, say, C# or Java? And why is that beneficial? Because you might want to take advantage of some existing .jar or something similar?

From the parent project there is also a JS demo, which seems pretty cool / crazy… ie, by the looks of things a Qt app inside a browser - i wonder how that fits together… is it WASM or something? Certainly never seen that before (although for me after a little while the JS app hangs, but still pretty cool)

So i guess from my perspective the jury is still out, i mean, it seems pretty cool, but im still stuck on “why not just use hxcpp and use qt ‘as is’”, it also feels like there are alot of moving parts here that look to create some type of friction (ie, the windows build not working for OP and the JS version hanging for me, but maybe thats just initial teething issues)

Cheers,
Ian

1 Like

Ian, I don’t think this approach is really “better” in any sense. On the contrary, there must be bottlenecks in the data transformation to/from json as far as I can see. (The developer - still don’t know his/her name - mentions Haxe enum support missing, I guess this is connected to this json conversion.)

What’s cool about - as I see it - is (theoretical) ease of use and full compatibility on any target that can kick off the backend sys process needed. Combined with fast compiletime as Qt libraries live on the “backside” and never have to be compiled/linked in. To be able to prototype an admin tool with Qt Gui run it in --interp would be … very cool! Ideally, when time for release, it would be a flick of a switch to compile natively using HxQt. :slight_smile:

PXshadow, best luck with your Haxe/Go projects! The Go/Fuse combo will be a great addition to the Haxe eco sys when that day has come…! :slight_smile: Thank you also for highlighting the LGPL “issue”.

2 Likes

The fast iteration via interp is an interesting angle, but its worth noting that the “it would be a flick of a switch to compile natively using HxQt” (if im understanding correctly) wouldnt be the case… its not code that would be compatible with Qt (hxQt or code generated by hxcpp in general). ie, in the repo you dont “new” anything in haxe code, you do things like:

final view = NewQGraphicsView(null);

And presumably that tells a backend to perform the object creation so there is no “switch to flip”, you are defo locked into this way of doing things - at least thats my very basic understanding of how this works. I do think, however, you can get this backend to compile and download an actual exe (at least you can on the js example - this also hangs fyi).

All in all, i really dont have clue how this works… And in total honesty, i cant see myself using it anytime soon… it feels really complex compared to Haxe => hxcpp => Qt… But maybe im missing something 8.1k people arent :slight_smile:

Cheers,
Ian

A similar route for Haxe users would be to build a cppia host that has Qt in it and then compile to cppia for iteration and cpp for release. However creating the necessary hxcpp bindings for Qt is probably a considerable amount of work.

1 Like

creating the necessary hxcpp bindings for Qt is probably a considerable amount of work

Im not sure that would be the case, hxQt already has (limited) bindings that seem to work and an experimental haxeui-qt can also use those bindings for qt UI’s - abstracted into haxeui’s framework ofc (image below is just using hxQt, not haxeui as i dont feel its anywhere near ready for consumption yet):

image

The bindings are hand crafted (and as i mentioned, quite limited component wise), and it would obviously be much nicer if they were generated somehow, but i just havent had any real time to get my teeth into this again (though im certainly going to revisit it at some point - hopefully soon).

As for iteration speed, maybe im just too used to c++ build times, but with the hxcpp compiler cache, making changes to the above project and running takes like 1 second… maybe thats slow to some people… dunno, for me thats perfectly acceptable (ive worked on c++ projects that took like 30 mins plus to do a clean build, so maybe im not a great judge of “fast compiles” :smiley: )

Cheers,
Ian

1 Like

Ideally, when time for release, it would be a flick of a switch to compile natively using HxQt.

Yes, Qt->Go backend and Qt->native are of course completely different animals, and that flick-of-a-switch would require another abstraction layer. (Maybe a HaxeUI backend could be possible if Qt->Go will be seen to deliver more than just an interesting poc.)

A similar route for Haxe users would be to build a cppia host that has Qt in it and then compile to cppia for iteration and cpp for release.

Yes, indeed. The cppia target sadly seems to be severly underused, and a simple workflow for quickly setting up Qt GUI apps would be a great showcase to shed the light it deserves on it…

2 Likes

A quick test using cppia and HxQt: I doesn’t work because some of the extern classes (qt.core.Application for example) use native untyped cpp-code: untyped __cpp__('char *argv[] = {NULL};'); etc. (The compiler explicitly notifies this.)

Ammer could theoretically be used with the eval target, but it seems to be a fairly complicated process right now, where Haxe has to be compiled from source using plug in. Hopefully this could be simpler in the future…

Hmm, i open to suggestions / PRs ofc… i think that untyped was just to be quick… im sure there is a real way to do the same… (NativeArray iirc)

Ill check when i have a moment.

Cheers,
Ian

1 Like