Writing C-compatible DLLs in Odin

Hello Odin people.

I am new to Odin, and it is the first low-level language I’ve spent any real time with (never touched C/C++, few hours with Rust).

I am trying to build a C-compatible DLL so that I can use it in C/C++/via FFI.

Using C libraries in Odin seems to be a much hotter topic than the inverse, so I’ve struggled to find much online. I’m left with a couple of questions.

Parameter Defaults

If I write a procedure and wish to export it as part of a DLL usable in C/C++/via FFI, must I avoid using optional parameters with default values?

I assume they should not be used because of C’s lack of function overloading. I don’t know enough about either Odin or C to be confident in that assumption, though.

If they can be used, I’ve no idea what the resulting function signature(s) would look like.

I failed to consider this for my current project, which is fortunately tiny, and ended up using param defaults for many procedures. A re-write will be simple enough, but I’d like to know I’m not shooting myself in the foot by avoiding param defaults in this context.

Header File Generation

In my few hours using Rust, I did more or less the same thing I’m now trying to achieve with Odin. I found cbindgen, and it was very helpful for producing header files.

I’ve figured out enough to write my own header file for this little project, but I can see it being a potential headache for projects of size.

Is there a way to produce header files when building a library? If not, do any tools like cbindgen exist for Odin?


I have been able to successfully call one of my procedures from a C program, and any insight into the above would help me sort out the rest without being plagued by neurotic quantities of doubt.

If anyone could point me in the right direction, be it an explanation or a link to relevant resources, it would be greatly appreciated.

Thanks!

1 Like

spall provides a C header file, perhaps you can look at how they did it. Seems to be handmade.

1 Like

Parameter Defaults
This is a callie thing. It doesn’t effect the FFI afaik.

Header File Generation
For Odin ↔ C there’s Runic. It’s strictly deals with the C ABI, so it’ll fit your propose.
For C → Odin there’s also odin-c-bindgen.
Though I’ve not used them, so I can’t vouch for it.

There’s just no tools for Odin → Odin (for now),

1 Like

Welcome to Odin! For C/C++ FFI, it’s best to avoid optional parameters, use explicit ones instead. Odin doesn’t have a tool like cbindgen, so writing headers manually is common. You’re on the right track!

1 Like

spall provides a C header file, perhaps you can look at how they did it. Seems to be handmade.

I took a look at the repo and I’d say you’re right about it appearing handmade. Good to have to hand as a quality example, though.

This is a callie thing. It doesn’t effect the FFI afaik.

I wasn’t too sure what this meant so I ended up just giving it a go to see what would happen, for the sake of clarity.

I wrote a tiny test program in Odin - just a single exported proc with an optional cstring parameter that prints:

@(export, link_name="op_test")
op_test :: proc "c" (text: cstring = "default") {
    context = runtime.default_context()
    fmt.printfln("text value: %s", text)
}

I built it as a library, wrote a header file, and then a test C program:

// include/optional.h
...
void op_test(const char* text); // Also tested without the param
...

// main.c
#include "include/optional.h"

int main(int argc, char *argv[])
{
    op_test("something");
    return 0;
}

If I used void op_test(const char* text); in the header file:

  • Calling it and passing a string would print “text value: {the value}”
  • The above is true even if the string was empty
  • Calling it without passing a string was invalid and wouldn’t compile
  • No matter what value I passed, it would never print “default”

If I used void op_test(); in the header file:

  • Calling it and passing a string would print “text value: {the value}”
  • Calling it without passing a string was now valid enough to compile, but resulted in nothing being printed
  • Again, in no case did “default” appear

I’m not familiar enough with either Odin or C to make heads/tails of that - I’m sure it makes sense, some how. All in all, not much of value was learnt.

For my original project that caused me to make this thread, I just did the sensible thing: avoided optional parameters - as I’ll continue to - and manually wrote my headers.

I did try runic for generating headers, but I couldn’t get the dependencies set up properly and figured I was putting more effort into generating headers than writing them would ever require.

Thanks all for the responses, and apologies for not getting back sooner.