Also, the Julia package curators are not a fan of the C.jl package name, so package functionality will probably be merged into CBinding.jl
And for historical reasons, the name of Clang.jl is also to some extent misleading. Clang.jl should only host a thin wrapper over libclang or even Clang, but I guess it’s too late to make the change.
Hah! “Thin” is a subjective term, so no worries!
For someone who might be interested in the interop between Julia and C, here are some recent PRs/Issues related to the topic:
-
@ccall
macro for varargs: https://github.com/JuliaLang/julia/pull/32748 -
forward decl: https://github.com/JuliaLang/julia/pull/32658
Off-topic, but I’ve been waiting for #32658 to finally be merged for ages. It’s really slightly embarrassing that Julia still has no simple, straightforward way to declare mutually recursive types.
The raylib bindings using CBinding.jl v1.0:
module libraylib
using CBinding
let
CMAKE_INSTALL_PREFIX = "$(dirname(@__DIR__))/deps/usr"
c`-I$(CMAKE_INSTALL_PREFIX)/include -L$(CMAKE_INSTALL_PREFIX)/lib -lraylib`
end
const c"va_list" = Cvoid
c"""
#include <raylib.h>
#include <physac.h>
#include <raymath.h>
#include <rlgl.h>
"""ji
end
You can add ‘w’ to the string macro options to wrap the inline functions as well, but that is more experimental functionality.
That’s also quite lean! But if I understand the documentation correctly the generated bindings have to be used via the c"" string macro, right?
With the ‘j’ string macro option applied, Julian names are also created. So in this example you can directly use libraylib.Transform
for instance.
As you mention, bindings are always generated in the c"..."
symbol “namespace” to avoid name collisions (that approach is 100% foolproof). They are optionally mapped into the Julian symbol “namespace” if the user determines no name collisions will occur and requests that functionality.
@mhinsch I’m also interested in an Raylib binding. If you have something working would you mind uploading it to GitHub?
Unfortunately more urgent (as in I’m actually getting paid to do them) things got in the way and will do so for a while. I still intend to get back to the raylib wrapper, but it might be a couple of months before I have the time to do so.
Do you have any unfinished code you could upload?
I might want to take part in the Game Makers Toolkit game jam next month and if i don’t have to start from scratch that might motivate me to get something runable by then.
Not really anything beyond a basic proof of concept. I basically used Gnumic’s example:
wrap.toml
[general]
library_name = ":libraylib"
output_file_path = "./LibRaylib.jl"
module_name = "LibRaylib"
use_julia_native_enum_type = true
wrap.jl
using Clang.Generators
cd(@__DIR__)
const RAYLIB_H = ["/usr/local/include/raylib.h"]
options = load_options(joinpath(@__DIR__, "wrap.toml"))
args = String[]
ctx = create_context(RAYLIB_H, args, options)
build!(ctx)
Running wrap.jl
produces LibRayLib.jl
which is 99% fine, but needs a tiny bit of editing to account for issues with vararg functions and some macros (no idea if that has been fixed in the meantime). Then code like this works:
run_rl.jl
include("LibRaylib.jl")
const RL = LibRaylib
const screen_width = 1600
const screen_height = 900
function run()
RL.InitWindow(screen_width, screen_height, "run")
camera = RL.Camera2D(RL.Vector2(500, 500),
RL.Vector2(screen_width/2, screen_height/2),
0.0,
1.0)
x = floor(Int, rand() * 1000) + 200
y = floor(Int, rand() * 700) + 100
while RL.WindowShouldClose() == 0
RL.BeginDrawing()
RL.BeginMode2D(camera)
RL.ClearBackground(RL.Color(0, 0, 0, 255))
x += floor(Int, (rand()-0.49)*10)
y += floor(Int, (rand()-0.49)*10)
RL.DrawText("Dies ist ein Test!", 200, 200, 20, RL.Color(250, 0, 0, 255))
RL.DrawCircle(x, y, 100, RL.Color(0, 255, 0, 150))
RL.EndMode2D()
RL.EndDrawing()
end
RL.CloseWindow()
end
run()
Hi, thank you for the thorough examples of using clang. However, I have an issue running the same code as the above.
The LibRaylib.jl
is created successfully, but while running the run_rl.jl
, I got this error ERROR: could not load library "libraylib"
.
Any tips to solve this issue?
It seems like you are trying to use a wrapper for a library, but without the library. Are you sure that libraylib
is installed on your system?
Hi @serenity4, thank you for responding.
I have installed the raylib (following through this guide Working on GNU Linux · raysan5/raylib Wiki · GitHub), it still gave me the same error.
git clone https://github.com/raysan5/raylib.git raylib
cd raylib
mkdir build && cd build
cmake -DBUILD_SHARED_LIBS=ON ..
make
sudo make install
I am not sure why it doesn’t detect the installation. I am a new Linux user, so maybe I didn’t install it correctly.
You should then make sure that the libraries you built are discoverable within the library search path of your system. You can look into LD_LIBRARY_PATH
for example.
Since Raylib
is in Yggdrasil (see here), an even better solution would be to use the Julia package Raylib_jll
. As long as the library name of the JLL package matches the library name you use in your wrapper, the issue might be solved by just doing import Raylib_jll
(at package __init__()
time, Raylib_jll
will dlopen
the shared library and therefore the library will be callable by name directly, i.e. no need to mess with system paths).
Thanks, @serenity4!
I will figure out how to continue with this one. However, I tried with a different approach using the JLL package.
using Clang.Generators
using Raylib_jll
cd(@__DIR__)
include_dir = normpath(Raylib_jll.artifact_dir, "include")
# wrapper generator options
options = load_options(joinpath(@__DIR__, "wrap.toml"))
# add compiler flags, e.g. "-DXXXXXXXXX"
args = get_default_args()
push!(args, "-I$include_dir")
header_dir = include_dir
headers = [joinpath(header_dir, header) for header in readdir(header_dir) if endswith(header, ".h")]
# create context
ctx = create_context(headers, args, options)
# run generator
build!(ctx)
[general]
library_name = "libraylib"
output_file_path = "./LibRayLib.jl"
module_name = "LibRaylib"
jll_pkg_name = "Raylib_jll"
However, I got this error message
[ Info: Processing header: /home/vscode/.julia/artifacts/43bf856bd341c937a4ef62a0db273d61985df75e/include/rlgl.h
ERROR: AssertionError: duplicated definitions should be exactly the same!
Stacktrace:
[1] (::IndexDefinition)(dag::ExprDAG, options::Dict{String, Any})
@ Clang.Generators ~/.julia/packages/Clang/i9s1u/src/generator/passes.jl:127
[2] build!(ctx::Context, stage::Clang.Generators.BuildStage)
@ Clang.Generators ~/.julia/packages/Clang/i9s1u/src/generator/context.jl:169
[3] build!(ctx::Context)
@ Clang.Generators ~/.julia/packages/Clang/i9s1u/src/generator/context.jl:160
[4] top-level scope
@ /workspaces/Docker/Julia/Raylib/jll/wrap.jl:22
Do you have any idea why this is happening?
If you want to use raylib with Julia, someone already made a Julia wrapper for it:
chengchingwen/Raylib.jl: Julia wrapper for the raylib videogames programming library (github.com)
It works pretty well. See this example:
NanoVG.jl/raylib.jl at main · dylanxyz/NanoVG.jl (github.com)
Hi @dylanxyz, thank you for the response
What I am trying to do here is to learn about using Clang.jl as a wrapper. Because I stumbled upon a problem when I was trying to make a wrapper for cuQuantum. There is already JLL for this: GitHub - JuliaBinaryWrappers/cuQuantum_jll.jl. But I think something is missing, which makes an error.
So, technically it should be easier for me to build it. But, as I am still new to Julia and cuQuantum, I want to see more examples of how Clang.jl can be used.
If you have any information that someone is already made the wrapper for this project, it would be awesome