From 9c2e4f14e005efec59779e64e0bb8301d56772ac Mon Sep 17 00:00:00 2001 From: Etienne Millon Date: Thu, 31 May 2018 10:09:24 +0200 Subject: [PATCH 1/2] Display an error when no installable mode is found If an executable is only available as a shared object for example, Dune cannot install it. In that case, it displays an error message. However, it is still possible to build a private one explicitly. Signed-off-by: Etienne Millon --- src/jbuild.ml | 8 ++++++++ test/blackbox-tests/dune.inc | 11 +++++++++++ .../no-installable-mode/private/jbuild | 8 ++++++++ .../no-installable-mode/private/myprivatelib.ml | 0 .../test-cases/no-installable-mode/public/jbuild | 9 +++++++++ .../no-installable-mode/public/mylib.ml | 0 .../no-installable-mode/public/mypackage.opam | 0 .../test-cases/no-installable-mode/run.t | 16 ++++++++++++++++ 8 files changed, 52 insertions(+) create mode 100644 test/blackbox-tests/test-cases/no-installable-mode/private/jbuild create mode 100644 test/blackbox-tests/test-cases/no-installable-mode/private/myprivatelib.ml create mode 100644 test/blackbox-tests/test-cases/no-installable-mode/public/jbuild create mode 100644 test/blackbox-tests/test-cases/no-installable-mode/public/mylib.ml create mode 100644 test/blackbox-tests/test-cases/no-installable-mode/public/mypackage.opam create mode 100644 test/blackbox-tests/test-cases/no-installable-mode/run.t diff --git a/src/jbuild.ml b/src/jbuild.ml index d5c3b264..70a41a26 100644 --- a/src/jbuild.ml +++ b/src/jbuild.ml @@ -879,8 +879,16 @@ module Executables = struct ; buildable } in + let has_public_name = + List.exists ~f:Option.is_some public_names + in let to_install = match Link_mode.Set.best_install_mode t.modes with + | None when has_public_name -> + Loc.fail + buildable.loc + "No installable mode found for %s." + (if multi then "these executables" else "this executable") | None -> [] | Some mode -> let ext = diff --git a/test/blackbox-tests/dune.inc b/test/blackbox-tests/dune.inc index 0af19fcf..62c146f7 100644 --- a/test/blackbox-tests/dune.inc +++ b/test/blackbox-tests/dune.inc @@ -372,6 +372,15 @@ (run ${exe:cram.exe} -skip-versions 4.02.3 -test run.t) (diff? run.t run.t.corrected)))))) +(alias + ((name no-installable-mode) + (deps + ((package dune) (files_recursively_in test-cases/no-installable-mode))) + (action + (chdir + test-cases/no-installable-mode + (progn (run ${exe:cram.exe} -test run.t) (diff? run.t run.t.corrected)))))) + (alias ((name null-dep) (deps ((package dune) (files_recursively_in test-cases/null-dep))) @@ -579,6 +588,7 @@ (alias meta-gen) (alias misc) (alias multiple-private-libs) + (alias no-installable-mode) (alias null-dep) (alias ocaml-syntax) (alias ocamldep-multi-stanzas) @@ -639,6 +649,7 @@ (alias merlin-tests) (alias meta-gen) (alias misc) + (alias no-installable-mode) (alias null-dep) (alias ocaml-syntax) (alias ocamldep-multi-stanzas) diff --git a/test/blackbox-tests/test-cases/no-installable-mode/private/jbuild b/test/blackbox-tests/test-cases/no-installable-mode/private/jbuild new file mode 100644 index 00000000..3eb43e8f --- /dev/null +++ b/test/blackbox-tests/test-cases/no-installable-mode/private/jbuild @@ -0,0 +1,8 @@ +(jbuild_version 1) + +(executable + ( + (name myprivatelib) + (modes (shared_object)) + ) + ) diff --git a/test/blackbox-tests/test-cases/no-installable-mode/private/myprivatelib.ml b/test/blackbox-tests/test-cases/no-installable-mode/private/myprivatelib.ml new file mode 100644 index 00000000..e69de29b diff --git a/test/blackbox-tests/test-cases/no-installable-mode/public/jbuild b/test/blackbox-tests/test-cases/no-installable-mode/public/jbuild new file mode 100644 index 00000000..83caf772 --- /dev/null +++ b/test/blackbox-tests/test-cases/no-installable-mode/public/jbuild @@ -0,0 +1,9 @@ +(jbuild_version 1) + +(executable + ( + (name mylib) + (public_name mylib) + (modes (shared_object)) + ) + ) diff --git a/test/blackbox-tests/test-cases/no-installable-mode/public/mylib.ml b/test/blackbox-tests/test-cases/no-installable-mode/public/mylib.ml new file mode 100644 index 00000000..e69de29b diff --git a/test/blackbox-tests/test-cases/no-installable-mode/public/mypackage.opam b/test/blackbox-tests/test-cases/no-installable-mode/public/mypackage.opam new file mode 100644 index 00000000..e69de29b diff --git a/test/blackbox-tests/test-cases/no-installable-mode/run.t b/test/blackbox-tests/test-cases/no-installable-mode/run.t new file mode 100644 index 00000000..1a30df39 --- /dev/null +++ b/test/blackbox-tests/test-cases/no-installable-mode/run.t @@ -0,0 +1,16 @@ +When a public executable is built in shared_object mode, a specific error +message is displayed: + + $ dune build --root=public --display=short + File "jbuild", line 4, characters 2-74: + Error: No installable mode found for this executable. + [1] + +However, it is possible to build a private one explicitly. + + $ dune build --root=private --display=short myprivatelib.so + Entering directory 'private' + ocamldep myprivatelib.ml.d + ocamlc .myprivatelib.eobjs/myprivatelib.{cmi,cmo,cmt} + ocamlopt .myprivatelib.eobjs/myprivatelib.{cmx,o} + ocamlopt myprivatelib$ext_dll From 673397a1b9069e988eaf563271145c45e46a69e4 Mon Sep 17 00:00:00 2001 From: Etienne Millon Date: Wed, 6 Jun 2018 15:48:37 +0200 Subject: [PATCH 2/2] Display the installable modes Signed-off-by: Etienne Millon --- src/binary_kind.ml | 11 +++ src/binary_kind.mli | 4 ++ src/jbuild.ml | 62 ++++++++++++----- src/jbuild.mli | 4 ++ .../test-cases/no-installable-mode/run.t | 4 ++ test/unit-tests/dune | 10 +++ test/unit-tests/jbuild.mlt | 67 +++++++++++++++++++ 7 files changed, 145 insertions(+), 17 deletions(-) create mode 100644 test/unit-tests/jbuild.mlt diff --git a/src/binary_kind.ml b/src/binary_kind.ml index 78174f49..c209eda9 100644 --- a/src/binary_kind.ml +++ b/src/binary_kind.ml @@ -13,4 +13,15 @@ let t = ; "shared_object" , Shared_object ] +let to_string = function + | Exe -> "exe" + | Object -> "object" + | Shared_object -> "shared_object" + +let pp fmt t = + Format.pp_print_string fmt (to_string t) + +let sexp_of_t t = + Sexp.unsafe_atom_of_string (to_string t) + let all = [Exe; Object; Shared_object] diff --git a/src/binary_kind.mli b/src/binary_kind.mli index 707188b4..b389c80d 100644 --- a/src/binary_kind.mli +++ b/src/binary_kind.mli @@ -9,4 +9,8 @@ type t = val t : t Sexp.Of_sexp.t +val sexp_of_t : t Sexp.To_sexp.t + val all : t list + +val pp : Format.formatter -> t -> unit diff --git a/src/jbuild.ml b/src/jbuild.ml index 70a41a26..f35200c2 100644 --- a/src/jbuild.ml +++ b/src/jbuild.ml @@ -608,6 +608,17 @@ module Mode_conf = struct ; "best" , Best ] + let to_string = function + | Byte -> "byte" + | Native -> "native" + | Best -> "best" + + let pp fmt t = + Format.pp_print_string fmt (to_string t) + + let sexp_of_t t = + Sexp.unsafe_atom_of_string (to_string t) + module Set = struct include Set.Make(T) @@ -796,15 +807,19 @@ module Executables = struct let byte = byte_exe let native = native_exe + let installable_modes = + [exe; native; byte] + + let simple_representations = + [ "exe" , exe + ; "object" , object_ + ; "shared_object" , shared_object + ; "byte" , byte + ; "native" , native + ] + let simple = - let open Sexp.Of_sexp in - enum - [ "exe" , exe - ; "object" , object_ - ; "shared_object" , shared_object - ; "byte" , byte - ; "native" , native - ] + Sexp.Of_sexp.enum simple_representations let t sexp = match sexp with @@ -813,6 +828,21 @@ module Executables = struct { mode; kind } | _ -> simple sexp + let simple_sexp_of_t link_mode = + let is_ok (_, candidate) = + compare candidate link_mode = Eq + in + match List.find ~f:is_ok simple_representations with + | Some (s, _) -> Some (Sexp.unsafe_atom_of_string s) + | None -> None + + let sexp_of_t link_mode = + match simple_sexp_of_t link_mode with + | Some s -> s + | None -> + let { mode; kind } = link_mode in + Sexp.To_sexp.pair Mode_conf.sexp_of_t Binary_kind.sexp_of_t (mode, kind) + module Set = struct include Set.Make(T) @@ -837,14 +867,7 @@ module Executables = struct ] let best_install_mode t = - if mem t exe then - Some exe - else if mem t native then - Some native - else if mem t byte then - Some byte - else - None + List.find ~f:(mem t) installable_modes end end @@ -885,10 +908,15 @@ module Executables = struct let to_install = match Link_mode.Set.best_install_mode t.modes with | None when has_public_name -> + let mode_to_string mode = " - " ^ Sexp.to_string (Link_mode.sexp_of_t mode) in + let mode_strings = List.map ~f:mode_to_string Link_mode.installable_modes in Loc.fail buildable.loc - "No installable mode found for %s." + "No installable mode found for %s.\n\ + One of the following modes is required:\n\ + %s" (if multi then "these executables" else "this executable") + (String.concat ~sep:"\n" mode_strings) | None -> [] | Some mode -> let ext = diff --git a/src/jbuild.mli b/src/jbuild.mli index 19b9e2cf..2ccac89d 100644 --- a/src/jbuild.mli +++ b/src/jbuild.mli @@ -171,6 +171,7 @@ module Mode_conf : sig val t : t Sexp.Of_sexp.t val compare : t -> t -> Ordering.t + val pp : Format.formatter -> t -> unit module Set : sig include Set.S with type elt = t @@ -240,6 +241,9 @@ module Executables : sig ; kind : Binary_kind.t } + val t : t Sexp.Of_sexp.t + val sexp_of_t : t Sexp.To_sexp.t + val exe : t val object_ : t val shared_object : t diff --git a/test/blackbox-tests/test-cases/no-installable-mode/run.t b/test/blackbox-tests/test-cases/no-installable-mode/run.t index 1a30df39..3c542077 100644 --- a/test/blackbox-tests/test-cases/no-installable-mode/run.t +++ b/test/blackbox-tests/test-cases/no-installable-mode/run.t @@ -4,6 +4,10 @@ message is displayed: $ dune build --root=public --display=short File "jbuild", line 4, characters 2-74: Error: No installable mode found for this executable. + One of the following modes is required: + - exe + - native + - byte [1] However, it is possible to build a private one explicitly. diff --git a/test/unit-tests/dune b/test/unit-tests/dune index 8fa30a6d..adc1fdf5 100644 --- a/test/unit-tests/dune +++ b/test/unit-tests/dune @@ -79,3 +79,13 @@ (progn (run ${exe:expect_test.exe} ${<}) (diff? ${<} ${<}.corrected)))))) + +(alias + ((name runtest) + (deps (jbuild.mlt + (glob_files ${SCOPE_ROOT}/src/.dune.objs/*.cmi) + (glob_files ${SCOPE_ROOT}/src/stdune/.stdune.objs/*.cmi))) + (action (chdir ${SCOPE_ROOT} + (progn + (run ${exe:expect_test.exe} ${<}) + (diff? ${<} ${<}.corrected)))))) diff --git a/test/unit-tests/jbuild.mlt b/test/unit-tests/jbuild.mlt new file mode 100644 index 00000000..812a9234 --- /dev/null +++ b/test/unit-tests/jbuild.mlt @@ -0,0 +1,67 @@ +open Dune;; +open Stdune;; + +#install_printer Jbuild.Mode_conf.pp;; +#install_printer Binary_kind.pp;; +#install_printer Sexp.pp;; + +(* Jbuild.Executables.Link_mode.t *) +let test s = + Jbuild.Executables.Link_mode.t + (Sexp.parse_string ~fname:"" ~mode:Sexp.Parser.Mode.Single s) +[%%expect{| +val test : string -> Dune.Jbuild.Executables.Link_mode.t = +|}] + +(* Link modes can be read as a ( ) list *) +test "(best exe)" +[%%expect{| +- : Dune.Jbuild.Executables.Link_mode.t = +{Dune.Jbuild.Executables.Link_mode.mode = best; kind = exe} +|}] + +(* Some shortcuts also exist *) +test "exe" +[%%expect{| +- : Dune.Jbuild.Executables.Link_mode.t = +{Dune.Jbuild.Executables.Link_mode.mode = best; kind = exe} +|}] +test "object" +[%%expect{| +- : Dune.Jbuild.Executables.Link_mode.t = +{Dune.Jbuild.Executables.Link_mode.mode = best; kind = object} +|}] +test "shared_object" +[%%expect{| +- : Dune.Jbuild.Executables.Link_mode.t = +{Dune.Jbuild.Executables.Link_mode.mode = best; kind = shared_object} +|}] +test "byte" +[%%expect{| +- : Dune.Jbuild.Executables.Link_mode.t = +{Dune.Jbuild.Executables.Link_mode.mode = byte; kind = exe} +|}] +test "native" +[%%expect{| +- : Dune.Jbuild.Executables.Link_mode.t = +{Dune.Jbuild.Executables.Link_mode.mode = native; kind = exe} +|}] + +(* Jbuild.Executables.Link_mode.sexp_of_t *) +let test l = + Jbuild.Executables.Link_mode.sexp_of_t l +[%%expect{| +val test : Dune.Jbuild.Executables.Link_mode.t -> Stdune__Sexp.t = +|}] + +(* In the general case, modes are serialized as a list *) +test {Jbuild.Executables.Link_mode.kind = Shared_object; mode = Byte } +[%%expect{| +- : Stdune__Sexp.t = (byte shared_object) +|}] + +(* But the specialized ones are serialized in the minimal version *) +test Jbuild.Executables.Link_mode.exe +[%%expect{| +- : Stdune__Sexp.t = exe +|}]