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.
- 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 and in the examples.
If you find this generator helpful and want to say thanks, then please consider donating.
Discuss and ask questions on my Discord server.
- Odin
- libclang version 16 or higher
- On Windows: Download libclang 20.1.8 from here: https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.8/clang+llvm-20.1.8-x86_64-pc-windows-msvc.tar.xz -- Copy the following from that archive:
lib/libclang.libinto the generator's 'libclang' folderbin/libclang.dllinto the root of the generator (next to where the bindgen executable will end up).
- On Linux/mac, please install libclang. For example using
apt install libclang-devon Ubuntu/Debian/Mint. Anything from clang version 16 and new should work.
- On Windows: Download libclang 20.1.8 from here: https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.8/clang+llvm-20.1.8-x86_64-pc-windows-msvc.tar.xz -- Copy the following from that archive:
Note
libclang is used for analysing the C headers and deciding what Odin code to output.
- Build the generator:
odin build src -out:bindgen.exe(replace.exewith.binon mac/Linux) - Make a folder. Inside it, put the C headers (
.hfiles) of the library you want to generate bindings for. - Execute
bindgen the_folder - Bindings can be found inside
the_folder/the_folder - To get more control of how the generation happens, use a
bindgen.sjsonfile to. See how in the next section, or look in theexamplesfolder.
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 for more advanced examples.
NOTE: Config uses the function/type names as found in header files.
// Inputs can be folders or files. If you provide a folder name, then the generator will look for
// header (.h) files inside it. The bindings will be based on those headers. For each header,
// you can create a `header_footer.odin` file with some additional code to append to the finished
// bindings. If the header is called `raylib.h` then the footer would be `raylib_footer.odin`.
inputs = [
"input"
]
// Output folder. In there you'll find 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 macro names
remove_macro_prefix = ""
// Remove this prefix from function names (and add it as link_prefix) to the foreign group
remove_function_prefix = ""
// Remove this suffix from type names (such as '_t' etc)
remove_type_suffix = ""
// Set to true translate type names to Ada_Case
force_ada_case_types = false
// Single lib file to import. Will be ignored if `imports_file` is set.
import_lib = "my_lib.lib"
// The filename of a file that contains the foreign import declarations. In it you can do
// platform-specific library imports etc. The contents of it will be placed near the top of the
// file.
imports_file = ""
// `package something` to put at top of each generated Odin binding file.
package_name = "my_lib"
// "Old_Name" = "New_Name"
rename = {
}
// Turns an enum into a bit_set. Converts the values of the enum into appropriate values for a
// bit_set (translates the enum values using a log2 procedure).
//
// Note that the enum will be turned into a bit_set type. There will be a new type created that
// contains the actual enum, which the bit_set then references.
bit_setify = {
// "Enum_To_Turn_Into_Bitset" = "New_Enum_Type_Name"
}
// Completely override the definition of a type.
type_overrides = {
// "Vector2" = "[2]f32"
}
// Override the type of a struct field.
//
// You can also use `[^]` to augment an already existing type.
struct_field_overrides = {
// "Some_Type.some_field" = "My_Type"
// "Some_Other_Type.field" = "[^]"
// "Some_Other_Type.another_file" = "[^]cstring"
}
// Put these tags on the specified struct field
struct_field_tags = {
// "BoneInfo.name" = "fmt:\"s,0\""
}
// Remove a specific enum member. Write the C name of the member. You can also use wildcards
// such as *_Count
remove_enum_members = [
// "MAGICAL_ENUM_ALL"
// "_*Count"
]
// Enums automatically have any prefix that is sharred by all members removed. This sometimes
// misbehaves for certain names. Use this setting to manually set the perfix to remove for a
// certain enum type.
remove_enum_member_prefix = {
// "enum type name" = "enum member prefix to strip"
// "PixelFormat" = "PIXEL_FORMAT_"
}
// 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.
//
// You can also use `[^]`, `#by_ptr` and `#any_int` to augment an already existing type.
procedure_type_overrides = {
// "SetConfigFlags.flags" = "ConfigFlags"
// "GetKeyPressed" = "KeyboardKey"
}
// Add in a default value to a procedure parameter. Use `Proc_Name.parameter_name` as key and
// write the plain-text Odin value as value.
//
// You can also add defaults for proc parameters within structs. In that case you do:
// `Struct_Name.proc_field.parameter_name` -- This does not currently support nested structs.
procedure_parameter_defaults = {
// "DrawTexturePro.tint" = "RED"
// "Some_Struct.a_field_that_is_a_proc.some_parameter" = "5"
}
// Put the names of declarations in here to remove them.
remove = [
// "Some_Declaration_Name"
]
// Group all procedures at the end of the file.
procedures_at_end = false
// 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"
]
// Pass these compiler defines into clang. Can be used to control clang pre-processor
clang_defines = {
// "UFBX_REAL_IS_FLOAT" = "1"
}
Please look through the list of configuration options listed above and see if they help you. Also, see the the examples folder for additional inspiration.
If you fail to make any progress on generating bindings for a certain library, 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.
If the source header is called raylib.h then add a a file called raylib_footer.odin next to it
and put your code in there.
Use imports_file in bindgen.sjson. See examples/raylib
In bindgen.sjson:
bit_setify = {
"Enum_To_Turn_Into_Bitset" = "New_Enum_Type_Name"
}
This will replace the type Enum_To_Turn_Into_Bitset (an enum) with a bit_set. The type will look like this:
This will create a type Enum_To_Turn_Into_Bitset :: bit_set[New_Enum_Type_Name; i32].
The members that Enum_To_Turn_Into_Bitset had when it was an enum will be moved into a new enum called New_Enum_Type_Name. Within that enum the members will have their values converted using a log2 procedure. The log2 procedure turns for example 2 into 1 and 4 into 2. The bit_set itself will use these numbers to target a specific bit within its backing type.
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_paths = [
"include"
]
Big thanks to Xandaron for figuring out a lot of the libclang stuff.
This generator was inspired by floooh's Sokol bindgen: https://github.com/floooh/sokol/tree/master/bindgen