Source

ocaml-cstruct-codegen / README.txt

Full commit
(* OASIS_START *)
(* DO NOT EDIT (digest: 48387c4b705458822196dc29f25d4964) *)
This is the README file for the ocaml-cstruct-codegen distribution.

Library for generating OCaml code to work with C-like structures

See the files INSTALL.txt for building and installation instructions. 


(* OASIS_STOP *)

  There already exists a library called "ocaml-cstruct"
( https://github.com/avsm/ocaml-cstruct ) that serves similar purpose.
However, author of this library didn't want to "dive into Camlp4" to
add new features to ocaml-cstruct, and decided to write his own
implementation instead.


        Here is how they compare:

  Pros:
  - ocaml-cstruct-codegen doesn't use Camlp4, it uses code generation
    (so people who don't want to learn Camlp4 can improve this library)
  - typing: every structure has its own abstract type, so it's impossible
    to use a structure getter/setter on another structure (with different
    layout; so with different type)
  - guarantees of full initialization of structures (when it's needed)
  - can dump structures to human-readable strings

  Cons:
  - ocaml-cstruct is easier to add in a project (compare ocaml-cstruct docs
    with section "How to use" below)
  - ocaml-cstruct uses Camlp4, so it allows one to write cstruct-definitions
    directly in the code
  - ocaml-cstruct-codegen is written in a very direct, one might even say
    cynical, way



        What would this library give you:

  For the structure called "mystruct" with a signle field called "a" 
this library would generates module Mystruct with abstract type t and
values:

  - val sizeof : int -- get size of structure in octets
  - val get_a : t -> <typeof a> -- get field "a"
  - val set_a : t -> <typeof a> -> unit -- set field "a"
  - val a_ofs : int -- offset of field "a" in the structure
  - val of_bigarray : bigarray -> t -- create Mystruct.t on top of bigarray
  - val bigarray_of : t -> bigarray -- get bigarray of Mystruct.t
  - val create : unit -> t -- create uninitialized Mystruct.t
  - val make : a:<typeof a> -> t -- create Mystruct.t passing initial field
    values as labelled arguments (so user has guarentees that all fields are
    initialized)
  - val dump : t -> string -- convert t to human-readable string like "{ a=4 }"

  When field "a" is enum of type "myenum" with carrying type "i"
(int/int32/int64), these values are generated instead of "get_a":
  - val get_a_num : t -> i -- get field value as a number
  - val get_a_exn : t -> Myenum.t -- get field value as Myenum.t, throwing
    exception Enum ("myenum", "badvalue") when field contains value not
    present in "myenum" definition.
  - val get_a_res : t -> [ `Ok of Myenum.t | `Error of i ] -- same as
    [get_a_exn] but returns "badvalue" with [`Error] constructor in numerical
    form.

  This, of course, scales up for multiple fields.



        How to define C-like structures and enums:


  First -- open module:

    open Cstruct_codegen

  Then -- enums:

    let myenum = let open Enum in
      enum "myenum" uint8_t
      [ elt "A"
      ; elt "B" ~v:3
      ; elt "C"
      ]

  "myenum" gives name to generated module with this enumerated type.
Here "Myenum.t" will be generated, where type t = A | B | C.
  uint8_t sets width of fields with type myenum and sets carrying type
(here -- int).
  Numeric values of enum elements start from 0 (0l, 0L) unless overriden with
optional argument "~v" (see "B" definition).  Numeric values increase by 1
for each next element.  So, here A = 0 (start from 0), B = 3 (explicitely
specified with ~v:3), C = 4 (not specified, so "previous value + 1").
This behaviour matches C enum definitions.
  Only enums that are used in cstructs are codegenerated.  Optional boolean
argument "generate_always" passed to "enum" function changes this behaviour.


  Then -- structures:

    let () = cstruct "mystruct"
      [ uint8_t "ui8"
      ; int64_t "si64" ~dump_fmt:"0x%LX"
      ; myenum  "en"
      ]

  Here "mystruct" is defined, module Mystruct is generated.
Fields can have either numeric or enum type.
  Optional argument ~dump_fmt is a Printf-style format string that specifies
how the field value will be dumped with Mystruct.dump.  Omitting ~dump_fmt
means that field value will be dumped in decimal notation.

  At last, run code generation:

    let () = codegen "src/mycstructs.ml"




        How to use this library in your project:


  Install ocaml-cstruct-codegen.

  Add to _oasis:

    PreBuildCommand: sh ./gen_cstructs.sh

  Add to _oasis / BuildDepends:

    cstruct_codegen, extunix

(since generated code uses extunix library to access bigarray "fields".)

  Add to _tags:

    <src/gen_cstructs.*> : pkg_cstruct_codegen

  Create ./gen_cstructs.sh:

    #! /bin/sh
    ocamlbuild src/gen_cstructs.byte && ./gen_cstructs.byte

  Write definitions in src/gen_cstructs.ml:

    open Cstruct_codegen
    [.. your structure definitions ..]
    let () = codegen "src/cstructs.ml"

  See section "How to define C-like structures and enums" for details.

  Then use "src/cstructs.ml".  Something like:

    open Cstructs
    let my1 = Mystruct.make ~a:12 in print_string (Mystruct.dump my1)



        People:

  - Dmitry Grebeniuk <gdsfh1@gmail.com> -- code
  - Dmitry Astapov <dastapov@gmail.com> -- documentation corrections


        License:

  LGPL-2.1 with OCaml linking exception