An open API service indexing awesome lists of open source software.

https://github.com/karl-zylinski/odin-c-bindgen

Generate Odin bindings for C libraries
https://github.com/karl-zylinski/odin-c-bindgen

binding-generator odin odin-lang odinlang

Last synced: 8 months ago
JSON representation

Generate Odin bindings for C libraries

Awesome Lists containing this project

README

          

# odin-c-bindgen: Generate Odin bindings for C libraries

This generator makes it possible to quickly generate C library bindings for the Odin Programming Language.

Features:
- Easy to get started with. Can generate bindings from a folder of headers.
- Generates nice-looking bindings that retain comments. Example: [Generated Raylib bindings](https://github.com/karl-zylinski/odin-c-bindgen/blob/main/examples/raylib/raylib/raylib.odin).
- Simplicity. The generator is simple enough that you can modify it, should the need arise.
- Configurable. Easy to override types and turn enums into bit_sets, etc. More info [below](#configuration) and [in the examples](https://github.com/karl-zylinski/odin-c-bindgen/blob/main/examples/raylib/bindgen.sjson).

## Requirements
- Odin
- clang (download from https://llvm.org/ or using the clang payload in Visual Studio installer)

> [!NOTE]
> clang is used for analysing the C headers and outputting an AST. The binding generator then processses that AST into Odin code.

## Getting started

1. Build the generator: `odin build src -out:bindgen.exe` (replace `.exe` with `.bin` on mac/Linux)
2. Make a folder. Inside it, put the C headers (`.h` files) of the library you want to generate bindings for.
3. Execute `bindgen the_folder`
4. Bindings can be found inside `the_folder/the_folder`
5. To get more control of how the generation happens, use a `bindgen.sjson` file to. See how in the next section, or look in the `examples` folder.

> [!WARNING]
> The generator assumes that the `clang` executable is in your PATH, i.e. that it is accessible system-wide.

## Configuration

Add a `bindgen.sjson` to your bindings folder. I.e. inside the folder you feed into `bindgen`. Below is an example. See the [examples folder](https://github.com/karl-zylinski/odin-c-bindgen/tree/main/examples) for more advanced examples.

bindgen.sjson template

```
// Inputs can be folders or files. It will look for header (.h) files inside
// any folder. The bindings will be based on those headers. Also, any .lib,
// .odin, .dll etc will be copied to the output folder.
inputs = [
"input"
]

// Files to ignore when processing files in the inputs folders
ignore_inputs = [
// "file.h"
]

// Output folder: One .odin file per processed header
output_folder = "my_lib"

// Remove this prefix from types names (structs, enums, etc)
remove_type_prefix = ""

// Remove this prefix from function names (and add it as link_prefix) to the foreign group
remove_function_prefix = ""

// Only include things that has this prefix
required_prefix = ""

// Single lib file to import
import_lib = "my_lib.lib" // For example: "some_lib.lib"

// Code file that contain libray import code and whatever else extra you need.
// Overrides lib_file. Is pasted near top of the final bindings.
imports_file = ""

// For package line at top of output files
package_name = "my_lib"

// "Old_Name" = "New_Name",
rename_types = {
}

// Turns an enum into a bit_set. Converts the values of the enum into
// appropriate values for a bit_set. Creates a bit_set type that uses the enum.
// Properly removes enum values with value 0. Translates the enum values using
// a log2 procedure.
bit_setify = {
// "Pre_Existing_Enum_Type" = "New_Bit_Set_Type"
}

// Completely override the definition of a type. The type needs to be pre-existing.
type_overrides = {
// "Vector2" = "[2]f32"
}

// Override the type of a struct field. Note that a plain `[^]` can be used to
// modify the existing type.
struct_field_overrides = {
// "Some_Type.some_field" = "My_Type"
}

// Overrides the type of a procedure parameter or return value. For a parameter
// use the key Proc_Name.parameter_name. For a return value use the key Proc_Name.
// Note that a plain `[^]` and `#by_ptr` can be used to modify the existing type.
procedure_type_overrides = {
// "SetConfigFlags.flags" = "ConfigFlags"
// "GetKeyPressed" = "KeyboardKey"
}

// Inject a new type before another type. Use `rename_types` to just rename
// a pre-existing type.
inject_before = {
// "Some_Type" = "New_Type :: distinct int"
}

// For typedefs that don't resolve to anything: Put them in here to create
// empty structs with that name.
opaque_types = [
// "Some_Type"
]

// additional include paths to send into clang. While generating the bindings
// clang will look into this path in search for included headers.
clang_include_paths = [
// "include"
]

// Writes the clang JSON ast dump for debug inspection (in output folder)
debug_dump_json_ast = false
```

## FAQ and common problems

### Why didn't my bindings generate correctly?

If your bindings don't work because of a missing C type, then chances are I've forgotten to add support for it. Try adding it to `c_type_mapping` inside `bindgen.odin` and recompile the generator.

If you have some library that is hard to generate bindings for, then submit an issue on this GitHub page and provide the headers in a zip. I'll try to help if I can find some time.

The generator won't bring along any `#define`'s or inline functions.

### How do I include a pre-made Odin file?

Add it to the input folder.

### How do I manually specify which libraries to load on different platforms etc?

Use `imports_file` in `bindgen.sjson`. See `examples/raylib`

### How can I turn an enum into a bit_set?

In `bindgen.sjson`:

```
bit_setify = {
"your_enum" = "the_bit_set_type"
}
```

This will create a type `the_bit_set_type :: bit_set[your_enum; c.int`.

It will also translate the values of the enum by calculating their log2 value (that gives you the bit index instead of the integer value corresponding to that bit).

### My headers can't find other headers in the same folder

If the generator is processing `include/some_folder/header.h` and it can't find some other header `include/some_folder/something.h`, then add `include` to the include search path by adding he following to `bindgen.sjson`:

```
clang_include_path = "include"
```

## Acknowledgements

This generator was inspired by floooh's Sokol bindgen: https://github.com/floooh/sokol/tree/master/bindgen