# On the making of Raylib bindings

**URL:** <https://forum.ada-lang.io/t/on-the-making-of-raylib-bindings/4399>\
**Category:** General\
**Created:** [May 7, 2026, 5:40pm UTC](https://forum.ada-lang.io/t/on-the-making-of-raylib-bindings/4399 "2026-05-07T17:40:49Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![ZenitDS](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/zenitds/32/949_2.png) [@ZenitDS](https://forum.ada-lang.io/u/ZenitDS)\
**Post date:** [May 7, 2026, 5:40pm UTC](https://forum.ada-lang.io/t/on-the-making-of-raylib-bindings/4399/1 "2026-05-07T17:40:49Z")

</div>

Hi there,

I am working on some bindings for raylib 6.0. I know there exist already some bindings, but these looked a bit abandoned so I decided to kickstart my own and hopefully get them to a usable state in the near future.

I am using some generative AI (gemini) to generate the bulk. Some functions however have/will need manual intervention.

I have some questions which hopefully if answered will allow me to complete these bindings. Here I go:

## 1

I am taking the approach of having in one side the plain c bindings (raylib\_c.ads) and then the “thick” bindings in (raylib.ads, raylib.adb). I expose some “thick” types that then get converted into the C counterparts in the bindings.

> The structures are simple when taking this approach, so that the conversion is fast. For more complex cases I intend to have other approaches as show in my following questions.

Should I consider other strategies?

## 2

What is the cleanest way to bind a function that takes a pointer (and usually a count) to several elements corresponding to a C type? This is because it would be rather nicer to have the binding take an Ada array of Ada types ( **note that the type inside the array is not of the C type** ) and then pass it somehow to the C function.

e.g. in the following, have `Check_Collision_Point_Poly` take an array of `Vector2` for `Points`

```ada
-- be advised that this may not compile
   function Check_Collision_Point_Poly (Point : Vector2; Points : System.Address; Point_Count : Integer) return Boolean is
   begin
      return To_Ada (Raylib_C.CheckCollisionPointPoly (To_C (Point), Points, To_C (Point_Count)));
   end Check_Collision_Point_Poly;

```

## 3

How can I make the build system configurable for different platforms (basically `linux`, `openbsd` and other UNIX-like OSes for the time being) and adding options such as an additional linking location or the location of libraylib.a for example.

* * *

I share here the project which has the `Unlicense` license. If someome wants to collaborate on finishing this, he/she is happily welcome. I am also new to Ada, so more senior advice is really appreciated.

> **[raylib-ada](https://codeberg.org/ZenitDS/raylib-ada)**
>
> Raylib bindings for the Ada programming language

Cheers  
–zen

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [May 7, 2026, 6:13pm UTC](https://forum.ada-lang.io/t/on-the-making-of-raylib-bindings/4399/2 "2026-05-07T18:13:17Z")

</div>

> [@ZenitDS](#):
>
> am taking the approach of having in one side the plain c bindings (raylib\_c.ads) and then the “thick” bindings in (raylib.ads, raylib.adb). I expose some “thick” types that then get converted into the C counterparts in the bindings.

Yes, that is the way. In thick bindings you replace char \* to String, procedure to functions returning objects, wrap resources into controlled types, replace int results with exceptions.

> [@ZenitDS](#):
>
> This is because it would be rather nicer to have the binding take an Ada array of Ada types ( **note that the type inside the array is not of the C type** ) and then pass it somehow to the C function.

You wrap the C vector type into an opaque Ada type with operations to access elements.

> [@ZenitDS](#):
>
> How can I make the build system configurable for different platforms (basically `linux`, `openbsd` and other UNIX-like OSes for the time being) and adding options such as an additional linking location or the location of libraylib.a for example.

Add _Target\_OS_ scenario to the gpr file. Select linker options according to the scenario.

You can also make gpr file for an external library. For that you use `for Externally_Built use "true";`Then you simply **with** it in your project. Here is a complicated case of the ODBC library which has different names under different systems:

```ada
project ODBC is

   type ODBC_Driver_Type is ("ODBC32", "unixODBC", "auto");
   ODBC_Driver : ODBC_Driver_Type := external ("odbc", "auto");
   
   type OS_Type is
        ( "Windows", "Windows_NT",
           "Linux",
           "UNIX",
           "OSX",
           "FreeBSD",
           "auto"
        );
   Target_OS : OS_Type := external ("Target_OS", "auto");
 
   Target_Triplet := Project'Target;

   case Target_OS is
      when "auto" =>
         case Target_Triplet is
            when "aarch64-linux-gnu" |
                 "arm-linux" |
                 "arm-linux-gnueabi" |
                 "arm-linux-gnueabihf" |
                 "x86_64-linux" |
                 "x86_64-linux-gnu" |
                 "x86_64-redhat-linux" |
                 "x86_64-suse-linux" |
                 "x86-linux" |
                 "x86-suse-linux" |
                 "i686-linux-gnu" |
                 "i686-redhat-linux" |
                 "i686-suse-linux" =>
               Target_OS := "Linux";
            when "x86_64-apple-darwin" |
                 "x86_64-darwin" |
                 "x86-darwin" =>
               Target_OS := "OSX";
            when "x86_64-freebsd" |
                 "i686-freebsd" =>
               Target_OS := "FreeBSD";
            when "x86_64-pc-cygwin" |
                 "x86_64-w64-mingw32" |
                 "x86_64-windows" |
                 "x86-windows" |
                 "i686-pc-cygwin" |
                 "i686-pc-mingw32" |
                 "i686-w64-mingw32" =>
               Target_OS := "Windows";
            when "" =>
               for Source_Files use
                   ( "target is undefined, "
                   & "scenario auto cannot be used"
                   );
            when others =>
               for Source_Files use
                   ( "target "
                   & Target_Triplet
                   & " is unknown, scenario auto cannot be used"
                   );
         end case;
      when others =>
         null;
   end case;

   case ODBC_Driver is
      when "auto" =>
         case Target_OS is
            when "Linux" | "OSX" | "FreeBSD" | "UNIX" =>
               ODBC_Driver := "unixODBC";
            when "Windows" | "Windows_NT" =>
               ODBC_Driver := "ODBC32";
            when "auto" =>
               for Source_Files use
                   ( "target is undefined, "
                   & "scenario auto cannot be used"
                   );
         end case;
      when others =>
         null;
   end case;
 
   case ODBC_Driver is
      when "unixODBC" | "auto" =>
         for Externally_Built use "true";
         for Source_Files use ();
         for Library_Dir use ".";
         for Library_Name use "odbc";
         for Library_Kind use "dynamic";
      when "ODBC32" =>
         for Externally_Built use "true";
         for Source_Files use ();
         for Library_Dir use ".";
         for Library_Name use "odbc32";
         for Library_Kind use "dynamic";
   end case;
end ODBC;

```

It tries to figure out the target OS (which `gprbuild` should rather provide out of the box, but for misterious reasons does not).

---

<div class="post-metadata">

**Author:** ![ZenitDS](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/zenitds/32/949_2.png) [@ZenitDS](https://forum.ada-lang.io/u/ZenitDS)\
**Post date:** [May 7, 2026, 10:25pm UTC](https://forum.ada-lang.io/t/on-the-making-of-raylib-bindings/4399/3 "2026-05-07T22:25:47Z")

</div>

Thanks for the response 🤗

> [@dmitry-kazakov](#):
>
> You wrap the C vector type into an opaque Ada type with operations to access elements.

I am concerned that it may be big overhead doing the whole transformation if the arrays are large. Is there some reasonable approach so that copying each time can be avoided?

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [May 8, 2026, 7:41am UTC](https://forum.ada-lang.io/t/on-the-making-of-raylib-bindings/4399/4 "2026-05-08T07:41:04Z")

</div>

That is why you wrap it in an Ada type. There is no copying:

```ada
   type Vector is tagged private;
   ... opeations
private
   type Vector is new Ada.Finalization.Controlled with record
      Ptr : C_Vector_Ptr;
   end record;

```

---

<div class="post-metadata">

**Author:** ![Fabien.C](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/fabien.c/32/46_2.png) [@Fabien.C](https://forum.ada-lang.io/u/Fabien.C)\
**Post date:** [May 11, 2026, 2:38pm UTC](https://forum.ada-lang.io/t/on-the-making-of-raylib-bindings/4399/5 "2026-05-11T14:38:58Z")

</div>

FYI, I have updated my low-level bindings to Raylib 6.0 see [Raylib 6.0 bindings - #5 by Fabien.C](https://forum.ada-lang.io/t/raylib-6-0-bindings/4411/5)

---

<div class="post-metadata">

**Author:** ![ZenitDS](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/zenitds/32/949_2.png) [@ZenitDS](https://forum.ada-lang.io/u/ZenitDS)\
**Post date:** [May 11, 2026, 5:18pm UTC](https://forum.ada-lang.io/t/on-the-making-of-raylib-bindings/4399/6 "2026-05-11T17:18:09Z")

</div>

That is nice! My objective with the new bindings is to have some more abstraction using the Ada typing capabilities (similar to sdlada), so I think I will continue on the journey.

Cheers  
– zen
