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

Mangle compilation units of dune generated modules #2364

Merged
merged 5 commits into from
Jul 9, 2019
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
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
- Change `implicit_transive_deps` to be false. Implicit transitive deps now must
be manually enabled (#2306, @rgrinberg)

- Compilation units of user defined executables are now mangled by default. This
is done to prevent the accidental collision with library dependencies of the
executable. (#2364, fixes #2292, @rgrinberg)

1.11.0 (unreleased)
-------------------

Expand Down
16 changes: 16 additions & 0 deletions doc/advanced-topics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,19 @@ this the default mode eventually.
Note that you must use ``threads.posix`` instead of ``threads`` when using this
mode. This is not an important limitation as ``threads.vm`` are deprecated
anyways.

Name Mangling of Executables
============================

Executables are made of compilation units whose names may collide with the
compilation units of libraries. To avoid this possibility, dune prefixes these
compilation unit names with ``Dune__exe__``. This is entirely transparent to
users except for when such executables are debugged. In which case the mangled
names will be visible in the debugger.

Starting from dune 1.11, the ``(wrapped_executables <bool>)`` option is
available to turn on/off name mangling for executables on a per project basis.

Starting from dune 2.0, dune mangles compilation units of executables by
default. However, this can still be turned off using ``(wrapped_executables
false)``
1 change: 1 addition & 0 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

(implicit_transitive_deps false)
(generate_opam_files true)
(wrapped_executables true)

(license MIT)
(maintainers "Jane Street Group, LLC <opensource@janestreet.com>")
Expand Down
2 changes: 1 addition & 1 deletion src/cinaps.ml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ let gen_rules sctx t ~dir ~scope ~dir_kind =
~dir_kind
in
let modules =
Modules.exe modules
Modules.exe_unwrapped modules
|> Modules.map_user_written ~f:(Preprocessing.pp_module preprocess)
in

Expand Down
17 changes: 13 additions & 4 deletions src/dir_contents.ml
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,12 @@ let modules_of_library t ~name =
let map = (Memo.Lazy.force t.modules).libraries in
Lib_name.Map.find_exn map name

let modules_of_executables t ~first_exe =
let modules_of_executables t ~obj_dir ~first_exe =
let map = (Memo.Lazy.force t.modules).executables in
(* we need to relocate the alias module to its own directory. *)
let src_dir = Path.build (Obj_dir.obj_dir obj_dir) in
String.Map.find_exn map first_exe
|> Modules.relocate_alias_module ~src_dir

let c_sources_of_library t ~name =
C_sources.for_lib (Memo.Lazy.force t.c_sources) ~name
Expand Down Expand Up @@ -272,8 +275,7 @@ end = struct
lib.private_modules)
in
Left ( lib
, let src_dir = Path.build src_dir in
Modules.lib ~lib ~src_dir ~modules ~main_module_name ~wrapped
, Modules.lib ~lib ~src_dir ~modules ~main_module_name ~wrapped
)
| Executables exes
| Tests { exes; _} ->
Expand All @@ -283,7 +285,14 @@ end = struct
~kind:Modules_field_evaluator.Exe_or_normal_lib
~private_modules:Ordered_set_lang.standard
in
Right (exes, Modules.exe modules)
let modules =
let project = Scope.project scope in
if Dune_project.wrapped_executables project then
Modules.exe_wrapped ~src_dir:d.ctx_dir ~modules
else
Modules.exe_unwrapped modules
in
Right (exes, modules)
| _ -> Skip)
in
let libraries =
Expand Down
6 changes: 5 additions & 1 deletion src/dir_contents.mli
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ val modules_of_library : t -> name:Lib_name.t -> Modules.t
val c_sources_of_library : t -> name:Lib_name.t -> C.Sources.t

(** Modules attached to a set of executables. *)
val modules_of_executables : t -> first_exe:string -> Modules.t
val modules_of_executables
: t
-> obj_dir:Path.Build.t Obj_dir.t
-> first_exe:string
-> Modules.t

