···37373838### Compiler user-interface and warnings:
39394040+* #12084: Check link order when creating archive and when using ocamlopt
4141+ (Hugo Heuzard, review by Stefan Muenzel and Sébastien Hinderer)
4242+4043### Internal/compiler-libs changes:
41444245- #12896: Simplify the compilation of custom bytecode runtimes by explicitly
···11File "_none_", line 1:
22-Error: Wrong link order: "Lib" depends on "Main"
22+Error: Wrong link order: "Lib" (lib.cmo) depends on "Main" (main.cmo)
33+File "_none_", line 1:
44+Error: Wrong link order: "Lib" (lib.cmo) depends on "Main" (main.cmo)
55+File "_none_", line 1:
66+Error: No implementation provided for the following modules:
77+ "Main" referenced from "Lib" (lib.cmo)
···11+File "_none_", line 1:
22+Error: Wrong link order: "Lib" (lib.cmx) depends on "Main" (main.cmx)
33+File "_none_", line 1:
44+Error: Wrong link order: "Lib" (lib.cmx) depends on "Main" (main.cmx)
55+File "_none_", line 1:
66+Error: No implementation provided for the following modules:
77+ "Main" referenced from "Lib" (lib.cmx)
···11+(**************************************************************************)
22+(* *)
33+(* OCaml *)
44+(* *)
55+(* Hugo Heuzard *)
66+(* *)
77+(* Copyright 2020 Institut National de Recherche en Informatique et *)
88+(* en Automatique. *)
99+(* *)
1010+(* All rights reserved. This file is distributed under the terms of *)
1111+(* the GNU Lesser General Public License version 2.1, with the *)
1212+(* special exception on linking described in the file LICENSE. *)
1313+(* *)
1414+(**************************************************************************)
1515+1616+module Style = Misc.Style
1717+1818+type compunit = string
1919+2020+type filename = string
2121+2222+type compunit_and_source = {
2323+ compunit : compunit;
2424+ filename : filename;
2525+}
2626+2727+module Compunit_and_source = struct
2828+ type t = compunit_and_source
2929+ module Set = Set.Make(struct type nonrec t = t let compare = compare end)
3030+end
3131+3232+type refs = Compunit_and_source.Set.t
3333+3434+type t = {
3535+ complete : bool;
3636+ missing_compunits : (compunit, refs) Hashtbl.t;
3737+ provided_compunits : (compunit, filename list) Hashtbl.t;
3838+ badly_ordered_deps : (Compunit_and_source.t, refs) Hashtbl.t;
3939+}
4040+4141+type error =
4242+ | Missing_implementations of (compunit * compunit_and_source list) list
4343+ | Wrong_link_order of (compunit_and_source * compunit_and_source list) list
4444+ | Multiple_definitions of (compunit * filename list) list
4545+4646+let create ~complete = {
4747+ complete;
4848+ missing_compunits = Hashtbl.create 17;
4949+ provided_compunits = Hashtbl.create 17;
5050+ badly_ordered_deps = Hashtbl.create 17;
5151+}
5252+5353+let required t compunit = Hashtbl.mem t.missing_compunits compunit
5454+5555+let update t k f =
5656+ let v = Hashtbl.find_opt t k in
5757+ Hashtbl.replace t k (f v)
5858+5959+let add_required t by (name : string) =
6060+ let add s =
6161+ Compunit_and_source.Set.add by
6262+ (Option.value s ~default:Compunit_and_source.Set.empty) in
6363+ (try
6464+ let filename = List.hd (Hashtbl.find t.provided_compunits name) in
6565+ update t.badly_ordered_deps {compunit = name; filename } add
6666+ with Not_found -> ());
6767+ update t.missing_compunits name add
6868+6969+let add t ~filename ~compunit ~provides ~requires =
7070+ List.iter (add_required t {compunit; filename}) requires;
7171+ List.iter (fun p ->
7272+ Hashtbl.remove t.missing_compunits p;
7373+ let l = Option.value ~default:[]
7474+ (Hashtbl.find_opt t.provided_compunits p) in
7575+ Hashtbl.replace t.provided_compunits p (filename :: l)) provides
7676+7777+let check t =
7878+ let of_seq s =
7979+ Seq.map (fun (k,v) -> k, Compunit_and_source.Set.elements v) s
8080+ |> List.of_seq
8181+ in
8282+ let missing = of_seq (Hashtbl.to_seq t.missing_compunits) in
8383+ let badly_ordered_deps = of_seq (Hashtbl.to_seq t.badly_ordered_deps) in
8484+ let duplicated =
8585+ Hashtbl.to_seq t.provided_compunits
8686+ |> Seq.filter (fun (_, files) -> List.compare_length_with files 1 > 0)
8787+ |> List.of_seq
8888+ in
8989+ match duplicated, badly_ordered_deps, missing with
9090+ | [], [], [] -> None
9191+ | [], [], l ->
9292+ if t.complete
9393+ then Some (Missing_implementations l)
9494+ else None
9595+ | [], l, _ ->
9696+ Some (Wrong_link_order l)
9797+ | l, _, _ ->
9898+ Some (Multiple_definitions l)
9999+100100+(* Error report *)
101101+102102+open Format
103103+104104+let print_reference print_fname ppf {compunit; filename} =
105105+ fprintf ppf "%a (%a)" Style.inline_code compunit print_fname filename
106106+107107+let pp_list_comma f =
108108+ pp_print_list ~pp_sep:(fun ppf () -> fprintf ppf ",@ ") f
109109+110110+let report_error ~print_filename ppf = function
111111+ | Missing_implementations l ->
112112+ let print_modules ppf =
113113+ List.iter
114114+ (fun (md, rq) ->
115115+ fprintf ppf "@ @[<hov 2>%a referenced from %a@]"
116116+ Style.inline_code md
117117+ (pp_list_comma (print_reference print_filename)) rq)
118118+ in
119119+ fprintf ppf
120120+ "@[<v 2>No implementation provided for the following modules:%a@]"
121121+ print_modules l
122122+ | Wrong_link_order l ->
123123+ let depends_on ppf (dep, depending) =
124124+ fprintf ppf "@ @[<hov 2>%a depends on %a@]"
125125+ (pp_list_comma (print_reference print_filename)) depending
126126+ (print_reference print_filename) dep
127127+ in
128128+ fprintf ppf "@[<hov 2>Wrong link order:%a@]"
129129+ (pp_list_comma depends_on) l
130130+ | Multiple_definitions l ->
131131+ let print ppf (compunit, files) =
132132+ fprintf ppf
133133+ "@ @[<hov>Multiple definitions of module %a in files %a@]"
134134+ Style.inline_code compunit
135135+ (pp_list_comma (Style.as_inline_code print_filename)) files
136136+137137+ in
138138+ fprintf ppf "@[<hov 2> Duplicated implementations:%a@]"
139139+ (pp_list_comma print) l
+64
utils/linkdeps.mli
···11+(**************************************************************************)
22+(* *)
33+(* OCaml *)
44+(* *)
55+(* Hugo Heuzard *)
66+(* *)
77+(* Copyright 2020 Institut National de Recherche en Informatique et *)
88+(* en Automatique. *)
99+(* *)
1010+(* All rights reserved. This file is distributed under the terms of *)
1111+(* the GNU Lesser General Public License version 2.1, with the *)
1212+(* special exception on linking described in the file LICENSE. *)
1313+(* *)
1414+(**************************************************************************)
1515+1616+type t
1717+(** The state of the linking check.
1818+ It keeps track of compilation units provided and required so far. *)
1919+2020+type compunit = string
2121+2222+type filename = string
2323+2424+val create : complete:bool -> t
2525+(** [create ~complete] returns an empty state. If [complete] is
2626+ [true], missing compilation units will be treated as errors. *)
2727+2828+val add : t
2929+ -> filename:filename -> compunit:compunit
3030+ -> provides:compunit list -> requires:compunit list -> unit
3131+(** [add t ~filename ~compunit ~provides ~requires] registers the
3232+ compilation unit [compunit] found in [filename] to [t].
3333+ - [provides] are units and sub-units provided by [compunit]
3434+ - [requires] are units required by [compunit]
3535+3636+ [add] should be called in reverse topological order. *)
3737+3838+val required : t -> compunit -> bool
3939+(** [required t compunit] returns [true] if [compunit] is a dependency of
4040+ previously added compilation units. *)
4141+4242+type compunit_and_source = {
4343+ compunit : compunit;
4444+ filename : filename;
4545+}
4646+4747+type error =
4848+ | Missing_implementations of (compunit * compunit_and_source list) list
4949+ | Wrong_link_order of (compunit_and_source * compunit_and_source list) list
5050+ | Multiple_definitions of (compunit * filename list) list
5151+5252+val check : t -> error option
5353+(** [check t] should be called once all the compilation units to be linked
5454+ have been added. It retuns some error if:
5555+ - There are some missing implementations
5656+ and [complete] is [true]
5757+ - Some implementation appear
5858+ before their dependencies *)
5959+6060+open Format
6161+6262+val report_error
6363+ : print_filename:(formatter -> string -> unit)
6464+ -> formatter -> error -> unit