Day Three

Ian Harris

2025-01-03

Busy

I didn’t really have the chance to work on much or write today. I wanted to finish my Raylib bindings from yesterday, but I’ll have to put that up tomorrow.

For now, since it’s 11pm, I’ll just share an overview of what I did.

Overview

The basic setup goes like this:

That’s pretty much it. It’s pretty simple, and not very rigid, but Raylib doesn’t change that often, and it’s not a very big library anyway. Making small adjustments as needed is pretty easy.

Doxygen

This isn’t the best way to do this. The only reason I picked Doxygen is because I’m familiar with it. It is not the correct tool for the job. Don’t do this.

Anyway, how you do it is just run doxygen -g, enable XML generation, and run doxygen. Then you get a nice raylib_8h.xml which has most of the definitions you’ll need. Struct definitions are in other files, but you don’t actually need them, since Zig and Zigler both make this nice anyway. I ended up parsing almost everything, like defines, typedefs, etc.

xmerl

Once you have that, you need to parse the XML with xmerl into some kind of shape. This is pretty straightforward. I used xmerl_xpath by itself, which is a little awkward. Using SweetXML would’ve been a bit nicer, I think, but I’ve been trying to get more familiar with existing tools in OTP.

There’s not much else that went into this. A bit finicky, since I don’t think xmerl is actually spec compliant, but I could’ve just been doing things wrong.

Translate

Next it’s just translating the C to Zig. For the most part, the translation ends up just being this:

pub const some_fn = raylib.SomeFn;

Which is really nice.

For “problem” types, it’s a little more involved. I still haven’t settled on how I want to handle it, since the way I’m doing it with Raylib is not very general. The basic behavior I have now is to just define a list of problem types, like const char *, and if I see one of them in the parameters or return type, I translate all the types to their Zig equivalent.

This is mostly fine. It’s a bit awkward, but fine. The only problem I ran into was when I realized I needed to handle non-const pointers in a correct way. There’s no easy way to identify these by just their type, since there are legitimate reasons to take a non-const pointer without modifying it.

For this, I opted for needing to manually define which functions have an “inout” type. For these, the functions need to be defined more like this:

// given void UpdateCamera(Camera *camera, int mode);
pub fn update_camera(camera: *raylib.Camera, mode: c_int) *raylib.Camera {
  raylib.UpdateCamera(camera, mode);
  return camera;
}

This isn’t too bad, and it pretty much wraps up all the caveats.

Next up

The first thing I want to do is use something other than Doxygen and xmerl. It’s a bit too fragile, and unpleasant to work with. Not the fastest either, if there are a lot of files involved.

Then I want to publish this as something you can use in a project easily.

Finally, there are some interesting things to consider in terms of how to interact with Raylib from Elixir.