(** Find out what buildable a module is part of *)
val lookup_module : t -> Module.Name.t -> Dune_file.Buildable.t option
Expand Down
48 changes: 21 additions & 27 deletions src/dune_project.ml
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ type t =
; extension_args : Univ_map.t
; parsing_context : Univ_map.t
; implicit_transitive_deps : bool
; wrapped_executables : bool
; dune_version : Syntax.Version.t
; allow_approx_merlin : bool
; generate_opam_files : bool
Expand Down Expand Up @@ -220,7 +221,7 @@ let to_dyn
; homepage ; documentation ; project_file ; parsing_context = _
; bug_reports ; maintainers
; extension_args = _; stanza_parser = _ ; packages
; implicit_transitive_deps ; dune_version
; implicit_transitive_deps ; wrapped_executables ; dune_version
; allow_approx_merlin ; generate_opam_files } =
let open Dyn.Encoder in
record
Expand All @@ -240,6 +241,7 @@ let to_dyn
(Package.Name.Map.to_list packages)
; "implicit_transitive_deps",
bool implicit_transitive_deps
; "wrapped_executables", bool wrapped_executables
; "dune_version", Syntax.Version.to_dyn dune_version
; "allow_approx_merlin", bool allow_approx_merlin
; "generate_opam_files", bool generate_opam_files
Expand Down Expand Up @@ -490,31 +492,7 @@ let interpret_lang_and_extensions ~(lang : Lang.Instance.t)
(parsing_context, stanza_parser, extension_args)

let key =
Univ_map.Key.create ~name:"dune-project"
(fun { name; root; version; project_file; source
; license; authors; homepage; documentation ; bug_reports ; maintainers
; stanza_parser = _; packages = _ ; extension_args = _
; parsing_context ; implicit_transitive_deps ; dune_version
; allow_approx_merlin ; generate_opam_files } ->
let open Dyn.Encoder in
record
[ "name", Name.to_dyn name
; "root", Path.Source.to_dyn root
; "license", (option string) license
; "authors", (list string) authors
; "source", Dyn.Encoder.(option Source_kind.to_dyn) source
; "version", (option string) version
; "homepage", (option string) homepage
; "documentation", (option string) documentation
; "bug_reports", (option string) bug_reports
; "maintainers", (list string) maintainers
; "project_file", Project_file.to_dyn project_file
; "parsing_context", Univ_map.to_dyn parsing_context
; "implicit_transitive_deps", bool implicit_transitive_deps
; "dune_version", Syntax.Version.to_dyn dune_version
; "allow_approx_merlin", bool allow_approx_merlin
; "generate_opam_files", bool generate_opam_files
])
Univ_map.Key.create ~name:"dune-project" to_dyn

let set t = Dune_lang.Decoder.set key t
let get_exn () =
Expand All @@ -529,6 +507,9 @@ let filename = "dune-project"
let implicit_transitive_deps_default ~(lang : Lang.Instance.t) =
lang.version < (2, 0)

let wrapped_executables_default ~(lang : Lang.Instance.t) =
lang.version >= (2, 0)

