[ANN] initial release of ppx_cstubs

It is my pleasure to announce the first release of ppx_cstubs!

ppx_cstubs is ppx-based preprocessor for quick and dirty stub generation with ctypes. It creates two files from a single OCaml file: a file with c stub code and a ml file with all additional boilerplate code.

The preprocessor abuses external declarations that are not used in regular code. Instead of OCaml types, values of type Ctypes.typ are used inside the declarations:

/* function prototypes */
int puts(const char *s);
char *getenv(const char *name);

To access the functions above from OCaml, you simply repeat the prototype in OCaml syntax and with appropriate Ctypes.typ values:

external puts: string -> int = "puts"
external getenv: string -> string_opt = "getenv"

let () = (* regular code *)
  match getenv "HOME" with
  | None -> ()
  | Some s ->
    let i = puts s in
    ...

As a slight extension of the scheme above, you can also label your parameters, annotate external (%c) and write a few lines of C code:

external%c flush_printf : str:string -> i64:int64_t -> bool = {|
  int r = printf("first param:%s; second param:%" PRId64 "\n", $str, $i64);
  if ( r < 0 ) {
    return false;
  }
  r = fflush(stdout);
  return (r == 0); /* `return` is mandatory, unless your function is void */
|} [@@ release_runtime_lock] 
/* other possible attributes are [@@ noalloc] and [@@ return_errno] */

let () =
  let r : bool = flush_printf ~str:"Hello World" ~i64:4L in
  ...

This way several switches between the OCaml runtime and C are avoided. This has various advantages:

  • Intermediate results can be stored on the C stack. They don’t need to be allocated on the heap and wrapped in a way to appease the OCaml runtime.

  • the c compiler can better optimise your code.

  • constant parameters don’t need to exposed to OCaml, just to pass them to the C function.

  • you often have to write (and generate) less code, if you don’t create wrappers for every c function and type, but just wrap snippets of C code.

Further possibilities, examples, and limitations are described in the project’s README.

14 Likes

This is a really impressive layer over Ctypes! @yallop and I often discussed having some sort of #include syntax over the years, but never got around to implementing it. I really like your syntax approach of intercepting external declarations of Ctypes.typ values…

This seems like a really awesome ppx! Thanks for releasing it on github!

The license for this ppx is GPLv3. As the author of ppx_cstubs you, of course, have the prerogative to release under license of your choice.

But I’m wondering what the implications of this are for code that uses your ppx. Would the code that uses your ppx be subject to GPLv3 also? Here I understand the concept that the ppx is generating code so the situation is more nuanced but I’m not sure what it all amounts to in the end.

Would it even be possible release this project under a more permissive license and sidestep discussions related to the GPL?

1 Like

Impressive PPX, @fdopen. I can see myself using it in the future, to the point of being a bit sad I have prior code which does not use it.

The point is less the generation of code (which GCC, the canonical example of GPLv3 licensed programs, also does) but rather the runtime that is required which requires the GPLv3. Licensing just this part under LGPL with OCaml linking exception would avoid this requirement while retaining the copyleft protection of the overall code of ppx_cstubs.

1 Like

This looks amazing. More surprises looking into the github page to see enums and other C types being easily mapped.

It’s almost like all of the OCaml features introduced in the past decade have been for this. :wink: … ppx, string literals, annotations. I’m surprised at how slick it all works out. Nicely done!

2 Likes

Thanks for your response @Leonidas . I am curious to know what @fdopen may think about this and if he feels that this is an issue he would like to address. As it stands currently the ppx license remains GPLv3.

Again, I fully support the decision of the author to release under license of his/her choice and not feel obliged to offer any reasoning. That said this looks like a really awesome ppx and some clarity would be helpful!

There is a runtime library, that you need to link in your program. It’s up to now very small, but I expect it to grow with future releases. This part has a different license (0BSD).

My understanding (see e.g. https://www.gnu.org/licenses/gpl-faq.html#WhatCaseIsOutputGPL or https://www.gnu.org/licenses/gpl-faq.html#GPLOutput) was that generated code won’t be a “derived work” of ppx_cstubs. It is owned by the owners of the original source files and they are therefore free to choose any license they like (no gpl infection). But apparently it is not that easy. I will look into it …

4 Likes

A minor criticism: your use of un-annotated

external getenv: string -> string_opt = "getenv"

violates the principle that, even for extension users, code that looks like normal OCaml code without extensions/attributes has exactly the usual semantics. I would prefer if users had to use external%c in that case – even if there is no additional C payload.

5 Likes

It sounds very interesting but the phrase “quick and dirty” worries me a bit. Is the sentence to be taken seriously?