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: adds a stop-gap measure deps fields #5346

Merged
merged 7 commits into from
Mar 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion doc/dune-files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,8 @@ adding the following field to the ``dune-project`` file:

In this mode, Dune will populate the ``:standard`` set of C flags with the
content of ``ocamlc_cflags`` and ``ocamlc_cppflags``. These flags can be
completed or overridden using the :ref:`ordered-set-language`.
completed or overridden using the :ref:`ordered-set-language`. The value
``true`` is the default for Dune 3.0.

accept_alternative_dune_file_name
---------------------------------
Expand Down
15 changes: 14 additions & 1 deletion doc/foreign-code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ descriptions by referencing them as the module specified in optional
- ``(headers (preamble <preamble>)`` adds directly the preamble. Variables
can be used in ``<preamble>`` such as ``%{read: }``.

- Since the Dune's ``ctypes`` feature is still experimental, it could be useful to
add additional dependencies in order to make sure that local
headers or libraries are available: ``(deps <deps-conf list>)``. See the
:ref:`deps-field` section for more details.

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

- ``(concurrency <sequential|unlocked|lwt_jobs|lwt_preemptive>)`` tells ``ctypes
Expand All @@ -270,7 +275,9 @@ descriptions by referencing them as the module specified in optional
- ``(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.
library; see the :ref:`foreign_library` stanza. Usually the ``<flags>`` should
contain ``:standard`` in order to add the default flags used by the OCaml
compiler for C files :ref:`always-add-cflags`.


.. _foreign-sandboxing:
Expand All @@ -292,6 +299,12 @@ To do that, follow the following procedure:

- depends on this directory recursively via :ref:`source_tree <source_tree>`
- invokes the external build system
- copies the generated files
- the C archive ``.a`` must be built with ``-fpic``
- the ``libfoo.so`` must be copied as ``dllfoo.so``, and no ``libfoo.so``
should appear, otherwise the dynamic linking of the C library will be
attempted. However, this usually fails because the ``libfoo.so`` isn't available at
the time of the execution.
- *Attach* the C archive files to an OCaml library via :ref:`foreign-archives`.

For instance, let's assume that you want to build a C library
Expand Down
60 changes: 37 additions & 23 deletions src/dune_rules/ctypes_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,7 @@ let rule ?(deps = []) ?stdout_to ?(args = []) ?(targets = []) ~exe ~sctx ~dir ()
in
Super_context.add_rule sctx ~dir build

let build_c_program ~foreign_archives_deps ~sctx ~dir ~source_files ~scope
~cflags_sexp ~output () =
let build_c_program ~foreign_archives_deps ~sctx ~dir ~source_files ~scope ~cflags_sexp ~output ~deps () =
let ctx = Super_context.context sctx in
let open Memo.Build.O in
let* exe =
Expand Down Expand Up @@ -364,11 +363,15 @@ let build_c_program ~foreign_archives_deps ~sctx ~dir ~source_files ~scope
let source_file_deps =
List.map source_files ~f:(Path.relative (Path.build dir))
|> Dep.Set.of_files

in
let foreign_archives_deps =
List.map foreign_archives_deps ~f:Path.build |> Dep.Set.of_files
in
Dep.Set.union source_file_deps foreign_archives_deps
let open Action_builder.O in
let* () = Dep.Set.union source_file_deps foreign_archives_deps
|> Action_builder.deps in
deps
in
let build =
let cflags_args =
Expand Down Expand Up @@ -402,7 +405,7 @@ let build_c_program ~foreign_archives_deps ~sctx ~dir ~source_files ~scope
let action =
let open Action_builder.O in
let* include_args = Resolve.Build.read include_args in
Action_builder.deps deps
deps
>>> Action_builder.map cflags_args ~f:(fun cflags_args ->
let source_files = List.map source_files ~f:absolute_path_hack in
let output = absolute_path_hack output in
Expand Down Expand Up @@ -445,7 +448,7 @@ let program_of_module_and_dir ~dir program =
; loc = Loc.in_file (Path.relative build_dir program)
}

let exe_build_and_link ?libraries ?(modules = []) ~scope ~loc ~dir ~cctx program
let exe_build_and_link ?libraries ?(modules = []) ~scope ~loc ~dir ~cctx ~sandbox program
=
let open Memo.Build.O in
let* cctx =
Expand All @@ -454,27 +457,31 @@ let exe_build_and_link ?libraries ?(modules = []) ~scope ~loc ~dir ~cctx program
in
let program = program_of_module_and_dir ~dir program in
Exe.build_and_link ~program ~linkages:[ Exe.Linkage.native ] ~promote:None
~sandbox
cctx

let exe_link_only ~dir ~shared_cctx program =
let exe_link_only ~dir ~shared_cctx ~sandbox program ~deps =
let link_args =
let open Action_builder.O in
let+ () = deps in
Command.Args.empty
in
let program = program_of_module_and_dir ~dir program in
Exe.link_many ~programs:[ program ] ~linkages:[ Exe.Linkage.native ]
~promote:None shared_cctx
Exe.link_many ~link_args ~programs:[ program ] ~linkages:[ Exe.Linkage.native ]
~promote:None shared_cctx ~sandbox

let write_osl_to_sexp_file ~sctx ~dir ~filename osl =
let write_osl_to_sexp_file ~sctx ~dir ~filename ~expand_flag flags =
let build =
let path = Path.Build.relative dir filename in
let sexp =
let encoded =
match Ordered_set_lang.Unexpanded.encode osl with
| [ s ] -> s
| _lst ->
User_error.raise
[ Pp.textf "expected %s to contain a list of atoms" filename ]
in
Dune_lang.to_string encoded
let sexp =
let open Action_builder.O in
let* expander =
Action_builder.memo_build @@ Super_context.expander sctx ~dir in
let+ flags = expand_flag ~expander flags in
let sexp = Sexp.List (List.map ~f:(fun x -> Sexp.Atom x) flags) in
Sexp.to_string sexp
in
Action_builder.write_file path sexp
let path = Path.Build.relative dir filename in
Action_builder.write_file_dyn path sexp
in
Super_context.add_rule ~loc:Loc.none sctx ~dir build

Expand Down Expand Up @@ -506,6 +513,8 @@ let gen_rules ~cctx ~buildable ~loc ~scope ~dir ~sctx =
; Foreign.Archive.dll_file ~archive ~dir ~ext_dll
])
in
let* expander = Super_context.expander sctx ~dir in
let deps, sandbox = Dep_conf_eval.unnamed ~expander ctypes.deps in
let* () =
write_c_types_includer_module ~sctx ~dir
~filename:(ml_of_module_name c_types_includer_module)
Expand All @@ -525,9 +534,14 @@ let gen_rules ~cctx ~buildable ~loc ~scope ~dir ~sctx =
| Vendored { c_flags; c_library_flags } ->
let* () =
write_osl_to_sexp_file ~sctx ~dir ~filename:cflags_sexp c_flags
~expand_flag:(fun ~expander flags -> Super_context.foreign_flags
sctx ~dir ~expander ~flags ~language:C)
in
write_osl_to_sexp_file ~sctx ~dir ~filename:c_library_flags_sexp
c_library_flags
~expand_flag:(fun ~expander flags ->
Expander.expand_and_eval_set expander flags
~standard:(Action_builder.return []))
| Pkg_config ->
let cflags_sexp = Stanza_util.cflags_sexp ctypes in
let discover_script = Stanza_util.discover_script ctypes in
Expand All @@ -536,7 +550,7 @@ let gen_rules ~cctx ~buildable ~loc ~scope ~dir ~sctx =
~cflags_sexp ~c_library_flags_sexp ~external_library_name
in
let* () =
exe_build_and_link ~scope ~loc ~dir ~cctx
exe_build_and_link ~scope ~loc ~dir ~cctx ~sandbox
~libraries:[ "dune.configurator" ] discover_script
in
rule
Expand All @@ -545,7 +559,7 @@ let gen_rules ~cctx ~buildable ~loc ~scope ~dir ~sctx =
in
let generated_entry_module = Stanza_util.entry_module ctypes in
let headers = ctypes.Ctypes.headers in
let exe_link_only = exe_link_only ~dir ~shared_cctx:cctx in
let exe_link_only = exe_link_only ~deps ~dir ~shared_cctx:cctx ~sandbox in
(* Type_gen produces a .c file, taking your type description module above as
an input. The .c file is compiled into an .exe. The .exe, when run produces
an .ml file. The .ml file is compiled into a module that will have the
Expand Down Expand Up @@ -573,7 +587,7 @@ let gen_rules ~cctx ~buildable ~loc ~scope ~dir ~sctx =
let* () =
build_c_program ~foreign_archives_deps ~sctx ~dir ~scope ~cflags_sexp
~source_files:[ c_generated_types_cout_c ]
~output:c_generated_types_cout_exe ()
~output:c_generated_types_cout_exe ~deps ()
in
rule
~stdout_to:(c_generated_types_module |> ml_of_module_name)
Expand Down
4 changes: 4 additions & 0 deletions src/dune_rules/ctypes_stanza.ml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ type t =
; function_description : Function_description.t list
; generated_types : Module_name.t
; generated_entry_point : Module_name.t
; deps : Dep_conf.t list
}

let name = "ctypes"
Expand All @@ -134,6 +135,8 @@ let decode =
and+ generated_types = field_o "generated_types" Module_name.decode
and+ generated_entry_point =
field "generated_entry_point" Module_name.decode
and+ deps =
field_o "deps" (repeat Dep_conf.decode)
in
{ external_library_name
; build_flags_resolver =
Expand All @@ -145,6 +148,7 @@ let decode =
Option.value generated_types
~default:(Module_name.of_string "Types_generated")
; generated_entry_point
; deps = Option.value ~default:[] deps
})

let () =
Expand Down
1 change: 1 addition & 0 deletions src/dune_rules/ctypes_stanza.mli
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type t =
; function_description : Function_description.t list
; generated_types : Module_name.t
; generated_entry_point : Module_name.t
; deps : Dep_conf.t list
}

type Stanza.t += T of t
Expand Down