let anonymous = lazy (
let lang = get_dune_lang () in
let name = Name.anonymous_root in
Expand All @@ -543,6 +524,7 @@ let anonymous = lazy (
interpret_lang_and_extensions ~lang ~explicit_extensions:[] ~project_file
in
let implicit_transitive_deps = implicit_transitive_deps_default ~lang in
let wrapped_executables = wrapped_executables_default ~lang in
{ name = name
; packages = Package.Name.Map.empty
; root = Path.Source.root
Expand All @@ -555,6 +537,7 @@ let anonymous = lazy (
; authors = []
; version = None
; implicit_transitive_deps
; wrapped_executables
; stanza_parser
; project_file
; extension_args
Expand Down Expand Up @@ -618,6 +601,9 @@ let parse ~dir ~lang ~opam_packages ~file =
and+ implicit_transitive_deps =
field_o_b "implicit_transitive_deps"
~check:(Syntax.since Stanza.syntax (1, 7))
and+ wrapped_executables =
field_o_b "wrapped_executables"
~check:(Syntax.since Stanza.syntax (1, 11))
and+ allow_approx_merlin =
field_o_b "allow_approximate_merlin"
~check:(Syntax.since Stanza.syntax (1, 9))
Expand Down Expand Up @@ -701,9 +687,13 @@ let parse ~dir ~lang ~opam_packages ~file =
Option.value implicit_transitive_deps
~default:(implicit_transitive_deps_default ~lang)
in
let wrapped_executables =
Option.value wrapped_executables
~default:(wrapped_executables_default ~lang) in
let allow_approx_merlin =
Option.value ~default:false allow_approx_merlin in
let generate_opam_files = Option.value ~default:false generate_opam_files in
let generate_opam_files =
Option.value ~default:false generate_opam_files in
{ name
; root = dir
; version
Expand All @@ -720,6 +710,7 @@ let parse ~dir ~lang ~opam_packages ~file =
; extension_args
; parsing_context
; implicit_transitive_deps
; wrapped_executables
; dune_version = lang.version
; allow_approx_merlin
; generate_opam_files
Expand Down Expand Up @@ -765,6 +756,7 @@ let make_jbuilder_project ~dir opam_packages =
; dune_version = lang.version
; allow_approx_merlin = true
; generate_opam_files = false
; wrapped_executables = false
}

let load ~dir ~files =
Expand Down Expand Up @@ -824,3 +816,5 @@ let dune_version t = t.dune_version

let set_parsing_context t parser =
Dune_lang.Decoder.set_many t.parsing_context parser

let wrapped_executables t = t.wrapped_executables
2 changes: 2 additions & 0 deletions src/dune_project.mli
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,5 @@ val set_parsing_context : t -> 'a Dune_lang.Decoder.t -> 'a Dune_lang.Decoder.t
val implicit_transitive_deps : t -> bool

val dune_version : t -> Syntax.Version.t

val wrapped_executables : t -> bool
13 changes: 11 additions & 2 deletions src/exe_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let executables_rules ~sctx ~dir ~dir_kind ~expander
Check_rules.add_obj_dir sctx ~obj_dir;
let modules =
Dir_contents.modules_of_executables dir_contents
~first_exe:(snd (List.hd exes.names))
~first_exe:(snd (List.hd exes.names)) ~obj_dir
in

let preprocessor_deps =
Expand Down Expand Up @@ -117,6 +117,15 @@ let executables_rules ~sctx ~dir ~dir_kind ~expander
~link_flags
~promote:exes.promote;

let flags =
match Modules.alias_module modules with
| None -> Ocaml_flags.common flags
| Some m ->
Ocaml_flags.prepend_common
["-open"; Module.Name.to_string (Module.name m)] flags
|> Ocaml_flags.common
in

(cctx,
let objs_dirs =
Obj_dir.public_cmi_dir obj_dir
Expand All @@ -125,7 +134,7 @@ let executables_rules ~sctx ~dir ~dir_kind ~expander
in
Merlin.make ()
~requires:requires_compile
~flags:(Ocaml_flags.common flags)
~flags
~preprocess:(Dune_file.Buildable.single_preprocess exes.buildable)
(* only public_dir? *)
~objs_dirs)
Expand Down
22 changes: 12 additions & 10 deletions src/inline_tests.ml
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ module Backend = struct
let f x = Lib_name.encode (Lib.name x.lib) in
((1, 0),
record_fields @@
[ field_l "runner_libraries" lib (Result.ok_exn t.runner_libraries)
; field_i "flags" Ordered_set_lang.Unexpanded.encode_and_upgrade
t.info.flags
; field_o "generate_runner" Action_dune_lang.encode_and_upgrade
(Option.map t.info.generate_runner ~f:snd)
; field_l "extends" f (Result.ok_exn t.extends)
])
[ field_l "runner_libraries" lib (Result.ok_exn t.runner_libraries)
; field_i "flags" Ordered_set_lang.Unexpanded.encode_and_upgrade
t.info.flags
; field_o "generate_runner" Action_dune_lang.encode_and_upgrade
(Option.map t.info.generate_runner ~f:snd)
; field_l "extends" f (Result.ok_exn t.extends)
])
end
include M
include Sub_system.Register_backend(M)
Expand Down Expand Up @@ -207,8 +207,10 @@ include Sub_system.Register_end_point(

let loc = lib.buildable.loc in

let lib_name = snd lib.name in

let inline_test_name =
sprintf "%s.inline-tests" (Lib_name.Local.to_string (snd lib.name))
sprintf "%s.inline-tests" (Lib_name.Local.to_string lib_name)
in

let inline_test_dir = Path.Build.relative dir ("." ^ inline_test_name) in
Expand All @@ -224,7 +226,7 @@ include Sub_system.Register_end_point(
Module.generated ~src_dir name
in

let modules = Modules.singleton main_module in
let modules = Modules.singleton_exe main_module in

let bindings =
Pform.Map.singleton "library-name"
Expand Down Expand Up @@ -367,6 +369,6 @@ include Sub_system.Register_end_point(
|> List.map ~f:(fun fn ->
A.diff ~optional:true
fn (Path.extend_basename fn ~suffix:".corrected"))))))))
end)
end)

let linkme = ()
3 changes: 2 additions & 1 deletion src/link_time_code_gen.ml
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ let generate_and_compile_module cctx ~precompiled_cmi ~name:basename
Ocaml_version.supports_opaque_for_mli
(Super_context.context sctx).version
in
let modules = Modules.singleton_exe module_ in
let cctx =
Compilation_context.create
~super_context:sctx
~expander:(Compilation_context.expander cctx)
~scope:(Compilation_context.scope cctx)
~dir_kind:(Compilation_context.dir_kind cctx)
~obj_dir
~modules:(Modules.singleton module_)
~modules
~requires_compile:requires
~requires_link:(lazy requires)
~flags:Ocaml_flags.empty
Expand Down
40 changes: 20 additions & 20 deletions src/menhir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -215,27 +215,27 @@ module Run (P : PARAMS) : sig end = struct
Module.of_source ~visibility:Public ~kind:Impl source
in

(* The following incantation allows the mock [.ml] file to be preprocessed
by the user-specified [ppx] rewriters. *)

let mock_module =
Preprocessing.pp_module_as
(Compilation_context.preprocessing cctx)
name
mock_module
~lint:false
in

let dep_graphs =
let modules = Modules.singleton mock_module in
Ocamldep.rules cctx ~modules
let modules =
(* The following incantation allows the mock [.ml] file to be preprocessed
by the user-specified [ppx] rewriters. *)

let mock_module =
Preprocessing.pp_module_as
(Compilation_context.preprocessing cctx)
name
mock_module
~lint:false
in
Modules.singleton_exe mock_module
in

Module_compilation.ocamlc_i
~dep_graphs
cctx
mock_module
~output:(inferred_mli base);
let dep_graphs = Ocamldep.rules cctx ~modules in

Modules.iter_no_vlib modules ~f:(fun m ->
Module_compilation.ocamlc_i
~dep_graphs
cctx
m
~output:(inferred_mli base));

(* 3. A second invocation of Menhir reads the inferred [.mli] file. *)

Expand Down
1 change: 1 addition & 0 deletions src/module.ml
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ let generated ~src_dir name =
source

let generated_alias ~src_dir name =
let src_dir = Path.build src_dir in
let t = generated ~src_dir name in
{ t with kind = Alias }

Expand Down
Loading