Skip to content

Commit

Permalink
Merge pull request #3825 from rgrinberg/extra-aliases
Browse files Browse the repository at this point in the history
(root_module ..) field for libraries & executables
  • Loading branch information
rgrinberg authored Nov 23, 2020
2 parents 92e1c27 + 2cb4b96 commit 5cf80f1
Show file tree
Hide file tree
Showing 27 changed files with 383 additions and 93 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ Unreleased

- Avoid pager when running `$ git diff` (#3912, @AltGr)

- Add `(root_module ..)` field to libraries & executables. This makes it
possible to use library dependencies shadowed by local modules (#3825,
@rgrinberg)

2.7.1 (2/09/2020)
-----------------

Expand Down
9 changes: 9 additions & 0 deletions doc/dune-files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,11 @@ to use the :ref:`include_subdirs` stanza.
configured through options using ``(inline_tests <options>)``. See
:ref:`inline_tests` for a reference of corresponding options.

- ``(root_module <module>)`` this field instructs dune to generate a module that
will contain module aliases for every library specified in dependencies. This
is useful whenever a library is shadowed by a local module. The library may
then still be accessible via this root module

Note that when binding C libraries, dune doesn't provide special support for
tools such as ``pkg-config``, however it integrates easily with
:ref:`configurator` by
Expand Down Expand Up @@ -644,6 +649,10 @@ Executables can also be linked as object or shared object files. See
the current stanza. It is interpreted in the same way as the ``(modules
...)`` field of `library`_

- ``(root_module <module>)`` specifies a ``root_module`` that collects all
dependencies specified in ``libraries``. See the documentation for
``root_module`` in the library stanza.

- ``(modes (<modes>))`` sets the `linking modes`_. The default is
``(exe)``. Before 2.0, it used to be ``(byte exe)``.

Expand Down
4 changes: 1 addition & 3 deletions src/dune_rules/cinaps.ml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ let decode =
field "files" Predicate_lang.Glob.decode ~default:Predicate_lang.any
and+ preprocess, preprocessor_deps = Dune_file.preprocess_fields
and+ libraries =
field "libraries"
(Dune_file.Lib_deps.decode ~allow_re_export:false)
~default:[]
field "libraries" (Dune_file.Lib_deps.decode Executable) ~default:[]
and+ flags = Ocaml_flags.Spec.decode in
{ loc; files; libraries; preprocess; preprocessor_deps; flags })

Expand Down
26 changes: 24 additions & 2 deletions src/dune_rules/compilation_context.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ open! Stdune
open Import
module SC = Super_context

let modules_of_lib = Fdecl.create Dyn.Encoder.opaque

module Includes = struct
type t = Command.Args.dynamic Command.Args.t Cm_kind.Dict.t

Expand Down Expand Up @@ -164,8 +166,8 @@ let for_alias_module t =
let flags =
let project = Scope.project t.scope in
let dune_version = Dune_project.dune_version project in
Ocaml_flags.default ~profile:(Super_context.context t.super_context).profile
~dune_version
let profile = (Super_context.context t.super_context).profile in
Ocaml_flags.default ~dune_version ~profile
in
let sandbox =
let ctx = Super_context.context t.super_context in
Expand All @@ -186,6 +188,20 @@ let for_alias_module t =
; sandbox
}

let for_root_module t =
let flags =
let project = Scope.project t.scope in
let dune_version = Dune_project.dune_version project in
let profile = (Super_context.context t.super_context).profile in
Ocaml_flags.default ~profile ~dune_version
in
{ t with
flags =
Ocaml_flags.append_common flags
[ "-w"; "-49"; "-nopervasives"; "-nostdlib" ]
; stdlib = None
}

let for_module_generated_at_link_time cctx ~requires ~module_ =
let opaque =
(* Cmi's of link time generated modules are compiled with -opaque, hence
Expand Down Expand Up @@ -214,3 +230,9 @@ let for_plugin_executable t ~embed_in_plugin_libraries =
{ t with requires_link }

let without_bin_annot t = { t with bin_annot = false }

let root_module_entries t : Module_name.t list Or_exn.t =
let open Result.O in
let* requires = t.requires_compile in
let local_lib = Fdecl.get modules_of_lib t.super_context in
Result.List.concat_map requires ~f:(Lib.entry_module_names ~local_lib)
8 changes: 8 additions & 0 deletions src/dune_rules/compilation_context.mli
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ type opaque =
| Inherit_from_settings
(** Determined from the version of OCaml and the profile *)

val modules_of_lib :
(* to avoid a cycle with [Dir_contents] *)
(Super_context.t -> dir:Path.Build.t -> name:Lib_name.t -> Modules.t) Fdecl.t

(** Create a compilation context. *)
val create :
super_context:Super_context.t
Expand Down Expand Up @@ -90,6 +94,8 @@ val modes : t -> Mode.Dict.Set.t

val for_wrapped_compat : t -> t

val for_root_module : t -> t

val for_module_generated_at_link_time :
t -> requires:Lib.t list Or_exn.t -> module_:Module.t -> t

Expand All @@ -99,3 +105,5 @@ val for_plugin_executable :
val bin_annot : t -> bool

val without_bin_annot : t -> t

val root_module_entries : t -> Module_name.t list Or_exn.t
8 changes: 8 additions & 0 deletions src/dune_rules/dir_contents.ml
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,14 @@ end = struct
| See_above _ -> assert false
| Here { t; rules = _; subdirs = _ } -> t )

