The Crystal Programming Language Forum

Can shards include linked C functions?

Hello There,

First time posting here. I saw a youtube video last night and over the last few hours have grown somewhat fond of Crystal and I’m trying to build a shard for ui automation (automating mouse clicks, keyboard inputs, etc.). As far as I can tell, the only way to do this is by linking and calling C functions. Probably a noob question, but does Crystal support C code being included in shards and if so, how?

Edit: I’ve already figured out how to link C code, I’m just not sure how that works with the shard system.

Welcome to the community! =)

Code in a shard is like any other Crystal code. You can just declare C bindings and then you can use them in Crystal code. Calling functions in C bindings works essentially the same as methods defined in Crystal. For example, you can define the bindings in one shard and use them in another.

Maybe you could take a look at some existing shards providing C bindings to see some practical examples.

I suppose the only challenge of a shard with bindings to an external library is that the shard is not self-contained. In order to use it, you need not just the shard itself but also the library. And that get’s kind of complicated because there’s no standard way to do that across different platforms.

The best you can do is to properly document the dependencies and how to get them, so that users of the shard know what they have to do.

Thank you for your response, that seems to make some sense. Is the way I’ve done it here bad? I apologize for the noob questions, I’m not exactly the best C programmer either, just cobbled this together from the X11/Xlib.h docs last night.

I suppose you mean GitHub - hrichharms/crystal-autogui: GUI Automation Functionality for Crystal by linking with X11 C bindings. ?

Well, I don’t really understand why you actually write C code. You can just implement those custom C functions in Crystal directly and don’t hassle with C.
You just have to define the bindings for libx11 instead of the bindings for your custom libraries.

I wasn’t aware that it was possible to do so. Again, I’m a noob here so that’s probably why, but I was under the impression that since there are multiple lines of c code at work for any given function, that it was necessary to link some c object files themselves. Are there any tutorials on how I might do this without such difficulties. When I was looking into it it seemed that there wasn’t a way to do it like that.

Oh yeah, you can absolutely do that! You can think of lib declarations as the .h file ported to Crystal. It’s fantastic! For example:

lib LibX11
  alias Int = LibC::Int # Lets you use C's `int` type

  struct Display
    # define struct members with Crystal type signatures ...
    foo : Int
    bar : String # (`char*` gets automatically promoted to a String, but you can also use Char*)
  end

  # `Display* XOpenDisplay(int value)` aliased as `open_display`
  fun open_display = XOpenDisplay(value : Int) : Display*
end

module X11
  class Display
    @display : Pointer(LibX11::Display) = LibX11.open_display(0)

    def finalize
      # Let GC free your pointers
      LibX11.however_you_free_pointers_with_this_lib(@display)
    end
  end
end

So whenever you call X11::Display.new it will automatically call the XOpenDisplay(0) function in C for you and mop it up when the object gets garbage-collected with the finalize hook method so you don’t have to manage your own memory — finalize is basically your best friend when interacting with C libraries.

Ok this for the most part makes sense although I’m still unclear as to the purpose of the foo and bar members of the Display struct are. Are those supposed to be replaced with members of the Display struct in the X11 library?

Exactly. I don’t know what the struct members actually are, so I just defined some bogus ones. :grinning_face_with_smiling_eyes: