Detect overlapping libraries
This commit is contained in:
parent
b5cb3c94b4
commit
a5f9a9e063
69
src/lib.ml
69
src/lib.ml
|
@ -253,6 +253,7 @@ and error =
|
||||||
| No_solution_found_for_select of Error0.No_solution_found_for_select.t
|
| No_solution_found_for_select of Error0.No_solution_found_for_select.t
|
||||||
| Dependency_cycle of (Path.t * string) list
|
| Dependency_cycle of (Path.t * string) list
|
||||||
| Conflict of conflict
|
| Conflict of conflict
|
||||||
|
| Overlap of overlap
|
||||||
|
|
||||||
and resolve_result =
|
and resolve_result =
|
||||||
| Not_found
|
| Not_found
|
||||||
|
@ -265,6 +266,11 @@ and conflict =
|
||||||
; lib2 : t * Dep_path.Entry.t list
|
; lib2 : t * Dep_path.Entry.t list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
and overlap =
|
||||||
|
{ in_workspace : t
|
||||||
|
; installed : t * Dep_path.Entry.t list
|
||||||
|
}
|
||||||
|
|
||||||
and 'a or_error = ('a, exn) result
|
and 'a or_error = ('a, exn) result
|
||||||
|
|
||||||
type lib = t
|
type lib = t
|
||||||
|
@ -279,11 +285,19 @@ module Error = struct
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Overlap = struct
|
||||||
|
type nonrec t = overlap =
|
||||||
|
{ in_workspace : t
|
||||||
|
; installed : t * Dep_path.Entry.t list
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
type t = error =
|
type t = error =
|
||||||
| Library_not_available of Library_not_available.t
|
| Library_not_available of Library_not_available.t
|
||||||
| No_solution_found_for_select of No_solution_found_for_select.t
|
| No_solution_found_for_select of No_solution_found_for_select.t
|
||||||
| Dependency_cycle of (Path.t * string) list
|
| Dependency_cycle of (Path.t * string) list
|
||||||
| Conflict of Conflict.t
|
| Conflict of Conflict.t
|
||||||
|
| Overlap of Overlap.t
|
||||||
end
|
end
|
||||||
|
|
||||||
exception Error of Error.t
|
exception Error of Error.t
|
||||||
|
@ -742,7 +756,7 @@ and resolve_user_deps db deps ~pps ~stack =
|
||||||
let pps =
|
let pps =
|
||||||
let pps = (pps : (Loc.t * Jbuild.Pp.t) list :> (Loc.t * string) list) in
|
let pps = (pps : (Loc.t * Jbuild.Pp.t) list :> (Loc.t * string) list) in
|
||||||
resolve_simple_deps db pps ~stack >>= fun pps ->
|
resolve_simple_deps db pps ~stack >>= fun pps ->
|
||||||
closure pps ~stack
|
closure_with_overlap_checks None pps ~stack
|
||||||
in
|
in
|
||||||
let deps =
|
let deps =
|
||||||
let rec loop acc = function
|
let rec loop acc = function
|
||||||
|
@ -759,7 +773,7 @@ and resolve_user_deps db deps ~pps ~stack =
|
||||||
in
|
in
|
||||||
(deps, pps, resolved_selects)
|
(deps, pps, resolved_selects)
|
||||||
|
|
||||||
and closure ts ~stack =
|
and closure_with_overlap_checks db ts ~stack =
|
||||||
let visited = ref String_map.empty in
|
let visited = ref String_map.empty in
|
||||||
let res = ref [] in
|
let res = ref [] in
|
||||||
let orig_stack = stack in
|
let orig_stack = stack in
|
||||||
|
@ -776,6 +790,23 @@ and closure ts ~stack =
|
||||||
}))
|
}))
|
||||||
| None ->
|
| None ->
|
||||||
visited := String_map.add !visited t.name (t, stack);
|
visited := String_map.add !visited t.name (t, stack);
|
||||||
|
(match db with
|
||||||
|
| None -> Ok ()
|
||||||
|
| Some db ->
|
||||||
|
match find_internal db t.name ~stack with
|
||||||
|
| St_found t' ->
|
||||||
|
if t.unique_id = t'.unique_id then
|
||||||
|
Ok ()
|
||||||
|
else begin
|
||||||
|
let req_by = Dep_stack.to_required_by stack ~stop_at:orig_stack in
|
||||||
|
Error
|
||||||
|
(Error (Overlap
|
||||||
|
{ in_workspace = t'
|
||||||
|
; installed = (t, req_by)
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
| _ -> assert false)
|
||||||
|
>>= fun () ->
|
||||||
Dep_stack.push stack (to_id t) >>= fun stack ->
|
Dep_stack.push stack (to_id t) >>= fun stack ->
|
||||||
t.requires >>= fun deps ->
|
t.requires >>= fun deps ->
|
||||||
iter deps ~stack >>| fun () ->
|
iter deps ~stack >>| fun () ->
|
||||||
|
@ -790,7 +821,10 @@ and closure ts ~stack =
|
||||||
iter ts ~stack >>| fun () ->
|
iter ts ~stack >>| fun () ->
|
||||||
List.rev !res
|
List.rev !res
|
||||||
|
|
||||||
let closure l = closure l ~stack:Dep_stack.empty
|
let closure_with_overlap_checks db l =
|
||||||
|
closure_with_overlap_checks db l ~stack:Dep_stack.empty
|
||||||
|
|
||||||
|
let closure l = closure_with_overlap_checks None l
|
||||||
|
|
||||||
let to_exn res =
|
let to_exn res =
|
||||||
match res with
|
match res with
|
||||||
|
@ -824,9 +858,9 @@ module Compile = struct
|
||||||
; sub_systems = Sub_system_name.Map.empty
|
; sub_systems = Sub_system_name.Map.empty
|
||||||
}
|
}
|
||||||
|
|
||||||
let for_lib (t : lib) =
|
let for_lib db (t : lib) =
|
||||||
{ direct_requires = t.requires
|
{ direct_requires = t.requires
|
||||||
; requires = t.requires >>= closure
|
; requires = t.requires >>= closure_with_overlap_checks db
|
||||||
; resolved_selects = t.resolved_selects
|
; resolved_selects = t.resolved_selects
|
||||||
; pps = t.pps
|
; pps = t.pps
|
||||||
; optional = t.optional
|
; optional = t.optional
|
||||||
|
@ -950,21 +984,28 @@ module DB = struct
|
||||||
|
|
||||||
let available t name = available_internal t name ~stack:Dep_stack.empty
|
let available t name = available_internal t name ~stack:Dep_stack.empty
|
||||||
|
|
||||||
let get_compile_info t name =
|
let get_compile_info t ?(allow_overlaps=false) name =
|
||||||
match find_even_when_hidden t name with
|
match find_even_when_hidden t name with
|
||||||
| None ->
|
| None ->
|
||||||
Sexp.code_error "Lib.DB.get_compile_info got library that doesn't exist"
|
Sexp.code_error "Lib.DB.get_compile_info got library that doesn't exist"
|
||||||
[ "name", Sexp.To_sexp.string name ]
|
[ "name", Sexp.To_sexp.string name ]
|
||||||
| Some lib -> Compile.for_lib lib
|
| Some lib ->
|
||||||
|
let t = Option.some_if (not allow_overlaps) t in
|
||||||
|
Compile.for_lib t lib
|
||||||
|
|
||||||
let resolve_user_written_deps t deps ~pps =
|
let resolve_user_written_deps t ?(allow_overlaps=false) deps ~pps =
|
||||||
let res, pps, resolved_selects =
|
let res, pps, resolved_selects =
|
||||||
resolve_user_deps t (Info.Deps.of_lib_deps deps) ~pps
|
resolve_user_deps t (Info.Deps.of_lib_deps deps) ~pps
|
||||||
~stack:Dep_stack.empty
|
~stack:Dep_stack.empty
|
||||||
in
|
in
|
||||||
|
let requires =
|
||||||
|
res
|
||||||
|
>>=
|
||||||
|
closure_with_overlap_checks (Option.some_if (not allow_overlaps) t)
|
||||||
|
in
|
||||||
{ Compile.
|
{ Compile.
|
||||||
direct_requires = res
|
direct_requires = res
|
||||||
; requires = res >>= closure
|
; requires
|
||||||
; pps
|
; pps
|
||||||
; resolved_selects
|
; resolved_selects
|
||||||
; optional = false
|
; optional = false
|
||||||
|
@ -1039,6 +1080,16 @@ let report_lib_error ppf (e : Error.t) =
|
||||||
Dep_path.Entries.pp rb1
|
Dep_path.Entries.pp rb1
|
||||||
lib2.name (Path.to_string_maybe_quoted lib2.src_dir)
|
lib2.name (Path.to_string_maybe_quoted lib2.src_dir)
|
||||||
Dep_path.Entries.pp rb2
|
Dep_path.Entries.pp rb2
|
||||||
|
| Overlap { in_workspace = lib1; installed = (lib2, rb2) } ->
|
||||||
|
Format.fprintf ppf
|
||||||
|
"@[<v>@{<error>Error@}: Conflict between the following libraries:@,\
|
||||||
|
- %S in %s@,\
|
||||||
|
- %S in %s@,\
|
||||||
|
\ %a@,\
|
||||||
|
This is not allowed.@\n"
|
||||||
|
lib1.name (Path.to_string_maybe_quoted lib1.src_dir)
|
||||||
|
lib2.name (Path.to_string_maybe_quoted lib2.src_dir)
|
||||||
|
Dep_path.Entries.pp rb2
|
||||||
| No_solution_found_for_select { loc } ->
|
| No_solution_found_for_select { loc } ->
|
||||||
Format.fprintf ppf
|
Format.fprintf ppf
|
||||||
"%a@{<error>Error@}: No solution found for this select form.\n"
|
"%a@{<error>Error@}: No solution found for this select form.\n"
|
||||||
|
|
13
src/lib.mli
13
src/lib.mli
|
@ -137,11 +137,21 @@ module Error : sig
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Overlap : sig
|
||||||
|
(** A conflict that doesn't prevent compilation, but that we still
|
||||||
|
consider as an error to avoid surprises. *)
|
||||||
|
type nonrec t =
|
||||||
|
{ in_workspace : t
|
||||||
|
; installed : t * Dep_path.Entry.t list
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
type t =
|
type t =
|
||||||
| Library_not_available of Library_not_available.t
|
| Library_not_available of Library_not_available.t
|
||||||
| No_solution_found_for_select of No_solution_found_for_select.t
|
| No_solution_found_for_select of No_solution_found_for_select.t
|
||||||
| Dependency_cycle of (Path.t * string) list
|
| Dependency_cycle of (Path.t * string) list
|
||||||
| Conflict of Conflict.t
|
| Conflict of Conflict.t
|
||||||
|
| Overlap of Overlap.t
|
||||||
end
|
end
|
||||||
|
|
||||||
exception Error of Error.t
|
exception Error of Error.t
|
||||||
|
@ -244,7 +254,7 @@ module DB : sig
|
||||||
|
|
||||||
(** Retreive the compile informations for the given library. Works
|
(** Retreive the compile informations for the given library. Works
|
||||||
for libraries that are optional and not available as well. *)
|
for libraries that are optional and not available as well. *)
|
||||||
val get_compile_info : t -> string -> Compile.t
|
val get_compile_info : t -> ?allow_overlaps:bool -> string -> Compile.t
|
||||||
|
|
||||||
val resolve : t -> Loc.t * string -> (lib, exn) result
|
val resolve : t -> Loc.t * string -> (lib, exn) result
|
||||||
|
|
||||||
|
@ -255,6 +265,7 @@ module DB : sig
|
||||||
This function is for executables stanzas. *)
|
This function is for executables stanzas. *)
|
||||||
val resolve_user_written_deps
|
val resolve_user_written_deps
|
||||||
: t
|
: t
|
||||||
|
-> ?allow_overlaps:bool
|
||||||
-> Jbuild.Lib_dep.t list
|
-> Jbuild.Lib_dep.t list
|
||||||
-> pps:(Loc.t * Jbuild.Pp.t) list
|
-> pps:(Loc.t * Jbuild.Pp.t) list
|
||||||
-> Compile.t
|
-> Compile.t
|
||||||
|
|
Loading…
Reference in New Issue