bindings-DSL: FFI domain specific language, on top of hsc2hs.

[ bsd3, ffi, library ] [ Propose Tags ] [ Report a vulnerability ]

This is a set of macros to be used when writing Haskell FFI. They were designed to be able to fully describe C interfaces, so that hsc2hs can extract from them all Haskell code needed to mimic such interfaces. All Haskell names used are automatically derived from C names, structures are mapped to Haskell instances of Storable, and there are also macros you can use with C code to help write bindings to inline functions or macro functions. Documentation is available at package homepage:

https://github.com/rethab/bindings-dsl/wiki

The extra module Bindings.Utilities will contain tools that may be convenient when working with FFI.


[Skip to Readme]

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 1.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4, 1.0.5, 1.0.6, 1.0.7, 1.0.8, 1.0.9, 1.0.10, 1.0.11, 1.0.12, 1.0.14, 1.0.15, 1.0.16, 1.0.17, 1.0.18, 1.0.19, 1.0.20, 1.0.21, 1.0.22, 1.0.23, 1.0.24, 1.0.25, 1.1.0 (info)
Change log CHANGELOG.md
Dependencies base (>=4 && <5) [details]
License BSD-3-Clause
Author Maurício C. Antunes
Maintainer Reto <rethab@protonmail.ch>
Uploaded by rethab at 2026-07-11T14:13:24Z
Category FFI
Home page https://github.com/rethab/bindings-dsl/wiki
Bug tracker https://github.com/rethab/bindings-dsl/issues
Source repo head: git clone https://github.com/rethab/bindings-dsl -b master
this: git clone https://github.com/rethab/bindings-dsl(tag bindings-DSL-1.1.0)
Distributions Arch:1.0.25, Fedora:1.0.25, LTSHaskell:1.0.25, Stackage:1.0.25
Reverse Dependencies 78 direct, 149 indirect [details]
Downloads 43300 total (97 in the last 30 days)
Rating 2.0 (votes: 1) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2026-07-11 [all 1 reports]

Readme for bindings-DSL-1.1.0

[back to package description]

bindings-dsl

Hackage CI BSD3 License

bindings-DSL is a domain specific language for writing Haskell FFI bindings, on top of hsc2hs. It is a set of C macros that describe a C interface, and from which hsc2hs extracts the Haskell code that mimics it: #ccall for a function, #starttype and #field for a struct, #num for a constant, and so on.

#include <bindings.dsl.h>
#include <gpgme.h>

module Bindings.Gpgme where
#strict_import

#num GPGME_PK_RSA

#starttype struct _gpgme_key
#field revoked , CUInt
#field fpr     , CString
#stoptype

#ccall gpgme_get_key , <gpgme_ctx_t> -> CString -> Ptr <gpgme_key_t> -> CInt -> IO <gpgme_error_t>

Haskell names are derived from the C names automatically, so there is no naming scheme to invent and no chance of the two drifting apart: a constant becomes c'GPGME_PK_RSA, a struct becomes a Storable instance with p'_gpgme_key'fpr accessors, and a function becomes c'gpgme_get_key. Structs are laid out by the C compiler rather than by hand, which is what makes the bindings portable across platforms where sizes and padding differ. There are also macros for binding inline functions and macro functions, which have no symbol to call.

Full documentation, including a tutorial, is on the wiki. Release notes are in CHANGELOG.md.

Packages

bindings-DSL is the DSL itself. The bindings built on top of it are released as separate packages from this repository:

Package Hackage
bindings-directfb Hackage
bindings-fann Hackage
bindings-glib Hackage
bindings-gpgme Hackage
bindings-gsl Hackage
bindings-hdf5 Hackage
bindings-libcddb Hackage
bindings-libffi Hackage
bindings-posix Hackage
bindings-sqlite3 Hackage

Contributing

Contributions are welcome, whether to the DSL itself or to any of the bindings. Bugs, missing coverage of a C API, and build problems can be raised in the issue tracker; pull requests are just as welcome. CI builds the DSL and the bindings across several GHC versions and library releases, so open a pull request and let it run.

Building bindings-gpgme on macOS with Homebrew

gpgme.h includes <gpg-error.h>, and Homebrew ships libgpg-error as a keg of its own, so both prefixes have to be on the include and library paths. Passing only gpgme's prefix leaves the nested include unresolved and the build fails with a misleading complaint about a missing gpgme.h.

brew install gpgme libgpg-error

cabal build bindings-gpgme \
  --extra-include-dirs="$(brew --prefix gpgme)/include" \
  --extra-include-dirs="$(brew --prefix libgpg-error)/include" \
  --extra-lib-dirs="$(brew --prefix gpgme)/lib" \
  --extra-lib-dirs="$(brew --prefix libgpg-error)/lib"

With stack, list both prefixes in stack.yaml (brew --prefix is /opt/homebrew on Apple silicon and /usr/local on Intel):

extra-include-dirs:
  - /opt/homebrew/opt/gpgme/include
  - /opt/homebrew/opt/libgpg-error/include
extra-lib-dirs:
  - /opt/homebrew/opt/gpgme/lib
  - /opt/homebrew/opt/libgpg-error/lib

Cross compilation

bindings-DSL does not work with hsc2hs --cross-compile (see #38). Every construct (#strict_import, #starttype, #ccall, ...) is a custom hsc2hs construct that emits Haskell while the generated C program runs. Cross mode never runs that program: it recognises only a fixed set of built-in directives and rejects everything else with

directive strict_import cannot be handled in cross-compilation mode

--via-asm does not help, it only changes how cross mode extracts constants. No change to bindings.dsl.h can lift this; it needs hsc2hs to support custom constructs when cross compiling.

Cross compiling still works if you can execute target binaries, e.g. with qemu-user plus binfmt_misc, or wine for Windows targets. Cabal gets in the way here: it passes -x to hsc2hs whenever the host platform differs from the build platform, and hsc2hs has no flag to undo that. Point Cabal at a wrapper that drops the flag and lets the normal compile-and-run path proceed under emulation:

#!/bin/sh
# hsc2hs-no-cross, used via --with-hsc2hs=/path/to/hsc2hs-no-cross
for a in "$@"; do
  shift
  case "$a" in
    -x|--cross-compile) ;;
    *) set -- "$@" "$a" ;;
  esac
done
exec hsc2hs "$@"

Otherwise, write plain .hsc without bindings-DSL for the modules you need to cross compile.