let () =
let f sctx ~dir ~name =
let t = get sctx ~dir in
let ml_sources = ocaml t in
Ml_sources.modules_of_library ml_sources ~name
in
Fdecl.set Compilation_context.modules_of_lib f

let gen_rules sctx ~dir =
match Memo.exec memo0 (sctx, dir) with
| See_above group_root -> Group_part group_root
Expand Down
50 changes: 32 additions & 18 deletions src/dune_rules/dune_file.ml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ module Js_of_ocaml = struct
{ flags = Ordered_set_lang.Unexpanded.standard; javascript_files = [] }
end

type for_ =
| Executable
| Library of Wrapped.t option

module Lib_deps = struct
type t = Lib_dep.t list

Expand All @@ -53,9 +57,16 @@ module Lib_deps = struct
| Optional
| Forbidden

let decode ~allow_re_export =
let decode for_ =
let+ loc = loc
and+ t = repeat (Lib_dep.decode ~allow_re_export) in
and+ t =
let allow_re_export =
match for_ with
| Library _ -> true
| Executable -> false
in
repeat (Lib_dep.decode ~allow_re_export)
in
let add kind name acc =
match Lib_name.Map.find acc name with
| None -> Lib_name.Map.set acc name kind
Expand Down Expand Up @@ -103,7 +114,7 @@ module Lib_deps = struct
let info t ~kind =
List.concat_map t ~f:(function
| Lib_dep.Re_export (_, s)
| Lib_dep.Direct (_, s) ->
| Direct (_, s) ->
[ (s, kind) ]
| Select { choices; _ } ->
List.concat_map choices ~f:(fun (c : Lib_dep.Select.Choice.t) ->
Expand Down Expand Up @@ -161,18 +172,18 @@ module Buildable = struct
; flags : Ocaml_flags.Spec.t
; js_of_ocaml : Js_of_ocaml.t
; allow_overlapping_dependencies : bool
; root_module : (Loc.t * Module_name.t) option
}

let decode ~in_library ~allow_re_export =
let decode (for_ : for_) =
let use_foreign =
Dune_lang.Syntax.deleted_in Stanza.syntax (2, 0)
~extra_info:"Use the (foreign_stubs ...) field instead."
in
let only_in_library decode =
if in_library then
decode
else
return None
match for_ with
| Executable -> return None
| Library _ -> decode
in
let add_stubs language ~loc ~names ~flags foreign_stubs =
match names with
Expand Down Expand Up @@ -219,8 +230,7 @@ module Buildable = struct
>>> enter (maybe string) )))
and+ modules_without_implementation =
Stanza_common.modules_field "modules_without_implementation"
and+ libraries =
field "libraries" (Lib_deps.decode ~allow_re_export) ~default:[]
and+ libraries = field "libraries" (Lib_deps.decode for_) ~default:[]
and+ flags = Ocaml_flags.Spec.decode
and+ js_of_ocaml =
field "js_of_ocaml" Js_of_ocaml.decode ~default:Js_of_ocaml.default
Expand Down Expand Up @@ -254,6 +264,9 @@ module Buildable = struct
repeat (String_with_vars.decode >>| version_check)
in
(libname, flags))) ))
and+ root_module =
field_o "root_module"
(Dune_lang.Syntax.since Stanza.syntax (2, 8) >>> Module_name.decode_loc)
in
let preprocess =
let init =
Expand Down Expand Up @@ -309,6 +322,7 @@ module Buildable = struct
; flags
; js_of_ocaml
; allow_overlapping_dependencies
; root_module
}

