From 9f8803af6767ac9e52714a7b41f4ddd06bec16e6 Mon Sep 17 00:00:00 2001 From: Jeremie Dimino Date: Mon, 29 May 2017 14:06:52 +0100 Subject: [PATCH] Add (modes ...) for executables --- doc/jbuild.rst | 10 ++++++++-- src/gen_rules.ml | 19 ++++++++++--------- src/jbuild_types.ml | 16 +++++++++++++--- src/mode.ml | 28 ++++++++++++++++++++++++++++ src/mode.mli | 10 ++++++++++ src/module_compilation.ml | 3 ++- 6 files changed, 71 insertions(+), 15 deletions(-) diff --git a/doc/jbuild.rst b/doc/jbuild.rst index 06298e81..e82dde17 100644 --- a/doc/jbuild.rst +++ b/doc/jbuild.rst @@ -205,10 +205,11 @@ the ``ocamlrun`` virtual machine as well as the byte code. As such you can always rely on ``.exe`` being available. Native compilation is considered not available when there is no -``ocamlopt`` binary at the same place as where ``ocamlc`` was found. +``ocamlopt`` binary at the same place as where ``ocamlc`` was found, +or when there is a ``(modes (...))`` field not listing ``native``. ```` are: - +0 - ``(public_name )`` specifies that the executable should be installed under that name. It is the same as adding the following stanza to your ``jbuild`` file: @@ -231,6 +232,11 @@ Native compilation is considered not available when there is no the current stanza. It is interpreted in the same way as the ``(modules ...)`` field of `library`_ +- ``(modes ())`` modes (``byte`` and ``native``) which should be built by + default. If the stanza has a ``(public_name ...)`` field and + ``native`` is not listed here, the byte-code version will be + installed instead. + - ``(preprocess )`` is the same as the ``(preprocess ...)`` field of `library`_ diff --git a/src/gen_rules.ml b/src/gen_rules.ml index e375f67f..94d3254c 100644 --- a/src/gen_rules.ml +++ b/src/gen_rules.ml @@ -306,8 +306,8 @@ module Gen(P : Params) = struct in let static = stubs_archive lib ~dir in let dynamic = dll lib ~dir in - if List.mem Mode.Native ~set:lib.modes && - List.mem Mode.Byte ~set:lib.modes && + if lib.modes.native && + lib.modes.byte && lib.dynlink then begin (* If we build for both modes and support dynlink, use a single invocation to @@ -384,12 +384,13 @@ module Gen(P : Params) = struct | Executables stuff | +-----------------------------------------------------------------+ *) - let build_exe ~js_of_ocaml ~flags ~dir ~requires ~name ~mode ~modules ~dep_graph ~link_flags = + let build_exe ~js_of_ocaml ~flags ~dir ~requires ~name ~mode ~modules ~dep_graph + ~link_flags ~force_custom_bytecode = let exe_ext = Mode.exe_ext mode in let mode, link_flags, compiler = - match Context.compiler ctx mode with - | Some compiler -> (mode, link_flags, compiler) - | None -> (Byte, "-custom" :: link_flags, ctx.ocamlc) + match force_custom_bytecode, Context.compiler ctx mode with + | false, Some compiler -> (mode, link_flags, compiler) + | _ -> (Byte, "-custom" :: link_flags, ctx.ocamlc) in let dep_graph = Ml_kind.Dict.get dep_graph Impl in let exe = Path.relative dir (name ^ exe_ext) in @@ -462,7 +463,8 @@ module Gen(P : Params) = struct List.iter exes.names ~f:(fun name -> List.iter Mode.all ~f:(fun mode -> build_exe ~js_of_ocaml:exes.buildable.js_of_ocaml ~flags ~dir ~requires ~name - ~mode ~modules ~dep_graph ~link_flags:exes.link_flags)); + ~mode ~modules ~dep_graph ~link_flags:exes.link_flags + ~force_custom_bytecode:(mode = Native && not exes.modes.native))); { Merlin. requires = real_requires ; flags = flags.common @@ -770,8 +772,7 @@ module Gen(P : Params) = struct Install.Entry.make section fn ?dst:(Option.map sub_dir ~f:(fun d -> sprintf "%s/%s" d (Path.basename fn))) in - let byte = List.mem Mode.Byte ~set:lib.modes in - let native = List.mem Mode.Native ~set:lib.modes in + let { Mode.Dict. byte; native } = lib.modes in let if_ cond l = if cond then l else [] in let files = let modules = diff --git a/src/jbuild_types.ml b/src/jbuild_types.ml index 4252a3c4..2b6bb3b6 100644 --- a/src/jbuild_types.ml +++ b/src/jbuild_types.ml @@ -512,7 +512,7 @@ module Library = struct ; synopsis : string option ; install_c_headers : string list ; ppx_runtime_libraries : string list - ; modes : Mode.t list + ; modes : Mode.Dict.Set.t ; kind : Kind.t ; c_flags : Ordered_set_lang.Unexpanded.t ; c_names : string list @@ -544,7 +544,7 @@ module Library = struct field "library_flags" (list String_with_vars.t) ~default:[] >>= fun library_flags -> field_oslu "c_library_flags" >>= fun c_library_flags -> field "virtual_deps" (list string) ~default:[] >>= fun virtual_deps -> - field "modes" (list Mode.t) ~default:Mode.all >>= fun modes -> + field "modes" Mode.Dict.Set.t ~default:Mode.Dict.Set.all >>= fun modes -> field "kind" Kind.t ~default:Kind.Normal >>= fun kind -> field "wrapped" bool ~default:true >>= fun wrapped -> field_b "optional" >>= fun optional -> @@ -623,6 +623,7 @@ module Executables = struct { names : string list ; link_executables : bool ; link_flags : string list + ; modes : Mode.Dict.Set.t ; buildable : Buildable.t } @@ -630,19 +631,28 @@ module Executables = struct Buildable.v1 >>= fun buildable -> field "link_executables" bool ~default:true >>= fun link_executables -> field "link_flags" (list string) ~default:[] >>= fun link_flags -> + map_validate (field "modes" Mode.Dict.Set.t ~default:Mode.Dict.Set.all) + ~f:(fun modes -> + if Mode.Dict.Set.is_empty modes then + Error "No compilation mode defined." + else + Ok modes) + >>= fun modes -> let t = { names ; link_executables ; link_flags + ; modes ; buildable } in let to_install = + let ext = if modes.native then ".exe" else ".bc" in List.map2 names public_names ~f:(fun name pub -> match pub with | None -> None - | Some pub -> Some ({ Install_conf. src = name ^ ".exe"; dst = Some pub })) + | Some pub -> Some ({ Install_conf. src = name ^ ext; dst = Some pub })) |> List.filter_map ~f:(fun x -> x) in match to_install with diff --git a/src/mode.ml b/src/mode.ml index 5ba79ac9..af929064 100644 --- a/src/mode.ml +++ b/src/mode.ml @@ -47,4 +47,32 @@ module Dict = struct { byte = f a.byte b.byte ; native = f a.native b.native } + + module Set = struct + type nonrec t = bool t + + let all = + { byte = true + ; native = true + } + + let to_list t = + let l = [] in + let l = if t.native then Native :: l else l in + let l = if t.byte then Byte :: l else l in + l + + let of_list l = + { byte = List.mem Byte ~set:l + ; native = List.mem Native ~set:l + } + + let t sexp = of_list (Sexp.Of_sexp.list t sexp) + + let is_empty t = not (t.byte || t.native) + + let iter t ~f = + if t.byte then f Byte; + if t.native then f Native + end end diff --git a/src/mode.mli b/src/mode.mli index ec027631..e37ec9b7 100644 --- a/src/mode.mli +++ b/src/mode.mli @@ -28,4 +28,14 @@ module Dict : sig val of_func : (mode:mode -> 'a) -> 'a t val map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + + module Set : sig + type nonrec t = bool t + val t : t Sexp.Of_sexp.t + val all : t + val is_empty : t -> bool + val to_list : t -> mode list + val of_list : mode list -> t + val iter : t -> f:(mode -> unit) -> unit + end end with type mode := t diff --git a/src/module_compilation.ml b/src/module_compilation.ml index e169918d..b4c62296 100644 --- a/src/module_compilation.ml +++ b/src/module_compilation.ml @@ -88,7 +88,8 @@ let build_module sctx ?sandbox ~dynlink ~js_of_ocaml ~flags m ~dir ~dep_graph let src = Module.cm_file m ~dir Cm_kind.Cmo in SC.add_rules sctx (Js_of_ocaml_rules.build_cm sctx ~dir ~js_of_ocaml ~src) -let build_modules sctx ~dynlink ~js_of_ocaml ~flags ~dir ~dep_graph ~modules ~requires ~alias_module = +let build_modules sctx ~dynlink ~js_of_ocaml ~flags ~dir ~dep_graph ~modules ~requires + ~alias_module = let cmi_requires = Build.memoize "cmi library dependencies" (requires