Suitability of Haxe for a cross-platform library (exporting a C API)?

(I’m asking this here because looking at the docs, googling and searching the forum has not yet answered this for me - apologies if I’m overlooking something obvious)

I’m trying to build a cross-platform library with a C API meant to be consumed from as many other languages as possible. I’m looking into Haxe for this because the language looks very comfortable and powerful compared to the alternatives I’ve looked at already - combined with the possibility of wide portability via the C++ backend.

  1. First of all, is this even possible? Can a public C API be declared in Haxe, that will be available after C++ compilation? I know it’s possible to consume native libraries with Haxe, but I’m looking at the inverse situation - consuming Haxe via C. I need to be able to (for example) declare C-consumable callbacks in Haxe, allocate and share structs with the outside world, etc - all the usual behavior of a native C library.

And assuming the above is possible:

  1. It’s not absolutely required, but it would be a major plus if I could even target older GCC compilers with the generated code - I’m hoping to get my code running on some legacy/exotic platforms like OS/2, Classic MacOS (9.2), and MorphOS/Amiga. (I believe all those have at least C++11 cross compilers available). But Win/Mac/Linux are the only hard requirements.

  2. How often does the average, non-power-user run into compiler bugs? I previously started my work with another language that I had high hopes for, but so far I’ve hit two compiler bugs that have slowed down my progress and reduced my confidence in going forward. Now if I were more in love with that language I would be more determined to stick with it, but it lacks the high-level/functional goodness of Haxe and in retrospect was probably just too low level for what I’m trying to accomplish - so I’m eagerly looking around for something more pleasurable to use, and (if I’m lucky) more portable to exotic platforms.

cheers and thanks!

Would this be Haxe only, or also other lib/framework dependency?

The Haxe code would be written around an existing native library. So:

Outer C API → Haxe code → internal C library dependency

Is that what you mean? No other dependencies / Haxe libraries would be used.

Yeah, that’s what I meant. For instance, if this were a UI heavy thing that needed OpenFL, then what you’re looking to do would be quite hard. But I image what you’re looking to do should be totally possible. Me and another guy are building something that wraps a Haxe/OpenFL project into a dll and, along with other dlls, is used as a .Net control. If we managed that, I think it bodes well for what you’re trying.
Perhaps some of our solutions overlap with your needs. Like how we shaped callbacks. Mind you, this is Haxe/Cpp.

That is encouraging! Are there any documents / examples / repos that demonstrate the basic procedure? Certain conventions or attributes/metadata required to yield C-friendly API functions?

I looked through the docs and all I saw was the inverse of what I’m attempting to do - how to consume native libraries, but not how to produce them.

I’m not really aware of any docs or samples for this kind of thing. Took us a Lot of trial and error to get something working. So, I’m happy to share a bit of info on how we did things like callbacks for Cpp, but I’m at a loss going down to just C. Not my area. Frankly, neither is Cpp, but maybe I’ve learned something useful to you.

Well, that sounds like a start, so yeah, I’d be interested in seeing example code if you have anything publicly visible. Maybe somebody will yet chime in with a more direct way of doing what I’m looking for, but what you’ve done so far might shine a light on just how much manual wrapping I’m in for. Fortunately what I have in mind will have a small surface area, just a handful of API methods visible to the outside world.

Are you on Haxe Discord? It would be easier to share some code that way. You can add me and PM me. I don’t currently have anything public, but don’t mind at all sharing the core bits to lend a hand. If it ends up helping you along, then you can come back to this post and follow up for others’ sake.

Not yet, but I’ll drop by tomorrow and say hello. Thanks for your offer to help!

Hi Daniel,

Not sure if this will be of any help, but I know that HashLink (Haxe’s very own VM) can compile to C via its “HL/C” mode. One of the docs linked to is an in-depth blog post that contains some info about the generated C code.

Thanks John, I will have a look!

Hey @nobody123, this is exactly how I’ve been using haxe and hxcpp for about a year now

We use haxe to write the bulk of our application, distribute as a binary library then expose a C-API to embed it on other platforms (like iOS or Android)

With hxcpp you can generate a C++ API using the @:nativeGen meta (see this example: hxcpp/test/extern-lib at master · HaxeFoundation/hxcpp · GitHub). To expose as a C-API we write a wrapper manually because the surface area is small enough, but there’s no reason you couldn’t write a macro to do this automatically

If you’re writing a complex or multi-threaded application like a game, you’ll need to make sure you consider the hxcpp gc when you call into haxe or handle haxe objects in C. Some details here: hxcpp/ThreadsAndStacks.md at master · HaxeFoundation/hxcpp · GitHub

Positive points about this approach:

  • Integrating with native C libraries is quick and easy, this is the main reason I like hxcpp: I can @:include() some a native header, call it directly from haxe and look at the generated C++ to debug issues. Example, OpenGL: gluon/GLContext.hx at master · haxiomic/gluon · GitHub
  • haxe + hxcpp has been used in a decent number of well-selling production games (many millions of users each), so there’s empirical reliability
  • Generated C++ is pretty sane and so easy to debug (it can be hard to read with the debug macros, but you can disable those with things like -D no-debug and @:noStack)

Some downsides:

  • While someone else has probably trodden the same path, there’s not much well-organised written documentation. So your main source of information is reading example code and hxcpp source code
  • The @:nativeGen could be more fleshed out, you’ll generally want to use it as it’s used in the examples
  • I do run into bugs, especially when I work with bleeding edge versions, although serious haxe compiler bugs are rare. GC issues concern me the most, one day I’d like to make the slower boehm gc available again in hxpp (Unity uses this one) so this reliability concern is reduced

For me being able to write the majority of my application in a high-level (but high-perf) language like haxe is worth the effort but right now there is a significant overhead required to learn how to properly work with hxcpp and external native code (not that is hard in itself, but it is hard to get at the right information)

Let me know if you’re still interested in this approach let me know and I’ll share resources that I have

What kind of application are you building?

3 Likes

@haxiomic thanks for the reply! just FYI I’ll respond in a few days - presently overwhelmed with a non-Haxe project :sweat:

1 Like