Cute Exporter»Blog

Working with Odin on MacOS

Odin is a great programming language. It lives up to at least this part of its mission statement.

joy of programming

I hadn't done any low level programming for a while before I started using Odin. Now I can't get enough.

Odin, while great, does have its rough edges. You can expect that from a newer language with a smaller community. And because the creator [Ginger Bill]( develops on a Windows machine there's a few more rough edges in MacOS vs Windows. I am going to talk about one of the issues I ran into on Mac and how I solved it.

(Look I develop on MacOS. I come from a web background and like the OS and it's ecosystem. Sue me.)

OSX Calling Convention Bug

Related Issue

I am not sure of the root problem, but Odin isn't passing certain structs properly. I think it has to do with the MacOS ABI wanting them passed as a 128 bit vector, but again I'm not sure.

This appears to be a major issue and it is, however we can work around it.
In my code and tool I use Raylib []. Odin's foreign system is awesome, making it super easy to include anything compiled to C code. I link to the raylib .a file and done... In a perfect world. As mentioned, the calling convention is broken for a few structs. But as mentioned, there is a solution. It's a simple solution. We can pass in our structs normally and modify our calls to pass in a pointer parameter for output instead of directly returning.

RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Returns the screen space position for a 2d camera world space position


RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera, Vector2 *out); // Returns the screen space position for a 2d camera world space position

The above method I was doing this a not smart way. I was modifying the entire raylib source to make these changes to the calls. This worked fine. I didn't think much of it as I was building out Cute Exporter. Then it came time to start making sure it worked for Windows. Windows doesn't have these calling convention issues. Do I now need to maintain two different versions of raylib for MacOS and Windows solely to work around Odin? That could work but doesn't seem optimal. Then I realized, Odin has a great foreign system we can do this better.

Instead of modifying raylib directly I made a small wrapper C library around functions that needed to change. I don't even need to do it for every raylib function, only the broken ones.
And in Windows we can import the raylib library code and be done.

In the C wrapper

#include "raylib.h"
Vector2 raylibext_GetScreenToWorld2D(Vector2 vec, Camera2D cam, Vector2 *input, Vector2 *result) {
	Vector2 res = GetScreenToWorld2D(*input, cam);

	*result = res;

	return res;

I can then import my wrapper functions and work with them to have the same Odin calling convention in Windows or MacOS. (Odin also has a great system for OS specific code.)

//The _darwin part means this file only gets included and compiled when on a Darwin (MacOS) system.
when ODIN_OS == "darwin"{
	foreign import raylib_host {
foreign raylib_host {
	_GetScreenToWorld2D :: proc(raylib._Vector2, raylib.Camera2D, ^raylib._Vector2, ^raylib._Vector2) -> raylib._Vector2 ---;

GetScreenToWorld2D :: proc "c" (coord: raylib._Vector2, camera: raylib.Camera2D) -> raylib._Vector2 {
		result : raylib._Vector2;
		input := raylib._Vector2{coord.x, coord.y};
		_GetScreenToWorld2D(input, camera, &input, &result);
		return raylib._Vector2{result.x, result.y};

The advantage of this method being, I don't need to maintain a different branch of my changes to raylib. If a newer version or bug fix come out I don't need to worry about conflicts.

In the end it's nothing too complex or crazy and that is fully owed to how flexible and awesome Odin is.

James Deeman,
Really appreciate this post as I was hoping to dip into Odin on MacOS myself. Might even push me to switch language for Advent of Code 2020. So yeah, thanks. :D