diff --git a/CHANGES.md b/CHANGES.md index c21e5fc0641..ee1da98ce25 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,11 @@ unreleased - Don't reserve the `Ppx` toplevel module name for ppx rewriters (#...., @diml) +- Redesign of the library variant feature according to the #2134 proposal. The + set of variants is now computed when the virtual library is installed. + Introducing a new `external_variant` stanza. (#2169, fixes #2134, @TheLortex, + review by @diml) + 1.10.0 (04/06/2019) ------------------- diff --git a/doc/dune-files.rst b/doc/dune-files.rst index 0a16e4bf126..163e75ef3f0 100644 --- a/doc/dune-files.rst +++ b/doc/dune-files.rst @@ -983,6 +983,23 @@ run this toplevel with: $ dune exec ./tt.exe +external_variant +----------------- + +The ``external_variant`` allow to declare a tagged implementation that does not +live inside the virtual library project. + +.. code:: scheme + + (external_variant + (variant foo) + (implementation lib-foo) + (virtual_library vlib)) + +This will add `lib-foo` to the list of known implementations of `vlib`. For more +details see :ref:`dune-variants` + + Common items ============ diff --git a/doc/variants.rst b/doc/variants.rst index bc2951ad454..bb5dc1e799a 100644 --- a/doc/variants.rst +++ b/doc/variants.rst @@ -76,11 +76,13 @@ implementation for every virtual library that we've used: clock_unix ;; leaving this dependency will make dune loudly complain calendar)) +.. _dune-variants: + Variants ======== This feature is still under development and may change with new dune -releases. You need to write ``(using library_variants 0.1)`` in your +releases. You need to write ``(using library_variants 0.2)`` in your ``dune-project`` file to unlock it. When building a binary, implementations can be selected using a set of variants @@ -108,6 +110,21 @@ implementation would have the following configuration: (implements time) (variant js)) +The list of available variants is computed while building the virtual library. +This means only variant implementations that are part of the same project are +implicitely taken into account. It's possible to declare an external +implementation by using the `external_variant` stanza in the virtual library +scope. + +.. code:: scheme + + (external_variant + (variant foo) + (implementation lib-foo) + (virtual_library vlib)) + +This will add `lib-foo` to the list of known implementations of `vlib`. + Default implementation ====================== diff --git a/src/dune_file.ml b/src/dune_file.ml index 43b0a2391eb..f7f32396ffe 100644 --- a/src/dune_file.ml +++ b/src/dune_file.ml @@ -55,7 +55,7 @@ let library_variants = let syntax = Syntax.create ~name:"library_variants" ~desc:"the experimental library variants feature." - [ (0, 1) ] + [ (0, 2) ] in Dune_project.Extension.register_simple ~experimental:true syntax (Dune_lang.Decoder.return []); @@ -830,6 +830,34 @@ module Mode_conf = struct end end +module External_variant = struct + type t = + { implementation : Lib_name.t + ; virtual_lib : Lib_name.t + ; variant : Variant.t + ; project : Dune_project.t + ; loc : Loc.t + } + + let decode = + let open Stanza.Decoder in + record ( + let+ loc = loc + and+ variant = field "variant" Variant.decode + and+ virtual_lib = field "virtual_library" Lib_name.decode + and+ implementation = field "implementation" Lib_name.decode + and+ project = Dune_project.get_exn () + in + { implementation + ; virtual_lib + ; variant + ; project + ; loc + } + ) +end + + module Library = struct module Inherited = struct type 'a t = @@ -1041,7 +1069,7 @@ module Library = struct "A library cannot be both virtual and implement %s" (Lib_name.to_string impl)); match virtual_modules, default_implementation with - | None, Some (loc, _) -> + | None, (Some (loc, _)) -> of_sexp_error loc "Only virtual libraries can specify a default implementation." | _ -> (); @@ -2171,16 +2199,17 @@ module Include_subdirs = struct end type Stanza.t += - | Library of Library.t - | Executables of Executables.t - | Rule of Rule.t - | Install of File_binding.Unexpanded.t Install_conf.t - | Alias of Alias_conf.t - | Copy_files of Copy_files.t - | Documentation of Documentation.t - | Tests of Tests.t - | Include_subdirs of Loc.t * Include_subdirs.t - | Toplevel of Toplevel.t + | Library of Library.t + | Executables of Executables.t + | Rule of Rule.t + | Install of File_binding.Unexpanded.t Install_conf.t + | Alias of Alias_conf.t + | Copy_files of Copy_files.t + | Documentation of Documentation.t + | Tests of Tests.t + | Include_subdirs of Loc.t * Include_subdirs.t + | Toplevel of Toplevel.t + | External_variant of External_variant.t module Stanzas = struct type t = Stanza.t list @@ -2249,6 +2278,10 @@ module Stanzas = struct (let+ () = Syntax.since Stanza.syntax (1, 0) and+ t = Tests.single in [Tests t]) + ; "external_variant", + (let+ () = Syntax.since library_variants (0, 2) + and+ t = External_variant.decode in + [External_variant t]) ; "env", (let+ x = Dune_env.Stanza.decode in [Dune_env.T x]) diff --git a/src/dune_file.mli b/src/dune_file.mli index e60ee043b68..58602fd9f2e 100644 --- a/src/dune_file.mli +++ b/src/dune_file.mli @@ -181,6 +181,16 @@ module Mode_conf : sig end end +module External_variant : sig + type t = + { implementation : Lib_name.t + ; virtual_lib : Lib_name.t + ; variant : Variant.t + ; project : Dune_project.t + ; loc : Loc.t + } +end + module Library : sig module Inherited : sig type 'a t = @@ -467,16 +477,17 @@ module Include_subdirs : sig end type Stanza.t += - | Library of Library.t - | Executables of Executables.t - | Rule of Rule.t - | Install of File_binding.Unexpanded.t Install_conf.t - | Alias of Alias_conf.t - | Copy_files of Copy_files.t - | Documentation of Documentation.t - | Tests of Tests.t - | Include_subdirs of Loc.t * Include_subdirs.t - | Toplevel of Toplevel.t + | Library of Library.t + | Executables of Executables.t + | Rule of Rule.t + | Install of File_binding.Unexpanded.t Install_conf.t + | Alias of Alias_conf.t + | Copy_files of Copy_files.t + | Documentation of Documentation.t + | Tests of Tests.t + | Include_subdirs of Loc.t * Include_subdirs.t + | Toplevel of Toplevel.t + | External_variant of External_variant.t val stanza_package : Stanza.t -> Package.t option diff --git a/src/dune_load.ml b/src/dune_load.ml index 4c3e45b55fc..5babdc6ba01 100644 --- a/src/dune_load.ml +++ b/src/dune_load.ml @@ -26,6 +26,18 @@ module Dune_file = struct ; stanzas ; kind } + + let rec fold_stanzas l ~init ~f = + match l with + | [] -> init + | t :: l -> inner_fold t t.stanzas l ~init ~f + + and inner_fold t inner_list l ~init ~f = + match inner_list with + | [] -> fold_stanzas l ~init ~f + | x :: inner_list -> + inner_fold t inner_list l ~init:(f t x init) ~f + end module Dune_files = struct diff --git a/src/dune_load.mli b/src/dune_load.mli index 464eaa3fcc1..30993673b5e 100644 --- a/src/dune_load.mli +++ b/src/dune_load.mli @@ -7,6 +7,12 @@ module Dune_file : sig ; stanzas : Dune_file.Stanzas.t ; kind : Dune_lang.File_syntax.t } + + val fold_stanzas : + t list + -> init:'acc + -> f:(t -> Stanza.t -> 'acc -> 'acc) + -> 'acc end module Dune_files : sig diff --git a/src/dune_package.ml b/src/dune_package.ml index a138b773d92..cf7fd75a888 100644 --- a/src/dune_package.ml +++ b/src/dune_package.ml @@ -19,9 +19,9 @@ module Lib = struct ; ppx_runtime_deps : (Loc.t * Lib_name.t) list ; sub_systems : 'sub_system Sub_system_name.Map.t ; virtual_ : bool - ; implements : (Loc.t * Lib_name.t) option - ; variant : Variant.t option + ; known_implementations : (Loc.t * Lib_name.t) Variant.Map.t ; default_implementation : (Loc.t * Lib_name.t) option + ; implements : (Loc.t * Lib_name.t) option ; modules : Lib_modules.t option ; main_module_name : Module.Name.t option ; requires : (Loc.t * Lib_name.t) list @@ -33,8 +33,8 @@ module Lib = struct let make ~loc ~kind ~name ~synopsis ~archives ~plugins ~foreign_objects ~foreign_archives ~jsoo_runtime ~main_module_name ~sub_systems - ~requires ~ppx_runtime_deps ~implements ~variant - ~default_implementation ~virtual_ ~modules ~modes + ~requires ~ppx_runtime_deps ~implements + ~default_implementation ~virtual_ ~known_implementations ~modules ~modes ~version ~orig_src_dir ~obj_dir ~special_builtin_support = let dir = Obj_dir.dir obj_dir in @@ -60,11 +60,11 @@ module Lib = struct ; requires ; ppx_runtime_deps ; implements - ; variant - ; default_implementation ; version ; orig_src_dir ; virtual_ + ; known_implementations + ; default_implementation ; modules ; modes ; obj_dir @@ -85,8 +85,8 @@ module Lib = struct let encode ~package_root { loc = _ ; kind ; synopsis ; name ; archives ; plugins ; foreign_objects ; foreign_archives ; jsoo_runtime ; requires - ; ppx_runtime_deps ; sub_systems ; virtual_ - ; implements ; variant ; default_implementation + ; ppx_runtime_deps ; sub_systems ; virtual_ ; known_implementations + ; implements ; default_implementation ; main_module_name ; version = _; obj_dir ; orig_src_dir ; modules ; modes ; special_builtin_support } = @@ -96,6 +96,7 @@ module Lib = struct let paths name f = field_l name path f in let mode_paths name (xs : Path.t Mode.Dict.List.t) = field_l name sexp (Mode.Dict.List.encode path xs) in + let known_implementations = Variant.Map.to_list known_implementations in let libs name = field_l name (no_loc Lib_name.encode) in record_fields @@ [ field "name" Lib_name.encode name @@ -111,7 +112,8 @@ module Lib = struct ; libs "requires" requires ; libs "ppx_runtime_deps" ppx_runtime_deps ; field_o "implements" (no_loc Lib_name.encode) implements - ; field_o "variant" Variant.encode variant + ; field_l "known_implementations" + (pair Variant.encode (no_loc Lib_name.encode)) known_implementations ; field_o "default_implementation" (no_loc Lib_name.encode) default_implementation ; field_o "main_module_name" Module.Name.encode main_module_name @@ -139,7 +141,6 @@ module Lib = struct record ( let* main_module_name = field_o "main_module_name" Module.Name.decode in let* implements = field_o "implements" (located Lib_name.decode) in - let* variant = field_o "variant" Variant.decode in let* default_implementation = field_o "default_implementation" (located Lib_name.decode) in let* name = field "name" Lib_name.decode in @@ -162,15 +163,21 @@ module Lib = struct and+ requires = libs "requires" and+ ppx_runtime_deps = libs "ppx_runtime_deps" and+ virtual_ = field_b "virtual" + and+ known_implementations = field_l "known_implementations" + (pair Variant.decode + (located Lib_name.decode)) and+ sub_systems = Sub_system_info.record_parser () and+ orig_src_dir = field_o "orig_src_dir" path and+ modules = field_o "modules" (Lib_modules.decode - ~implements:(Option.is_some implements) ~obj_dir) - and+ special_builtin_support = - field_o "special_builtin_support" - (Syntax.since Stanza.syntax (1, 10) >>> - Dune_file.Library.Special_builtin_support.decode) + ~implements:(Option.is_some + implements) ~obj_dir) + and+ special_builtin_support = + field_o "special_builtin_support" + (Syntax.since Stanza.syntax (1, 10) >>> + Dune_file.Library.Special_builtin_support.decode) in + let known_implementations = + Variant.Map.of_list_exn known_implementations in let modes = Mode.Dict.Set.of_list modes in { kind ; name @@ -184,8 +191,8 @@ module Lib = struct ; requires ; ppx_runtime_deps ; implements - ; variant ; default_implementation + ; known_implementations ; sub_systems ; main_module_name ; virtual_ @@ -215,7 +222,7 @@ module Lib = struct let foreign_archives t = t.foreign_archives let requires t = t.requires let implements t = t.implements - let variant t = t.variant + let known_implementations t = t.known_implementations let default_implementation t = t.default_implementation let modes t = t.modes let special_builtin_support t = t.special_builtin_support diff --git a/src/dune_package.mli b/src/dune_package.mli index 05750426c8b..f722ed8955f 100644 --- a/src/dune_package.mli +++ b/src/dune_package.mli @@ -23,7 +23,7 @@ module Lib : sig val plugins : _ t -> Path.t list Mode.Dict.t val jsoo_runtime : _ t -> Path.t list val implements : _ t -> (Loc.t * Lib_name.t) option - val variant : _ t -> Variant.t option + val known_implementations : _ t -> (Loc.t * Lib_name.t) Variant.Map.t val default_implementation : _ t -> (Loc.t * Lib_name.t) option val special_builtin_support : _ t -> Dune_file.Library.Special_builtin_support.t option @@ -51,9 +51,9 @@ module Lib : sig -> requires:(Loc.t * Lib_name.t) list -> ppx_runtime_deps:(Loc.t * Lib_name.t) list -> implements:(Loc.t * Lib_name.t) option - -> variant: (Variant.t) option -> default_implementation: (Loc.t * Lib_name.t) option -> virtual_:bool + -> known_implementations: (Loc.t * Lib_name.t) Variant.Map.t -> modules:Lib_modules.t option -> modes:Mode.Dict.Set.t -> version:string option diff --git a/src/dune_project.ml b/src/dune_project.ml index ef96ef930e7..ea2c12783e8 100644 --- a/src/dune_project.ml +++ b/src/dune_project.ml @@ -15,6 +15,7 @@ module Name : sig val to_dyn : t -> Dyn.t + val equal : t -> t -> bool val compare : t -> t -> Ordering.t val to_string_hum : t -> string @@ -44,6 +45,8 @@ end = struct | Anonymous x, Anonymous y -> Path.Source.compare x y | Named _, Anonymous _ -> Lt | Anonymous _, Named _ -> Gt + + let equal a b = Ordering.is_eq (compare a b) end include T diff --git a/src/dune_project.mli b/src/dune_project.mli index a051ddb35d9..029a6636ffb 100644 --- a/src/dune_project.mli +++ b/src/dune_project.mli @@ -20,6 +20,7 @@ module Name : sig val to_dyn : t -> Dyn.t + val equal : t -> t -> bool val compare : t -> t -> Ordering.t (** Convert to a string that is suitable for human readable messages *) diff --git a/src/findlib.ml b/src/findlib.ml index d8c80383274..8bf742b0f96 100644 --- a/src/findlib.ml +++ b/src/findlib.ml @@ -231,7 +231,7 @@ module Package = struct ~ppx_runtime_deps:(List.map ~f:add_loc (ppx_runtime_deps t)) ~virtual_:false ~implements:None - ~variant:None + ~known_implementations:Variant.Map.empty ~default_implementation:None ~modules:None ~main_module_name:None (* XXX remove *) diff --git a/src/gen_rules.ml b/src/gen_rules.ml index aa3a15e8bcb..8e595216fea 100644 --- a/src/gen_rules.ml +++ b/src/gen_rules.ml @@ -304,11 +304,36 @@ module type Gen = sig val sctx : Super_context.t end -let relevant_stanzas pkgs stanzas = - List.filter stanzas ~f:(fun stanza -> +let filter_out_stanzas_from_hidden_packages ~visible_pkgs = + List.filter_map ~f:(fun stanza -> match Dune_file.stanza_package stanza with - | Some package -> Package.Name.Set.mem pkgs package.name - | None -> true) + | None -> Some stanza + | Some package -> + if Package.Name.Set.mem visible_pkgs package.name then + Some stanza + else + (* If the stanza is a hidden public implementation of a + visible library, turn it into an external variant so that + we can correctly compute the set of "knonw implementation" + when generating the dune-package file. *) + match stanza with + | Library { public = Some { name = (_, name); _ } + ; variant = Some variant + ; implements = Some (_, virtual_lib) + ; project + ; buildable = { loc; _ } + ; _ } + when Package.Name.Set.mem visible_pkgs + (Lib_name.package_name virtual_lib) -> + Some + (External_variant + { implementation = name + ; virtual_lib + ; variant + ; project + ; loc + }) + | _ -> None) let gen ~contexts ?(external_lib_deps_mode=false) @@ -333,14 +358,16 @@ let gen ~contexts Fiber.Ivar.read (Hashtbl.find_exn sctxs h.name) >>| Option.some in + let stanzas () = let+ stanzas = Dune_load.Dune_files.eval ~context dune_files in match only_packages with | None -> stanzas - | Some pkgs -> + | Some visible_pkgs -> List.map stanzas ~f:(fun (dir_conf : Dune_load.Dune_file.t) -> { dir_conf with - stanzas = relevant_stanzas pkgs dir_conf.stanzas + stanzas = filter_out_stanzas_from_hidden_packages + ~visible_pkgs dir_conf.stanzas }) in let* (host, stanzas) = Fiber.fork_and_join host stanzas in diff --git a/src/lib.ml b/src/lib.ml index 3be37c15796..3ebfb7010a2 100644 --- a/src/lib.ml +++ b/src/lib.ml @@ -206,8 +206,8 @@ module T = struct ; user_written_deps : Dune_file.Lib_deps.t ; implements : t Or_exn.t option ; (* these fields cannot be forced until the library is instantiated *) - default_implementation : t Or_exn.t Lazy.t option - ; implementations : t Or_exn.t list Variant.Map.t Lazy.t option + default_implementation : t Or_exn.t Lazy.t option + ; resolved_implementations : t Or_exn.t Variant.Map.t Lazy.t option ; (* This is mutable to avoid this error: {[ @@ -233,7 +233,6 @@ type status = type db = { parent : db option ; resolve : Lib_name.t -> resolve_result - ; find_implementations : Lib_name.t -> Lib_info.t list Variant.Map.t ; table : (Lib_name.t, status) Hashtbl.t ; all : Lib_name.t list Lazy.t } @@ -309,9 +308,8 @@ let wrapped t = let package t = match t.info.status with | Installed -> Some (Lib_name.package_name t.name) - | Public p -> Some p.name - | Private _ -> - None + | Public (_, p) -> Some p.name + | Private _ -> None let to_id t : Id.t = t.unique_id let equal l1 l2 = Id.equal (to_id l1) (to_id l2) @@ -775,14 +773,15 @@ let find_implementation_for lib ~variants = | None -> Ok None | Some (loc, variants_set) -> let available_implementations = - Lazy.force (Option.value_exn lib.implementations) + Lazy.force (Option.value_exn lib.resolved_implementations) in let* candidates = Variant.Set.fold variants_set ~init:[] ~f:(fun variant acc -> - List.rev_append acc - (Variant.Map.Multi.find available_implementations variant)) + match Variant.Map.find available_implementations variant with + | Some res -> res :: acc + | None -> acc) |> Result.List.all in match candidates with @@ -797,16 +796,6 @@ let find_implementation_for lib ~variants = ; conflict })) -let find_implementations db name = - let rec loop acc db = - let implementations = db.find_implementations name in - let acc = Variant.Map.Multi.rev_union acc implementations in - match db.parent with - | None -> acc - | Some db -> loop acc db - in - loop Variant.Map.empty db - let rec instantiate db name (info : Lib_info.t) ~stack ~hidden = let id, stack = Dep_stack.create_and_push stack name info.src_dir @@ -825,29 +814,43 @@ let rec instantiate db name (info : Lib_info.t) ~stack ~hidden = Option.map info.implements ~f:(fun ((loc, _) as name) -> let* vlib = resolve name in match vlib.info.virtual_ with - | Some _ -> Ok vlib | None -> Error (Error (Error.Not_virtual_lib - { impl = info ; loc ; not_vlib = vlib.info }))) + { impl = info ; loc ; not_vlib = vlib.info })) + | Some _ -> + match info.variant with + | None -> Ok vlib + | Some variant -> + (* If the library is an implementation tagged with a + variant, we must make sure that that it implements a + library that is part of the same project *) + if Option.equal Dune_project.Name.equal + (Lib_info.Status.project_name info.status) + (Lib_info.Status.project_name vlib.info.status) + then + Ok vlib + else + Errors.fail loc + "Library implementation %a with variant %a implements@ a \ + library outside the project.@ Instead of using \ + (variant %a) here,@ you need to reference it in the \ + virtual library project,@ using the external_variant stanza:@ \ + (external_variant@\n\ + \ (virtual_library %a)@\n\ + \ (variant %a)@\n\ + \ (implementation %a))" + Lib_name.pp info.name + Variant.pp variant + Variant.pp variant + Lib_name.pp vlib.name + Variant.pp variant + Lib_name.pp info.name) in let default_implementation = Option.map info.default_implementation ~f:(fun l -> lazy (resolve l)) in - let implementations = + let resolved_implementations = Option.map info.virtual_ ~f:(fun _ -> lazy ( - let available_implementations = find_implementations db name in - let seen_libs = ref Set.empty in - Variant.Map.map available_implementations ~f:( - List.filter_map ~f:(fun (impl : Lib_info.t) -> - match resolve (impl.loc, impl.name) with - | Error _ as e -> Some e - | Ok lib -> - if Set.mem !seen_libs lib then - None - else begin - seen_libs := Set.add !seen_libs lib; - Some (Ok lib) - end - )))) + Variant.Map.map info.known_implementations ~f:resolve)) in let requires, pps, resolved_selects = resolve_user_deps db info.requires ~allow_private_deps ~pps:info.pps ~stack @@ -881,7 +884,7 @@ let rec instantiate db name (info : Lib_info.t) ~stack ~hidden = ; sub_systems = Sub_system_name.Map.empty ; implements ; default_implementation - ; implementations + ; resolved_implementations } in t.sub_systems <- @@ -1311,50 +1314,105 @@ module DB = struct type t = db - let create ?parent ~resolve ~find_implementations ~all () = + let create ?parent ~resolve ~all () = { parent ; resolve - ; find_implementations ; table = Hashtbl.create 1024 ; all = Lazy.from_fun all } - let create_variant_map lib_info_list = - List.concat_map lib_info_list ~f:(fun (info : Lib_info.t) -> - match info.implements, info.variant with - | Some (_, virtual_lib), Some variant -> [virtual_lib, (variant, [info])] - | _, _ -> []) - |> List.map ~f:(fun (virtual_lib, content) -> - (virtual_lib, Variant.Map.of_list_exn [content])) - |> Lib_name.Map.of_list_reduce ~f:Variant.Map.Multi.rev_union - - (* implementations tagged with a variant are only variant when the they - implement a virtual library from the same project. *) - let check_valid_implementations (libmap : resolve_result Lib_name.Map.t) = - Lib_name.Map.iter libmap ~f:(function - | Found (lib : Lib_info.t) -> - begin match lib.implements, lib.variant with - | Some (loc, implements), Some variant -> - if not (Lib_name.Map.mem libmap implements) then - Errors.fail loc - "Library implementation %a for variant %a implements a library \ - outside the project. This is forbidden." - Lib_name.pp implements Variant.pp variant - | _, _ -> () - end - | Redirect (_, _) (* skip b/c [Found] covers *) -> () - | Hidden (_, _) -> assert false - | Not_found -> assert false) - - let create_from_library_stanzas ?parent ~lib_config stanzas = + let check_valid_external_variants libmap external_variants = + List.iter external_variants ~f:(fun (ev : Dune_file.External_variant.t) -> + match + Option.map (Lib_name.Map.find libmap ev.virtual_lib) ~f:(fun res -> + (* [res] is created by the code in + [create_from_library_stanzas] bellow. We know that it is + either [Found] or [Redirect (_, name)] where [name] is in + [libmap] for sure and maps to [Found _]. *) + match res with + | Not_found | Hidden _ -> assert false + | Found x -> x + | Redirect (_, name') -> + match Lib_name.Map.find libmap name' with + | Some (Found x) -> x + | _ -> assert false) + with + | None -> + Errors.fail ev.loc + "Virtual library %a hasn't been found in the project." + Lib_name.pp ev.virtual_lib + | Some { virtual_ = None; _ } -> + Errors.fail ev.loc + "Library %a isn't a virtual library." + Lib_name.pp ev.virtual_lib + | Some { virtual_ = Some _; _ } -> ()) + + let error_two_impl_for_variant name variant (loc1, impl1) (loc2, impl2) = + Errors.fail_opt None + "Error: Two implementations of %a have the same variant %a:\n\ + - %a (%a)\n\ + - %a (%a)\n" + Lib_name.Local.pp name + Variant.pp variant + Lib_name.pp impl1 + Loc.pp_file_colon_line loc1 + Lib_name.pp impl2 + Loc.pp_file_colon_line loc2 + + let create_from_library_stanzas ?parent ~lib_config lib_stanzas + external_variant_stanzas = + (* Construct a mapping from virtual library name to a list of + [(variant, implementation_for_this_variant)]. We check a bit + later that there is duplicate in the inner lists. *) + let variant_map = Lib_name.Map.empty in let variant_map = - List.map stanzas ~f:(fun (dir, (conf : Dune_file.Library.t)) -> - Lib_info.of_library_stanza ~dir ~lib_config conf) - |> create_variant_map + (* Add entries from library stanzas *) + List.fold_left lib_stanzas ~init:variant_map ~f:(fun acc (_, lib) -> + match (lib : Dune_file.Library.t) with + | { implements = Some (_, vlib) + ; variant = Some variant + ; buildable = { loc; _ } + ; _ } -> + Lib_name.Map.Multi.cons acc vlib + (variant, (loc, Dune_file.Library.best_name lib)) + | _ -> acc) + in + let variant_map = + (* Add entries from external_variant stanzas *) + List.fold_left external_variant_stanzas ~init:variant_map + ~f:(fun acc (ev : Dune_file.External_variant.t) -> + Lib_name.Map.Multi.cons acc ev.virtual_lib + (ev.variant, (ev.loc, ev.implementation))) in let map = - List.concat_map stanzas ~f:(fun (dir, (conf : Dune_file.Library.t)) -> - let info = Lib_info.of_library_stanza ~dir ~lib_config conf in + List.concat_map lib_stanzas ~f:(fun (dir, (conf : Dune_file.Library.t)) -> + (* In the [implements] field of library stanzas, the user + might use either public or private library names. As a + result, we have to lookup for implementations via both the + public and private names. *) + let variants_private = + Lib_name.Map.find variant_map (Lib_name.of_local conf.name) + |> Option.value ~default:[] + in + let variants = + match conf.public with + | None -> variants_private + | Some { name = (_loc, name); _ } -> + if Lib_name.equal name (Lib_name.of_local conf.name) then + variants_private + else + match Lib_name.Map.find variant_map name with + | None -> variants_private + | Some variants_public -> + List.rev_append variants_private variants_public + in + let variants = + match Variant.Map.of_list variants with + | Ok x -> x + | Error (variant, x, y) -> + error_two_impl_for_variant (snd conf.name) variant x y + in + let info = Lib_info.of_library_stanza ~dir ~lib_config variants conf in match conf.public with | None -> [Dune_file.Library.best_name conf, Resolve_result.Found info] @@ -1371,13 +1429,14 @@ module DB = struct | Ok x -> x | Error (name, _, _) -> match - List.filter_map stanzas ~f:(fun (_, (conf : Dune_file.Library.t)) -> - if Lib_name.equal name (Lib_name.of_local conf.name) || - match conf.public with - | None -> false - | Some p -> Lib_name.equal name (Dune_file.Public_lib.name p) - then Some conf.buildable.loc - else None) + List.filter_map lib_stanzas + ~f:(fun (_, (conf : Dune_file.Library.t)) -> + if Lib_name.equal name (Lib_name.of_local conf.name) || + match conf.public with + | None -> false + | Some p -> Lib_name.equal name (Dune_file.Public_lib.name p) + then Some conf.buildable.loc + else None) with | [] | [_] -> assert false | loc1 :: loc2 :: _ -> @@ -1388,22 +1447,17 @@ module DB = struct (Loc.to_file_colon_line loc1) (Loc.to_file_colon_line loc2) in - check_valid_implementations map; + (* We need to check that [external_variant] stanzas are correct, + i.e. contain valid [virtual_library] fields now since this is + the last time we analyse them. *) + check_valid_external_variants map external_variant_stanzas; create () ?parent ~resolve:(fun name -> Lib_name.Map.find map name |> Option.value ~default:Not_found) - ~find_implementations:(fun virt -> - Lib_name.Map.find variant_map virt - |> Option.value ~default:Variant.Map.empty) ~all:(fun () -> Lib_name.Map.keys map) let create_from_findlib ?(external_lib_deps_mode=false) findlib = - let variant_map = lazy ( - Findlib.all_packages findlib - |> List.map ~f:Lib_info.of_dune_lib - |> create_variant_map - ) in create () ~resolve:(fun name -> match Findlib.find findlib name with @@ -1418,9 +1472,6 @@ module DB = struct Not_found | Hidden pkg -> Hidden (Lib_info.of_dune_lib pkg, "unsatisfied 'exist_if'")) - ~find_implementations:(fun virt -> - Lib_name.Map.find (Lazy.force variant_map) virt - |> Option.value ~default:Variant.Map.empty) ~all:(fun () -> Findlib.all_packages findlib |> List.map ~f:Dune_package.Lib.name) @@ -1428,8 +1479,6 @@ module DB = struct let find = find let find_even_when_hidden = find_even_when_hidden - let find_implementations t = t.find_implementations - let resolve t (loc, name) = match find t name with | Ok _ as res -> res @@ -1578,7 +1627,6 @@ let report_lib_error ppf (e : Error.t) = | Some x -> x | None -> Variant.make "err"))) conflict - | Double_implementation { impl1; impl2; vlib } -> Format.fprintf ppf "@[@{Error@}: \ @@ -1672,7 +1720,8 @@ let () = Some (Report_error.make_printer ?loc ?hint pp) | _ -> None) -let to_dune_lib ({ name ; info ; _ } as lib) ~lib_modules ~foreign_objects ~dir = +let to_dune_lib ({ name ; info ; _ } as lib) ~lib_modules ~foreign_objects + ~dir = let add_loc = List.map ~f:(fun x -> (info.loc, x.name)) in let virtual_ = Option.is_some info.virtual_ in let obj_dir = Obj_dir.convert_to_external ~dir (obj_dir lib) in @@ -1686,7 +1735,8 @@ let to_dune_lib ({ name ; info ; _ } as lib) ~lib_modules ~foreign_objects ~dir | None -> match Path.drop_build_context info.src_dir with | None -> info.src_dir - | Some src_dir -> Path.(of_string (to_absolute_filename (Path.source src_dir))) + | Some src_dir -> + Path.(of_string (to_absolute_filename (Path.source src_dir))) ) else None in @@ -1712,7 +1762,7 @@ let to_dune_lib ({ name ; info ; _ } as lib) ~lib_modules ~foreign_objects ~dir ~ppx_runtime_deps:(add_loc (ppx_runtime_deps_exn lib)) ~modes:info.modes ~implements:info.implements - ~variant:info.variant + ~known_implementations:info.known_implementations ~default_implementation:info.default_implementation ~virtual_ ~modules:(Some lib_modules) diff --git a/src/lib.mli b/src/lib.mli index bf6cb8f3a83..39c3fd2146e 100644 --- a/src/lib.mli +++ b/src/lib.mli @@ -259,16 +259,16 @@ module DB : sig val create : ?parent:t -> resolve:(Lib_name.t -> Resolve_result.t) - -> find_implementations:(Lib_name.t -> Lib_info.t list Variant.Map.t) -> all:(unit -> Lib_name.t list) -> unit -> t - (** Create a database from a list of library stanzas *) + (** Create a database from a list of library/variants stanzas *) val create_from_library_stanzas : ?parent:t -> lib_config:Lib_config.t -> (Path.Build.t * Dune_file.Library.t) list + -> Dune_file.External_variant.t list -> t val create_from_findlib @@ -291,8 +291,6 @@ module DB : sig for libraries that are optional and not available as well. *) val get_compile_info : t -> ?allow_overlaps:bool -> Lib_name.t -> Compile.t - val find_implementations : t -> Lib_name.t -> Lib_info.t list Variant.Map.t - val resolve : t -> Loc.t * Lib_name.t -> lib Or_exn.t (** Resolve libraries written by the user in a jbuild file. The diff --git a/src/lib_info.ml b/src/lib_info.ml index a9305044dff..c6731f56261 100644 --- a/src/lib_info.ml +++ b/src/lib_info.ml @@ -3,7 +3,7 @@ open Stdune module Status = struct type t = | Installed - | Public of Package.t + | Public of Dune_project.Name.t * Package.t | Private of Dune_project.Name.t let pp ppf t = @@ -17,6 +17,10 @@ module Status = struct let is_private = function | Private _ -> true | Installed | Public _ -> false + + let project_name = function + | Installed -> None + | Public (name, _) | Private name -> Some name end @@ -80,6 +84,7 @@ type t = ; virtual_ : Lib_modules.t Source.t option ; implements : (Loc.t * Lib_name.t) option ; variant : Variant.t option + ; known_implementations : (Loc.t * Lib_name.t) Variant.Map.t ; default_implementation : (Loc.t * Lib_name.t) option ; wrapped : Wrapped.t Dune_file.Library.Inherited.t option ; main_module_name : Dune_file.Library.Main_module_name.t @@ -95,6 +100,7 @@ let user_written_deps t = let of_library_stanza ~dir ~lib_config:({ Lib_config.has_native; ext_lib; ext_obj; _ } as lib_config) + (known_implementations : (Loc.t * Lib_name.t) Variant.Map.t) (conf : Dune_file.Library.t) = let (_loc, lib_name) = conf.name in let obj_dir = @@ -114,7 +120,7 @@ let of_library_stanza ~dir let status = match conf.public with | None -> Status.Private (Dune_project.name conf.project) - | Some p -> Public p.package + | Some p -> Public (Dune_project.name conf.project, p.package) in let virtual_library = Dune_file.Library.is_virtual conf in let foreign_archives = @@ -207,6 +213,7 @@ let of_library_stanza ~dir ; virtual_ ; implements = conf.implements ; variant = conf.variant + ; known_implementations ; default_implementation = conf.default_implementation ; main_module_name ; modes @@ -253,7 +260,8 @@ let of_dune_lib dp = ; sub_systems = Lib.sub_systems dp ; virtual_ ; implements = Lib.implements dp - ; variant = Lib.variant dp + ; variant = None + ; known_implementations = Lib.known_implementations dp ; default_implementation = Lib.default_implementation dp ; modes = Lib.modes dp ; wrapped diff --git a/src/lib_info.mli b/src/lib_info.mli index 17096973b9e..8c06d646d14 100644 --- a/src/lib_info.mli +++ b/src/lib_info.mli @@ -5,12 +5,15 @@ open Stdune module Status : sig type t = | Installed - | Public of Package.t + | Public of Dune_project.Name.t * Package.t | Private of Dune_project.Name.t val pp : t Fmt.t val is_private : t -> bool + + (** For local libraries, return the project name they are part of *) + val project_name : t -> Dune_project.Name.t option end module Deps : sig @@ -61,6 +64,7 @@ type t = private ; virtual_ : Lib_modules.t Source.t option ; implements : (Loc.t * Lib_name.t) option ; variant : Variant.t option + ; known_implementations : (Loc.t * Lib_name.t) Variant.Map.t ; default_implementation : (Loc.t * Lib_name.t) option ; wrapped : Wrapped.t Dune_file.Library.Inherited.t option ; main_module_name : Dune_file.Library.Main_module_name.t @@ -71,6 +75,7 @@ type t = private val of_library_stanza : dir:Path.Build.t -> lib_config:Lib_config.t + -> (Loc.t * Lib_name.t) Variant.Map.t -> Dune_file.Library.t -> t diff --git a/src/scope.ml b/src/scope.ml index bb389e2df98..1ea9aa43612 100644 --- a/src/scope.ml +++ b/src/scope.ml @@ -62,12 +62,6 @@ module DB = struct let scope = find_by_name (Fdecl.get t) (Dune_project.name project) in Redirect (Some scope.db, name) - let find_implementations t public_libs virt = - Lib_name.Map.fold public_libs ~init:Variant.Map.empty ~f:(fun project acc -> - let scope = find_by_name (Fdecl.get t) (Dune_project.name project) in - Lib.DB.find_implementations scope.db virt - |> Variant.Map.Multi.rev_union acc) - let public_libs t ~installed_libs internal_libs = let public_libs = List.filter_map internal_libs @@ -94,15 +88,13 @@ module DB = struct (Loc.to_file_colon_line loc2) in let resolve = resolve t public_libs in - let find_implementations = find_implementations t public_libs in Lib.DB.create () ~parent:installed_libs ~resolve - ~find_implementations ~all:(fun () -> Lib_name.Map.keys public_libs) let sccopes_by_name ~context ~projects ~lib_config ~public_libs - internal_libs = + internal_libs variant_implementations = let build_context_dir = Path.Build.relative Path.Build.root context in let projects_by_name = List.map projects ~f:(fun (project : Dune_project.t) -> @@ -126,23 +118,39 @@ module DB = struct (Dune_project.name lib.project, (dir, lib))) |> Dune_project.Name.Map.of_list_multi in - Dune_project.Name.Map.merge projects_by_name libs_by_project_name - ~f:(fun _name project libs -> + let variant_implementations_by_project_name = + List.map variant_implementations + ~f:(fun (lib : Dune_file.External_variant.t) -> + (Dune_project.name lib.project, lib)) + |> Dune_project.Name.Map.of_list_multi + in + let libs_variants_by_project_name = + Dune_project.Name.Map.merge + libs_by_project_name + variant_implementations_by_project_name + ~f:(fun _name libs variants -> + let libs = Option.value libs ~default:[] in + let variants = Option.value variants ~default:[] in + Some (libs, variants)) + in + Dune_project.Name.Map.merge projects_by_name libs_variants_by_project_name + ~f:(fun _name project l_v -> let project = Option.value_exn project in - let libs = Option.value libs ~default:[] in - let db = Lib.DB.create_from_library_stanzas libs ~parent:public_libs - ~lib_config in + let libs, variants = Option.value l_v ~default:([], []) in + let db = Lib.DB.create_from_library_stanzas libs variants + ~parent:public_libs ~lib_config in let root = Path.Build.append_source build_context_dir (Dune_project.root project) in Some { project; db; root }) let create ~projects ~context ~installed_libs ~lib_config - internal_libs = + internal_libs variant_implementations = let t = Fdecl.create () in let public_libs = public_libs t ~installed_libs internal_libs in let by_name = - sccopes_by_name ~context ~projects ~lib_config ~public_libs internal_libs + sccopes_by_name ~context ~projects ~lib_config ~public_libs + internal_libs variant_implementations in let by_dir = Dune_project.Name.Map.values by_name diff --git a/src/scope.mli b/src/scope.mli index 2cee26336bb..01e6d468799 100644 --- a/src/scope.mli +++ b/src/scope.mli @@ -27,6 +27,7 @@ module DB : sig -> installed_libs:Lib.DB.t -> lib_config:Lib_config.t -> (Path.Build.t * Dune_file.Library.t) list + -> Dune_file.External_variant.t list -> t * Lib.DB.t val find_by_dir : t -> Path.Build.t -> scope diff --git a/src/super_context.ml b/src/super_context.ml index 2ce8042bfef..64c88418427 100644 --- a/src/super_context.ml +++ b/src/super_context.ml @@ -181,8 +181,8 @@ end = struct let default_context_flags (ctx : Context.t) = let c = ctx.ocamlc_cflags in let cxx = - List.filter ctx.ocamlc_cflags - ~f:(fun s -> not (String.is_prefix s ~prefix:"-std=")) in + List.filter ctx.ocamlc_cflags + ~f:(fun s -> not (String.is_prefix s ~prefix:"-std=")) in C.Kind.Dict.make ~c ~cxx let c_flags t ~dir = @@ -359,7 +359,7 @@ let create ~(context:Context.t) ?host ~projects - ~file_tree + ~file_tree ~packages ~stanzas ~external_lib_deps_mode @@ -367,23 +367,28 @@ let create let installed_libs = Lib.DB.create_from_findlib context.findlib ~external_lib_deps_mode in - let internal_libs = - List.concat_map stanzas - ~f:(fun { Dune_load.Dune_file. dir; stanzas; project = _ ; kind = _ } -> - let ctx_dir = Path.Build.append_source context.build_dir dir in - List.filter_map stanzas ~f:(fun stanza -> - match (stanza : Stanza.t) with - | Dune_file.Library lib -> Some (ctx_dir, lib) - | _ -> None)) - in let scopes, public_libs = + let libs, external_variants = + Dune_load.Dune_file.fold_stanzas stanzas ~init:([], []) + ~f:(fun dune_file stanza ((libs, external_variants) as acc) -> + match stanza with + | Dune_file.Library lib -> + let ctx_dir = + Path.Build.append_source context.build_dir dune_file.dir + in + ((ctx_dir, lib) :: libs, external_variants) + | Dune_file.External_variant ev -> + (libs, ev :: external_variants) + | _ -> acc) + in let lib_config = Context.lib_config context in Scope.DB.create ~projects ~context:context.name ~installed_libs ~lib_config - internal_libs + libs + external_variants in let stanzas = List.map stanzas @@ -455,18 +460,18 @@ let create ~bin_artifacts_host:artifacts_host.bin in let env_context = { Env_context. - env; - profile = context.profile; - scopes; - context_env = context.env; - default_env; - stanzas_per_dir; - host = Option.map host ~f:(fun x -> x.env_context); - build_dir = context.build_dir; - context = context; - expander = expander; - bin_artifacts = artifacts.Artifacts.bin; - } + env; + profile = context.profile; + scopes; + context_env = context.env; + default_env; + stanzas_per_dir; + host = Option.map host ~f:(fun x -> x.env_context); + build_dir = context.build_dir; + context = context; + expander = expander; + bin_artifacts = artifacts.Artifacts.bin; + } in let dir_status_db = Dir_status.DB.make file_tree ~stanzas_per_dir in { context diff --git a/test/blackbox-tests/dune.inc b/test/blackbox-tests/dune.inc index ab08aefe47b..4c808372b92 100644 --- a/test/blackbox-tests/dune.inc +++ b/test/blackbox-tests/dune.inc @@ -1440,6 +1440,24 @@ test-cases/variants (progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected))))) +(alias + (name variants-external-declaration) + (deps (package dune) (source_tree test-cases/variants-external-declaration)) + (action + (chdir + test-cases/variants-external-declaration + (progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected))))) + +(alias + (name variants-external-declaration-conflict) + (deps + (package dune) + (source_tree test-cases/variants-external-declaration-conflict)) + (action + (chdir + test-cases/variants-external-declaration-conflict + (progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected))))) + (alias (name variants-multi-project) (deps (package dune) (source_tree test-cases/variants-multi-project)) @@ -1448,6 +1466,14 @@ test-cases/variants-multi-project (progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected))))) +(alias + (name variants-only-package) + (deps (package dune) (source_tree test-cases/variants-only-package)) + (action + (chdir + test-cases/variants-only-package + (progn (run %{exe:cram.exe} -test run.t) (diff? run.t run.t.corrected))))) + (alias (name vlib) (deps (package dune) (source_tree test-cases/vlib)) @@ -1674,7 +1700,10 @@ (alias utop) (alias utop-default) (alias variants) + (alias variants-external-declaration) + (alias variants-external-declaration-conflict) (alias variants-multi-project) + (alias variants-only-package) (alias vlib) (alias vlib-default-impl) (alias windows-diff) @@ -1834,7 +1863,10 @@ (alias unreadable-src) (alias upgrader) (alias variants) + (alias variants-external-declaration) + (alias variants-external-declaration-conflict) (alias variants-multi-project) + (alias variants-only-package) (alias vlib) (alias vlib-default-impl) (alias windows-diff) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/1/dune b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/1/dune new file mode 100644 index 00000000000..a04e88f2e34 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/1/dune @@ -0,0 +1,13 @@ +(library + (name vlibfoo) + (virtual_modules vlibfoo)) + +(external_variant + (virtual_library vlibfoo) + (variant somevariant) + (implementation impl1)) + +(external_variant + (virtual_library vlibfoo) + (variant somevariant) + (implementation impl2)) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/1/dune-project b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/1/dune-project new file mode 100644 index 00000000000..51cd215341f --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/1/dune-project @@ -0,0 +1,2 @@ +(lang dune 1.10) +(using library_variants 0.2) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/1/vlibfoo.mli b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/1/vlibfoo.mli new file mode 100644 index 00000000000..56a52c4170a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/1/vlibfoo.mli @@ -0,0 +1 @@ +val implme : unit -> unit diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/dune-project b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/dune-project new file mode 100644 index 00000000000..51cd215341f --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/dune-project @@ -0,0 +1,2 @@ +(lang dune 1.10) +(using library_variants 0.2) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/exe/dune b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/exe/dune new file mode 100644 index 00000000000..38ffdbfca9c --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/exe/dune @@ -0,0 +1,4 @@ +(executable + (name exe) + (libraries vlibfoo) + (variants somevariant)) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/exe/exe.ml b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/exe/exe.ml new file mode 100644 index 00000000000..abb3a1931c1 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/exe/exe.ml @@ -0,0 +1 @@ +let () = Vlibfoo.implme () \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/impl/dune b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/impl/dune new file mode 100644 index 00000000000..fb102b83ca4 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/impl/dune @@ -0,0 +1,4 @@ +(library + (name impl2) + (implements vlibfoo) + (variant somevariant)) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/impl/vlibfoo.ml b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/impl/vlibfoo.ml new file mode 100644 index 00000000000..e11e2d7309a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/impl/vlibfoo.ml @@ -0,0 +1 @@ +let implme () = () \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/vlib/dune b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/vlib/dune new file mode 100644 index 00000000000..be5cc1bc52e --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/vlib/dune @@ -0,0 +1,8 @@ +(library + (name vlibfoo) + (virtual_modules vlibfoo)) + +(external_variant + (virtual_library vlibfoo) + (variant somevariant) + (implementation impl1)) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/vlib/vlibfoo.mli b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/vlib/vlibfoo.mli new file mode 100644 index 00000000000..56a52c4170a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/2/vlib/vlibfoo.mli @@ -0,0 +1 @@ +val implme : unit -> unit diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/dune-project b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/dune-project new file mode 100644 index 00000000000..51cd215341f --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/dune-project @@ -0,0 +1,2 @@ +(lang dune 1.10) +(using library_variants 0.2) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/exe/dune b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/exe/dune new file mode 100644 index 00000000000..38ffdbfca9c --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/exe/dune @@ -0,0 +1,4 @@ +(executable + (name exe) + (libraries vlibfoo) + (variants somevariant)) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/exe/exe.ml b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/exe/exe.ml new file mode 100644 index 00000000000..abb3a1931c1 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/exe/exe.ml @@ -0,0 +1 @@ +let () = Vlibfoo.implme () \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/impl/dune b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/impl/dune new file mode 100644 index 00000000000..6841af61e33 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/impl/dune @@ -0,0 +1,5 @@ +(library + (name impl1) + (implements vlibfoo) + (variant somevariant) +) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/impl/vlibfoo.ml b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/impl/vlibfoo.ml new file mode 100644 index 00000000000..e11e2d7309a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/impl/vlibfoo.ml @@ -0,0 +1 @@ +let implme () = () \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/vlib/dune b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/vlib/dune new file mode 100644 index 00000000000..f05a5551495 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/vlib/dune @@ -0,0 +1,9 @@ +(library + (name vlibfoo) + (virtual_modules vlibfoo) +) + +(external_variant + (virtual_library vlibfoo) + (variant somevariant) + (implementation impl1)) \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/vlib/vlibfoo.mli b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/vlib/vlibfoo.mli new file mode 100644 index 00000000000..56a52c4170a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/3/vlib/vlibfoo.mli @@ -0,0 +1 @@ +val implme : unit -> unit diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/not-a-vlib/dune b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/not-a-vlib/dune new file mode 100644 index 00000000000..a7d13e70a2c --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/not-a-vlib/dune @@ -0,0 +1,7 @@ +(library + (name libfoo)) + +(external_variant + (virtual_library libfoo) + (variant somevariant) + (implementation impl1)) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/not-a-vlib/dune-project b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/not-a-vlib/dune-project new file mode 100644 index 00000000000..51cd215341f --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/not-a-vlib/dune-project @@ -0,0 +1,2 @@ +(lang dune 1.10) +(using library_variants 0.2) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/not-a-vlib/libfoo.ml b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/not-a-vlib/libfoo.ml new file mode 100644 index 00000000000..e11e2d7309a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/not-a-vlib/libfoo.ml @@ -0,0 +1 @@ +let implme () = () \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/another-name.opam b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/another-name.opam new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/dune b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/dune new file mode 100644 index 00000000000..9baf297182a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/dune @@ -0,0 +1,13 @@ +(library + (name libfoo) + (public_name another-name)) + +(external_variant + (virtual_library libfoo) + (variant somevariant) + (implementation impl1)) + +(external_variant + (virtual_library another-name) + (variant somevariant) + (implementation impl2)) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/dune-project b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/dune-project new file mode 100644 index 00000000000..51cd215341f --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/dune-project @@ -0,0 +1,2 @@ +(lang dune 1.10) +(using library_variants 0.2) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/libfoo.ml b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/libfoo.ml new file mode 100644 index 00000000000..e11e2d7309a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/public-private/libfoo.ml @@ -0,0 +1 @@ +let implme () = () \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/run.t b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/run.t new file mode 100644 index 00000000000..dd30a008ca5 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/run.t @@ -0,0 +1,52 @@ +It is forbidden to declare two external implementations with the same variant. + + $ dune build --root 1/ + Entering directory '1' + Error: Two implementations of vlibfoo have the same variant "somevariant": + - impl1 (dune:5) + - impl2 (dune:10) + [1] + +It is forbidden to declare an external implementation and have a local +implementation with the same variant. + + $ dune build --root 2 exe/exe.exe + Entering directory '2' + Error: Two implementations of vlibfoo have the same variant "somevariant": + - impl1 (vlib/dune:5) + - impl2 (impl/dune:1) + [1] + + $ dune build --root 3 exe/exe.exe + Entering directory '3' + Error: Two implementations of vlibfoo have the same variant "somevariant": + - impl1 (vlib/dune:6) + - impl1 (impl/dune:1) + [1] + + $ dune build --root not-a-vlib + Entering directory 'not-a-vlib' + File "dune", line 4, characters 0-91: + 4 | (external_variant + 5 | (virtual_library libfoo) + 6 | (variant somevariant) + 7 | (implementation impl1)) + Error: Library libfoo isn't a virtual library. + [1] + + $ dune build --root public-private + Entering directory 'public-private' + Error: Two implementations of libfoo have the same variant "somevariant": + - impl1 (dune:5) + - impl2 (dune:10) + [1] + + $ dune build --root vlib-dont-exist + Entering directory 'vlib-dont-exist' + File "dune", line 1, characters 0-97: + 1 | (external_variant + 2 | (virtual_library i-dont-exist) + 3 | (variant somevariant) + 4 | (implementation impl1)) + Error: Virtual library i-dont-exist hasn't been found in the project. + [1] diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/vlib-dont-exist/dune b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/vlib-dont-exist/dune new file mode 100644 index 00000000000..ba222f458a0 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/vlib-dont-exist/dune @@ -0,0 +1,4 @@ +(external_variant + (virtual_library i-dont-exist) + (variant somevariant) + (implementation impl1)) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration-conflict/vlib-dont-exist/dune-project b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/vlib-dont-exist/dune-project new file mode 100644 index 00000000000..51cd215341f --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration-conflict/vlib-dont-exist/dune-project @@ -0,0 +1,2 @@ +(lang dune 1.10) +(using library_variants 0.2) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/exe/dune b/test/blackbox-tests/test-cases/variants-external-declaration/exe/dune new file mode 100644 index 00000000000..fb2c70786fd --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration/exe/dune @@ -0,0 +1,4 @@ +(executable + (name exe) + (libraries vlibfoo-ext) + (variants somevariant)) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/exe/dune-project b/test/blackbox-tests/test-cases/variants-external-declaration/exe/dune-project new file mode 100644 index 00000000000..8a603347b8d --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration/exe/dune-project @@ -0,0 +1,2 @@ +(lang dune 1.10) +(using library_variants 0.1) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/exe/exe.ml b/test/blackbox-tests/test-cases/variants-external-declaration/exe/exe.ml new file mode 100644 index 00000000000..abb3a1931c1 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration/exe/exe.ml @@ -0,0 +1 @@ +let () = Vlibfoo.implme () \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/prj1/dune b/test/blackbox-tests/test-cases/variants-external-declaration/prj1/dune new file mode 100644 index 00000000000..edd369fc3fe --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration/prj1/dune @@ -0,0 +1,16 @@ +(library + (name vlibfoo) + (public_name vlibfoo-ext) + (virtual_modules vlibfoo) +) + +(external_variant + (virtual_library vlibfoo) + (variant somevariant) + (implementation impl)) + + +(external_variant + (virtual_library vlibfoo-ext) + (variant somevariant-2) + (implementation impl-2)) \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/prj1/dune-project b/test/blackbox-tests/test-cases/variants-external-declaration/prj1/dune-project new file mode 100644 index 00000000000..51cd215341f --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration/prj1/dune-project @@ -0,0 +1,2 @@ +(lang dune 1.10) +(using library_variants 0.2) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/prj1/vlibfoo-ext.opam b/test/blackbox-tests/test-cases/variants-external-declaration/prj1/vlibfoo-ext.opam new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/prj1/vlibfoo.mli b/test/blackbox-tests/test-cases/variants-external-declaration/prj1/vlibfoo.mli new file mode 100644 index 00000000000..56a52c4170a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration/prj1/vlibfoo.mli @@ -0,0 +1 @@ +val implme : unit -> unit diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/prj2/dune b/test/blackbox-tests/test-cases/variants-external-declaration/prj2/dune new file mode 100644 index 00000000000..078f3bd5d06 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration/prj2/dune @@ -0,0 +1,4 @@ +(library + (name impl) + (public_name impl) + (implements vlibfoo-ext)) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/prj2/dune-project b/test/blackbox-tests/test-cases/variants-external-declaration/prj2/dune-project new file mode 100644 index 00000000000..8a603347b8d --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration/prj2/dune-project @@ -0,0 +1,2 @@ +(lang dune 1.10) +(using library_variants 0.1) diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/prj2/impl.opam b/test/blackbox-tests/test-cases/variants-external-declaration/prj2/impl.opam new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/prj2/vlibfoo.ml b/test/blackbox-tests/test-cases/variants-external-declaration/prj2/vlibfoo.ml new file mode 100644 index 00000000000..e7126a66014 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration/prj2/vlibfoo.ml @@ -0,0 +1 @@ +let implme () = print_endline "foobar" diff --git a/test/blackbox-tests/test-cases/variants-external-declaration/run.t b/test/blackbox-tests/test-cases/variants-external-declaration/run.t new file mode 100644 index 00000000000..b0f323b4b97 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-external-declaration/run.t @@ -0,0 +1,27 @@ +Implementation of library from another project is allowed when explicitely +declared in the virtual library definition. + + $ dune build exe/exe.exe + + $ dune build -p vlibfoo-ext + + $ cat _build/install/default/lib/vlibfoo-ext/dune-package + (lang dune 1.10) + (name vlibfoo-ext) + (library + (name vlibfoo-ext) + (kind normal) + (virtual) + (foreign_archives (native vlibfoo$ext_lib)) + (known_implementations (somevariant impl) (somevariant-2 impl-2)) + (main_module_name Vlibfoo) + (modes byte native) + (modules + (main_module_name Vlibfoo) + (modules + ((name Vlibfoo) + (obj_name vlibfoo) + (visibility public) + (kind virtual) + (intf))) + (wrapped true))) diff --git a/test/blackbox-tests/test-cases/variants-multi-project/run.t b/test/blackbox-tests/test-cases/variants-multi-project/run.t index cf6cdfc8eac..c9688857876 100644 --- a/test/blackbox-tests/test-cases/variants-multi-project/run.t +++ b/test/blackbox-tests/test-cases/variants-multi-project/run.t @@ -5,5 +5,12 @@ variant. File "prj2/dune", line 4, characters 13-20: 4 | (implements vlibfoo) ^^^^^^^ - Error: Library implementation vlibfoo for variant "somevariant" implements a library outside the project. This is forbidden. + Error: Library implementation impl with variant "somevariant" implements + a library outside the project. Instead of using (variant "somevariant") here, + you need to reference it in the virtual library project, + using the external_variant stanza: + (external_variant + (virtual_library vlibfoo) + (variant "somevariant") + (implementation impl)) [1] diff --git a/test/blackbox-tests/test-cases/variants-only-package/dune-project b/test/blackbox-tests/test-cases/variants-only-package/dune-project new file mode 100644 index 00000000000..8a603347b8d --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-only-package/dune-project @@ -0,0 +1,2 @@ +(lang dune 1.10) +(using library_variants 0.1) diff --git a/test/blackbox-tests/test-cases/variants-only-package/implfoo.opam b/test/blackbox-tests/test-cases/variants-only-package/implfoo.opam new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/variants-only-package/implfoo/dune b/test/blackbox-tests/test-cases/variants-only-package/implfoo/dune new file mode 100644 index 00000000000..e7ee652dab5 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-only-package/implfoo/dune @@ -0,0 +1,6 @@ +(library + (name implfoo) + (public_name implfoo) + (implements vlibfoo) + (variant somevariant) +) diff --git a/test/blackbox-tests/test-cases/variants-only-package/implfoo/vlibfoo.ml b/test/blackbox-tests/test-cases/variants-only-package/implfoo/vlibfoo.ml new file mode 100644 index 00000000000..e11e2d7309a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-only-package/implfoo/vlibfoo.ml @@ -0,0 +1 @@ +let implme () = () \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/variants-only-package/run.t b/test/blackbox-tests/test-cases/variants-only-package/run.t new file mode 100644 index 00000000000..708ab6916f6 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-only-package/run.t @@ -0,0 +1,25 @@ +Check that local variant implementations are correctly exported in the list of +known_implementations implementations when using -p + + $ dune build -p vlibfoo + + $ cat _build/install/default/lib/vlibfoo/dune-package + (lang dune 1.10) + (name vlibfoo) + (library + (name vlibfoo) + (kind normal) + (virtual) + (foreign_archives (native vlibfoo$ext_lib)) + (known_implementations (somevariant implfoo)) + (main_module_name Vlibfoo) + (modes byte native) + (modules + (main_module_name Vlibfoo) + (modules + ((name Vlibfoo) + (obj_name vlibfoo) + (visibility public) + (kind virtual) + (intf))) + (wrapped true))) diff --git a/test/blackbox-tests/test-cases/variants-only-package/vlibfoo.opam b/test/blackbox-tests/test-cases/variants-only-package/vlibfoo.opam new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/variants-only-package/vlibfoo/dune b/test/blackbox-tests/test-cases/variants-only-package/vlibfoo/dune new file mode 100644 index 00000000000..45399090dd3 --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-only-package/vlibfoo/dune @@ -0,0 +1,5 @@ +(library + (name vlibfoo) + (public_name vlibfoo) + (virtual_modules vlibfoo) +) diff --git a/test/blackbox-tests/test-cases/variants-only-package/vlibfoo/vlibfoo.mli b/test/blackbox-tests/test-cases/variants-only-package/vlibfoo/vlibfoo.mli new file mode 100644 index 00000000000..56a52c4170a --- /dev/null +++ b/test/blackbox-tests/test-cases/variants-only-package/vlibfoo/vlibfoo.mli @@ -0,0 +1 @@ +val implme : unit -> unit diff --git a/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/dune b/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/dune index 3a97cf5f5f9..605f5d60a4a 100644 --- a/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/dune +++ b/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/dune @@ -1,7 +1,7 @@ (executable (name bar) (libraries vlib) - (variants default)) + (variants a b)) (alias (name default) diff --git a/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib.b/dune b/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib.b/dune new file mode 100644 index 00000000000..064a7eb758c --- /dev/null +++ b/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib.b/dune @@ -0,0 +1,4 @@ +(library + (name lib_b) + (implements vlib) + (variant b)) diff --git a/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib.default/vlib.ml b/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib.b/vlib.ml similarity index 100% rename from test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib.default/vlib.ml rename to test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib.b/vlib.ml diff --git a/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib.default/dune b/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib.default/dune deleted file mode 100644 index 53e8b77eacd..00000000000 --- a/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib.default/dune +++ /dev/null @@ -1,4 +0,0 @@ -(library - (name lib_default) - (implements vlib) - (variant default)) diff --git a/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib2.a/dune b/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib2.a/dune new file mode 100644 index 00000000000..cefe6024d2e --- /dev/null +++ b/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib2.a/dune @@ -0,0 +1,4 @@ +(library + (name lib2_a) + (implements vlib) + (variant a)) diff --git a/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib2.default/vlib.ml b/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib2.a/vlib.ml similarity index 100% rename from test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib2.default/vlib.ml rename to test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib2.a/vlib.ml diff --git a/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib2.default/dune b/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib2.default/dune deleted file mode 100644 index 59fa416dfdb..00000000000 --- a/test/blackbox-tests/test-cases/variants/multiple-implementations-for-variants/lib2.default/dune +++ /dev/null @@ -1,4 +0,0 @@ -(library - (name lib2_default) - (implements vlib) - (variant default)) diff --git a/test/blackbox-tests/test-cases/variants/run.t b/test/blackbox-tests/test-cases/variants/run.t index 4b73da7b0bf..8a327550a44 100644 --- a/test/blackbox-tests/test-cases/variants/run.t +++ b/test/blackbox-tests/test-cases/variants/run.t @@ -12,13 +12,13 @@ Having multiple implementations of the same library with respect to selected variants results in an appropriate error message. $ dune build --root multiple-implementations-for-variants Entering directory 'multiple-implementations-for-variants' - File "dune", line 4, characters 11-18: - 4 | (variants default)) - ^^^^^^^ + File "dune", line 4, characters 11-14: + 4 | (variants a b)) + ^^^ Error: Multiple solutions for the implementation - of vlib with variants [ "default" ] - -> lib2_default ("default") - -> lib_default ("default") + of vlib with variants [ "a"; "b" ] + -> lib_b ("b") + -> lib2_a ("a") -> required by executable bar in dune:2 [1] @@ -52,7 +52,6 @@ Check that variant data is installed in the dune package file. (foreign_archives (native a$ext_lib)) (requires b) (implements b) - (variant test) (main_module_name B) (modes byte native) (modules @@ -60,6 +59,23 @@ Check that variant data is installed in the dune package file. (main_module_name B) (modules ((name X) (obj_name b__X) (visibility public) (impl))) (wrapped true))) + $ cat dune-package/_build/install/default/lib/b/dune-package + (lang dune 1.10) + (name b) + (library + (name b) + (kind normal) + (virtual) + (foreign_archives (native b$ext_lib)) + (known_implementations (test a)) + (main_module_name B) + (modes byte native) + (modules + (alias_module (name B) (obj_name b) (visibility public) (impl)) + (main_module_name B) + (modules + ((name X) (obj_name b__X) (visibility public) (kind virtual) (intf))) + (wrapped true))) Test variants for an external library @@ -73,11 +89,13 @@ Then we make sure that it works fine. bar alias default hey -Solving variant ambiguity by specifying a concrete implementation. +Variant ambiguity is forbidden even if a concrete implementation is provided. $ dune build --root variant-with-concrete-impl Entering directory 'variant-with-concrete-impl' - bar alias default - hello from lib2.default + Error: Two implementations of vlib have the same variant "default": + - lib2_default (lib2.default/dune:1) + - lib_default (lib.default/dune:1) + [1] Don't fail when the same library is defined in multiple scopes. $ dune build --root same-lib-in-multiple-scopes