Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ctypes stanza #3905

Closed
wants to merge 78 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
716d790
start working on ctypes stanza
mbacarella Oct 30, 2020
40463b5
Merge branch 'master' of github.com:mbacarella/dune into ctypes-stanza
mbacarella Oct 30, 2020
ec9e8c1
pseudocode direction
mbacarella Nov 6, 2020
bbb3f93
naive first pass translation of hand-written dune file rules. with er…
mbacarella Dec 6, 2020
6f68c0c
have ctypes provide list of generated files to Dir_contents
mbacarella Dec 7, 2020
5ea1a03
lowercase
mbacarella Dec 7, 2020
f372ccd
save progress
mbacarella Dec 24, 2020
5743185
dont use Build.exec
mbacarella Dec 25, 2020
c68c1b6
no need for this variant anymore
mbacarella Dec 25, 2020
83947d8
saving work, almost almost compiles a ctypes module
mbacarella Jan 26, 2021
69a0f55
include parsing_context for :include directives
mbacarella Jan 29, 2021
a4d7fc3
minimal example works
mbacarella Jan 31, 2021
76a50c9
declare module names
mbacarella Feb 2, 2021
760b3ea
move from library to buildable stanza, so exe can use ctypes too
mbacarella Feb 4, 2021
1a0875f
finish ctypes stanza for executables
mbacarella Feb 4, 2021
8b8ca1f
inch towards a finalized ctypes config (for ctypes 0.1)
mbacarella Feb 13, 2021
ef88772
headers include or preamble
mbacarella Feb 14, 2021
545bf2e
get rid of extra cflags file. support vendoring
mbacarella Feb 14, 2021
227f520
user_error instead of failwith
mbacarella Feb 16, 2021
fdbbb13
ctypes_library is its own top-level stanza now
mbacarella Feb 21, 2021
d993a1d
decided to not do a top-level stanza after all
mbacarella Feb 22, 2021
1bd95b1
trying an approach with no intermediate libraries
mbacarella Mar 8, 2021
9d4662d
Add a test showing that Dune always pulls unused ml files
jeremiedimino Mar 8, 2021
7bd71b9
Narrow dependencies on .ml files for executables
jeremiedimino Mar 8, 2021
09fe7fd
resolve merge conflict with ctypes-stanza
mbacarella Mar 8, 2021
f0810fa
Merge remote-tracking branch 'jeremiedimino/dont-pull-all-ml-for-tran…
mbacarella Mar 8, 2021
365505e
(executables ... (ctypes ...)) almost works
mbacarella Mar 9, 2021
8a9c921
dont need the ctypes.foreign library
mbacarella Mar 10, 2021
827ec06
pull ctypes stubs into Buildable.foreign_stubs
mbacarella Mar 11, 2021
a75d8d6
implement ctypes for libraries too
mbacarella Mar 11, 2021
b1c9e40
add ctypes libraries to buildable if user uses ctypes
mbacarella Mar 12, 2021
93f69cd
use ctypes link flags in libraries
mbacarella Mar 12, 2021
ac3ad60
remove unneeded code
mbacarella Mar 13, 2021
326c279
build some blackbox tests
mbacarella Mar 25, 2021
22d7771
simplify stanza a bit
mbacarella Apr 1, 2021
c2f2521
start documenting ctypes stanza
mbacarella Apr 1, 2021
4702cb1
capital percent S
mbacarella Apr 16, 2021
64a581b
better error message
mbacarella Apr 16, 2021
44988cc
support building docs for libraries that depend on foreign_librarys
mbacarella Apr 23, 2021
968e238
dont install modules that are for stub generation
mbacarella Apr 23, 2021
12d58bf
simplifiy non_installable_modules
mbacarella Apr 24, 2021
823151f
whitespace
mbacarella Apr 24, 2021
cac6945
revert recent changes to install rules
mbacarella Apr 24, 2021
00d9efc
exclude ctypes code-gen programs from being added to archives
mbacarella Apr 24, 2021
33b73de
ctypes doc fix
mbacarella Apr 24, 2021
efcb33a
support repeated function_description stanzas
mbacarella Apr 28, 2021
4f535b8
list ctypes in CHANGES.md
mbacarella Apr 29, 2021
99aca83
fix descriptions
mbacarella May 19, 2021
90dfeed
merge main into ctypes-stanza
mbacarella May 20, 2021
e25db44
fix accidentally calling build_all twice
mbacarella May 20, 2021
233efad
fix comment
mbacarella May 20, 2021
746744d
re-add PR request number to CHANGES.md entry
mbacarella May 27, 2021
8f3227b
extension appears in dune 3.0 lang
mbacarella May 27, 2021
550e56f
Small doc tweak
rgrinberg Jul 20, 2021
8ed91d0
Move Dune_file.Ctypes to own module
rgrinberg Jul 20, 2021
60d1303
did not actually need to add this sub_systems field here
mbacarella Jul 20, 2021
35f66b1
ctypes build tests dune-project 2.8 -> 3.0
mbacarella Jul 20, 2021
3a8d53d
quick description of each unit test
mbacarella Jul 20, 2021
84ab501
remove whitespace-only changes from PR
mbacarella Jul 20, 2021
2da56ab
make fmt
mbacarella Jul 20, 2021
1655d9b
more ctypes unit tests (pkg-config probed args)
mbacarella Jul 21, 2021
0be0ea6
more docs on using ctypes, with quick example ocaml code
mbacarella Jul 22, 2021
a9a88e6
more unit test coverage
mbacarella Jul 22, 2021
4f341ec
unneeded file
mbacarella Jul 22, 2021
b175c71
coverage for preamble headers
mbacarella Jul 22, 2021
9e165d6
one more test
mbacarella Jul 22, 2021
d3519d3
Merge branch 'main' into ctypes-stanza
mbacarella Aug 2, 2021
0c46b09
resolve merge conflict
mbacarella Oct 14, 2021
b658441
Merge branch 'main' into ctypes-stanza
mbacarella Oct 15, 2021
5f57410
resolve merge conflict markers in doc
mbacarella Oct 15, 2021
3e48615
Merge branch 'ctypes-stanza' of github.com:mbacarella/dune into ctype…
mbacarella Oct 15, 2021
52ed839
fix(ctypes): busted merge conflict
rgrinberg Oct 17, 2021
8fa4100
test(ctypes): require ctypes as test dependency
rgrinberg Oct 17, 2021
627967e
test(ctypes): remove binaries
rgrinberg Oct 17, 2021
605350f
Merge branch 'main' into ctypes-stanza
rgrinberg Oct 17, 2021
18ca12c
chore(nix): add ctypes to test dependencies
rgrinberg Oct 17, 2021
9781f16
chore: add ctypes to test deps in makefile
rgrinberg Oct 17, 2021
cda682e
chore: enable ctypes tests on linux only
rgrinberg Oct 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,12 @@ Unreleased
- Do not pass include directories containing native objects when compiling
bytecode (#4200, @nojb)

- If an .ml file is not used by an executable, Dune no longer report
parsing error in this file (#4330, @jeremiedimino)

- Experimental ctypes support (#3905, fixes #135, @mbacarella)


2.8.2 (21/01/2021)
------------------

Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ cinaps \
coq-native \
"coq>=8.12.1" \
core_bench \
ctypes \
"csexp>=1.3.0" \
js_of_ocaml \
js_of_ocaml-compiler \
Expand All @@ -28,6 +29,7 @@ ocamlformat.0.19.0 \
ppx_inline_test \
ppxlib \
result \
ctypes \
"utop>=2.6.0"

# Dependencies recommended for developing dune locally,
Expand Down
36 changes: 24 additions & 12 deletions doc/dune-files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,11 @@ to use the :ref:`include_subdirs` stanza.
is useful whenever a library is shadowed by a local module. The library may
then still be accessible via this root module

- ``(ctypes <ctypes stanza>)`` instructs dune to use ctypes stubgen to process
your type and function descriptions for binding system libraries, vendored
libraries, or other foreign code. See :ref:`ctypes-stubgen` for a full
reference. This field is available since the 3.0 version of the dune language.

- ``(empty_module_interface_if_absent)`` causes the generation of empty
interfaces for every module that does not have an interface file already.
Useful when modules are used solely for their side-effects. This field is
Expand Down Expand Up @@ -811,14 +816,21 @@ files for executables. See `executables_implicit_empty_intf`_.
flag if some of the libraries listed here are not referenced from any of the
plugin modules.

Linking Modes
=============
- ``(ctypes <ctypes stanza>)`` instructs dune to use ctypes stubgen to process
your type and function descriptions for binding system libraries, vendored
libraries, or other foreign code. See :ref:`ctypes-stubgen` for a full
reference. This field is available since the 3.0 version of the dune language.

- ``(empty_module_interface_if_absent)`` causes the generation of empty

``(empty_module_interface_if_absent)`` causes the generation of empty
- ``(empty_module_interface_if_absent)`` causes the generation of empty
interfaces for every module that does not have an interface file already.
Useful when modules are used solely for their side-effects. This field is
available since the 3.0 version of the Dune language.

Linking Modes
=============
mbacarella marked this conversation as resolved.
Show resolved Hide resolved

The ``modes`` field allows selecting which linking modes will be used
to link executables. Each mode is a pair ``(<compilation-mode>
<binary-kind>)``, where ``<compilation-mode>`` describes whether the
Expand Down Expand Up @@ -1916,21 +1928,21 @@ Where ``<optional-fields>`` are:
- ``(libraries <libraries>)`` are libraries that should be
statically linked in the MDX test executable.

- ``(enabled_if <blang expression>)`` is the same as the
corresponding field of `library`_.
- ``(enabled_if <blang expression>)`` is the same as the corresponding field
of `library`_.

- ``(package <package>)`` specifies which package to attach
this stanza to (similarly to when ``(package)`` is attached to a ``(rule)``
stanza). When ``-p`` is passed, ``(mdx)`` stanzas with another package will
be ignored. Note that this feature is completely separate from
``(packages)``, which specifies some dependencies.
- ``(package <package>)`` specifies which package to attach this stanza to
(similarly to when ``(package)`` is attached to a ``(rule)`` stanza). When
``-p`` is passed, ``(mdx)`` stanzas with another package will be ignored.
Note that this feature is completely separate from ``(packages)``, which
specifies some dependencies.

Upgrading from Version 0.1
~~~~~~~~~~~~~~~~~~~~~~~~~~

- The 0.2 version of the stanza requires at least MDX 1.9.0. If you encounter
an error such as, ``ocaml-mdx: unknown command `dune-gen'``, then you
should upgrade MDX.
an error such as, ``ocaml-mdx: unknown command `dune-gen'``, then you should
upgrade MDX.

- The field ``(packages <packages>)`` is deprecated in version 0.2. You can
use package items in the generic ``deps`` field instead:
Expand Down
211 changes: 211 additions & 0 deletions doc/foreign-code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,215 @@ without the ``.h`` extension. When a library install header files,
these are made visible to users of the library via the include search
path.

.. _ctypes-stubgen:

Stub Generation with Dune Ctypes
================================

Beginning in dune 3.0, it is possible to use the ctypes_ stanza to generate
bindings for C libraries without writing any C code.

Note that dune support for this feature is experimental and is not subject
to backward compatibility guarantees.

To use dune ctypes stub generation, you must provide two OCaml modules: a "type
description" module for describing the C library types and constants, and a
"function description" module for describing the C library functions.
Additionally, you must list any C headers and a method for resolving build and
link flags.

If you're binding a library distributed by your OS, you can use the
``pkg-config`` utility to resolve any build and link flags. Alternatively, if
you're using a locally installed library or a vendored library, you can provide
the flags manually.

The "type description" module must define a functor named ``Types`` with
signature ``Ctypes.TYPE``. The "function description" module must define a
functor named ``Functions`` with signature ``Ctypes.FOREIGN``.

A toy example
-------------

To begin, you must declare the ctypes extension in your ``dune-project`` file:

.. code:: scheme

(lang dune 3.0)
(using ctypes 0.1)


Next, here is a ``dune`` file you can use to define an OCaml program that
binds a C system library called ``libfoo``, which offers ``foo.h`` in a
standard location.

.. code:: scheme

(executable
(name foo)
(libraries core)
; ctypes backward compatibility shims warn sometimes; suppress them
(flags (:standard -w -9-27))
(ctypes
(external_library_name libfoo)
(build_flags_resolver pkg_config)
(headers (include "foo.h"))
(type_description
(instance Type)
(functor Type_description))
(function_description
(concurrency unlocked)
(instance Function)
(functor Function_descriptio))
(generated_types Types_generated)
(generated_entry_point C)))

This stanza will introduce a module named ``C`` into your project, with the
sub-modules ``Types`` and ``Functions`` that will have your fully bound C
types, constants and functions.

Given libfoo with the C header file ``foo.h``:

.. code:: c

#define FOO_VERSION 1

int foo_init(void);

int foo_fnubar(char *);

void foo_exit(void);

Your example ``type_description.ml`` file is:

.. code:: ocaml

open Ctypes

module Types (F : Ctypes.TYPE) = struct
open F

let foo_version = constant "FOO_VERSION" int
end

Your example ``function_description.ml`` file is:

.. code:: ocaml

open Ctypes

(* This Types_generated module is an instantiation of the Types
functor defined in the type_description.ml file. It's generated by
a C program that dune creates and runs behind the scenes. *)
module Types = Types_generated

module Functions (F : Ctypes.FOREIGN) = struct
open F

let foo_init = foreign "foo_init" (void @-> returning int)

let foo_fnubar = foreign "foo_fnubar" (string_opt @-> returning int)

let foo_exit = foreign "foo_exit" (void @-> returning void)
end

Finally, the entry point of your executable named above, ``foo.ml``,
demonstrates how to access the bound C library functions and values:

.. code:: ocaml

let () =
if (C.Types.foo_version <> 1) then
failwith "foo only works with libfoo version 1";

match C.Functions.foo_init () with
| 0 ->
C.Functions.foo_fnubar "fnubar!";
C.Functions.foo_exit ()
| err_code ->
Printf.eprintf "foo_init failed: %d" err_code;
;;

From here, one only needs to run ``dune build ./foo.exe`` to generate the
stubs and build and link the example ``foo.exe`` program.

Complete information about the ctypes combinators used above is available at
the ctypes_ project.

Ctypes stanza reference
------------------------

The ``ctypes`` stanza can be used in any ``executable(s)`` or ``library``
stanza.

.. code:: scheme

((executable|library)
...
(ctypes
(external_library_name <package-name>)
(type_description
(instance <module-name>)
(functor <module-name>))
(function_description
(instance <module-name>)
(functor <module-name>)
<optional-function-description-fields>)
(generated_entry_point <module-name>)
<optional-ctypes-fields>)
)

- ``type_description``: the ``functor`` module is a description of the C library
types and constants written in the ``ctypes`` domain-specific language you
wish to bind. The ``instance`` module is the name the functor will be
instantiated under, inserted into the top-level of the
``generated_entry_point`` module.

- ``function_description``: the ``functor`` module is a description of the C
library functions written in the ``ctypes`` domain-specific language you wish
to bind. The ``instance`` module is the name the functor will be
instantiated under, inserted into the top-level of the
``generated_entry_point`` module. The ``function_description`` stanza can be
repeated. This is useful if you need to specify sets of functions with
different concurrency policies (see below).

The instantiated types described above can be accessed from the function
descriptions by referencing them as the module specified in optional
``generated_types`` field.

``<optional-ctypes-fields>`` are:

- ``(build_flags_resolver <pkg_config|vendored-stanza>)`` tells dune how to
compile and link your foreign library. Specifying ``pkg_config`` will use
the ``pkg-config`` tool to query the compilation and link flags for
``external_library_name``. For vendored libraries, provide the build and link
flags using ``vendored`` stanza. If ``build_flags_resolver`` is not
specified, the default of ``pkg_config`` will be used.

- ``(generated_types <module-name>)`` is the name of an intermediate module. By
default it is named ``Types_generated``. You can use this module to access
the types defined in ``Type_description`` from your ``Function_description``
module(s).

- ``(generated_entry_point <module-name>)`` is the name of a generated module
that your instantiated ``Types`` and ``Function`` modules will instantiated
under. We suggest calling it ``C``.

``<optional-function-description-fields>`` are:

- ``(concurrency <sequential|unlocked|lwt_jobs|lwt_preemptive>)`` tells ctypes
stubgen whether to call your C functions with the runtime lock held or
released. These correspond to the ``concurrency_policy`` type in the
``ctypes`` library. If ``concurrency`` is not specified, the default of
``sequential`` will be used.

``<vendored-stanza>`` is:

- ``(vendored (c_flags <flags>) (c_library_flags <flags>))`` provide the build
and link flags for binding your vendored code. You must also provide
instructions in your ``dune`` file on how to build the vendored foreign
library; see the :ref:`foreign_library` stanza.


.. _foreign-sandboxing:

Foreign build sandboxing
Expand Down Expand Up @@ -148,3 +357,5 @@ The `re2 project <https://github.com/janestreet/re2>`_ uses this
method to build the re2 C library. You can look at the file
``re2/src/re2_c/dune`` in this project to see a full working
example.

.. _ctypes: https://github.com/ocamllabs/ocaml-ctypes
1 change: 1 addition & 0 deletions nix/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ let
"ppxlib"
"result"
"utop"
"ctypes"
"${coq}/coq-core.opam"
]);

Expand Down
Loading