let has_foreign t =
Expand Down Expand Up @@ -564,8 +578,9 @@ module Library = struct
let decode =
fields
(let* stanza_loc = loc in
let* wrapped = Wrapped.field in
let* dune_version = Dune_lang.Syntax.get_exn Stanza.syntax in
let+ buildable = Buildable.decode ~in_library:true ~allow_re_export:true
let+ buildable = Buildable.decode (Library (Option.map ~f:snd wrapped))
and+ name = field_o "name" Lib_name.Local.decode_loc
and+ public =
field_o "public_name" (Public_lib.decode ~allow_deprecated_names:false)
Expand All @@ -585,7 +600,6 @@ module Library = struct
field "modes" Mode_conf.Set.decode
~default:(Mode_conf.Set.default stanza_loc)
and+ kind = field "kind" Lib_kind.decode ~default:Lib_kind.Normal
and+ wrapped = Wrapped.field
and+ optional = field_b "optional"
and+ no_dynlink = field_b "no_dynlink"
and+ () =
Expand Down Expand Up @@ -902,13 +916,14 @@ module Library = struct
let wrapped = Some conf.wrapped in
let special_builtin_support = conf.special_builtin_support in
let instrumentation_backend = conf.instrumentation_backend in
let entry_modules = Lib_info.Source.Local in
Lib_info.create ~loc ~name ~kind ~status ~src_dir ~orig_src_dir ~obj_dir
~version ~synopsis ~main_module_name ~sub_systems ~requires
~foreign_objects ~plugins ~archives ~ppx_runtime_deps ~foreign_archives
~native_archives ~foreign_dll_files ~jsoo_runtime ~jsoo_archive
~preprocess ~enabled ~virtual_deps ~dune_version ~virtual_ ~implements
~default_implementation ~modes ~wrapped ~special_builtin_support
~exit_module ~instrumentation_backend
~preprocess ~enabled ~virtual_deps ~dune_version ~virtual_ ~entry_modules
~implements ~default_implementation ~modes ~wrapped
~special_builtin_support ~exit_module ~instrumentation_backend
end

module Plugin = struct
Expand Down Expand Up @@ -1347,7 +1362,7 @@ module Executables = struct

let common =
let* dune_version = Dune_lang.Syntax.get_exn Stanza.syntax in
let+ buildable = Buildable.decode ~in_library:false ~allow_re_export:false
let+ buildable = Buildable.decode Executable
and+ (_ : bool) =
field "link_executables" ~default:true
(Dune_lang.Syntax.deleted_in Stanza.syntax (1, 0) >>> bool)
Expand Down Expand Up @@ -1772,8 +1787,7 @@ module Tests = struct

let gen_parse names =
fields
(let+ buildable =
Buildable.decode ~in_library:false ~allow_re_export:false
(let+ buildable = Buildable.decode Executable
and+ link_flags = Ordered_set_lang.Unexpanded.field "link_flags"
and+ names = names
and+ package = field_o "package" Stanza_common.Pkg.decode
Expand Down
7 changes: 6 additions & 1 deletion src/dune_rules/dune_file.mli
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@ module Js_of_ocaml : sig
val default : t
end

type for_ =
| Executable
| Library of Wrapped.t option

module Lib_deps : sig
type nonrec t = Lib_dep.t list

val of_pps : Lib_name.t list -> t

val info : t -> kind:Lib_deps_info.Kind.t -> Lib_deps_info.t

val decode : allow_re_export:bool -> t Dune_lang.Decoder.t
val decode : for_ -> t Dune_lang.Decoder.t
end

(** [preprocess] and [preprocessor_deps] fields *)
Expand All @@ -49,6 +53,7 @@ module Buildable : sig
; flags : Ocaml_flags.Spec.t
; js_of_ocaml : Js_of_ocaml.t
; allow_overlapping_dependencies : bool
; root_module : (Loc.t * Module_name.t) option
}

(** Check if the buildable has any foreign stubs or archives. *)
Expand Down
18 changes: 10 additions & 8 deletions src/dune_rules/dune_package.ml
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ module Lib = struct
and+ orig_src_dir = field_o "orig_src_dir" path
and+ modules =
let src_dir = Obj_dir.dir obj_dir in
field_o "modules"
field "modules"
(Modules.decode
~implements:(Option.is_some implements)
~src_dir ~version:lang.version)
Expand All @@ -153,6 +153,9 @@ module Lib = struct
field_o "instrumentation.backend" (located Lib_name.decode)
in
let modes = Mode.Dict.Set.of_list modes in
let entry_modules =
Modules.entry_modules modules |> List.map ~f:Module.name
in
let info : Path.t Lib_info.t =
let src_dir = Obj_dir.dir obj_dir in
let enabled = Lib_info.Enabled_status.Normal in
Expand All @@ -170,25 +173,24 @@ module Lib = struct
let dune_version = None in
let virtual_ =
if virtual_ then
let modules = Option.value_exn modules in
Some (Lib_info.Source.External modules)
else
None
in
let wrapped =
Option.map modules ~f:Modules.wrapped
|> Option.map ~f:(fun w -> Lib_info.Inherited.This w)
Some (Lib_info.Inherited.This (Modules.wrapped modules))
in
let entry_modules = Lib_info.Source.External (Ok entry_modules) in
Lib_info.create ~loc ~name ~kind ~status ~src_dir ~orig_src_dir
~obj_dir ~version ~synopsis ~main_module_name ~sub_systems ~requires
~foreign_objects ~plugins ~archives ~ppx_runtime_deps
~foreign_archives ~native_archives ~foreign_dll_files:[]
~jsoo_runtime ~jsoo_archive ~preprocess ~enabled ~virtual_deps
~dune_version ~virtual_ ~implements ~default_implementation ~modes
~wrapped ~special_builtin_support ~exit_module:None
~instrumentation_backend
~dune_version ~virtual_ ~entry_modules ~implements
~default_implementation ~modes ~wrapped ~special_builtin_support
~exit_module:None ~instrumentation_backend
in
{ info; main_module_name; modules })
{ info; main_module_name; modules = Some modules })

let modules t = t.modules

Expand Down
Loading

0 comments on commit 5cf80f1

Please sign in to comment.