electro-smith / libDaisy

Hardware Library for the Daisy Audio Platform
https://www.electro-smith.com/daisy
MIT License
312 stars 131 forks source link

C Bindings #569

Open scolsen opened 1 year ago

scolsen commented 1 year ago

A good portion of libDaisy is currently only defined as CPP classes and bindings. Providing bindings in plain C would not only allow users to leverage libDaisy in plain C, it would also burst open the door for adding bindings to other programming languages, many of which have foreign function interfaces that anticipate C linkage/ABI. For example, if C bindings were provided one could use libDaisy from zig.

I'm going to write such bindings for myself regardless, simply because I much prefer C to CPP and I may explore using other languages as well. Before I do that as a separate project, I figured I'd file an issue here in case it's something others want too and is worth upstreaming into the library. In theory it will only require adding a few extern "C" calls to the CPP sources.

stephenhensley commented 1 year ago

Hm! I just saw zig for the first time the other day.

I'd be curious to see what the footprint looks like once you get started! 😄

chaosprint commented 1 year ago

I would second this.

scolsen commented 1 year ago

I'll set aside some time this week to start exploring this. I poked around a bit yesterday, and in most cases we'll likely need to add static factories for constructing and destructing class instances; other than that, all the C definitions can just take an additional instance parameter and wrap calls to the underlying methods.

scolsen commented 1 year ago

Ok, https://github.com/electro-smith/libDaisy/pull/580 has a small proof-of-concept of how we might do this, starting with the Analog Control API. I've confirmed it at least builds, but we'll likely want to add unit tests for the C bindings.

The general process is as follows:

  1. Define an opaque pointer that represents instances of the class in C.
  2. Define a create method that wraps invocation of the constructor, static_casting it to a void pointer, then C casting the void pointer to the opaque C type.
  3. Define a destroy method that wraps the invocation of the destructor by casting back to the CPP type.
  4. Wrap any other class methods.
znmeb commented 1 year ago

+1 for C bindings! But I'm not buying the zig hype just yet. The effort-to-payoff ratio for learning a new syntax and semantics when there are a dozen major Turing-complete multi-paradigm languages, three of which I know well, is probably too high. :-)

scolsen commented 1 year ago

+1 for C bindings! But I'm not buying the zig hype just yet. The effort-to-payoff ratio for learning a new syntax and semantics when there are a dozen major Turing-complete multi-paradigm languages, three of which I know well, is probably too high. :-)

totally, no plans to add explicit zig support, at least not from me. I just mentioned it as one example of a language that could leverage a C FFI. This effort is just limited to providing some C bindings.