Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Have Dune warn us of unnecessary library dependencies #11061

Open
nojb opened this issue Oct 31, 2024 · 1 comment
Open

Have Dune warn us of unnecessary library dependencies #11061

nojb opened this issue Oct 31, 2024 · 1 comment

Comments

@nojb
Copy link
Collaborator

nojb commented Oct 31, 2024

Listing unnecessary libraries in the (libraries ...) field of executables and libraries is not harmless at the moment due to the way dependencies are computed in Dune: this can cause potentially a lot of unnecessary recompilation, as any change in the "unused" dependency will cause the recompilation of the whole executable/library.

Having some way of knowing if one has included unnecessary libraries in (libraries ...) would thus be quite useful.

@alainfrisch
Copy link

It's rather straightforward to instrument ocamlc/ocamlopt to dump which of the libraries specified on the command-line (when linking an executable) have actually been linked. Or, without patching the compiler, one can replicate the logic with a simple script like:

let required = Hashtbl.create 17
let add_required (name, _crc) = Hashtbl.replace required name ()
let used_libs = ref []

let scan_file obj_name =
  let file_name =
    try Load_path.find obj_name
    with Not_found -> failwith (Printf.sprintf "File not found: %s" obj_name)
  in
  if Filename.check_suffix file_name ".cmx" then begin
    let (info, _) = Compilenv.read_unit_info file_name in
    List.iter add_required info.ui_imports_cmx
  end else if Filename.check_suffix file_name ".cmxa" then begin
    let infos =
      try Compilenv.read_library_info file_name
      with Compilenv.Error(Not_a_unit_info _) ->
        failwith (Printf.sprintf "Not an object file: %s" file_name)
    in
    let trace = lazy (used_libs := file_name :: !used_libs) in
    List.iter
      (fun (info, _) ->
         if info.Cmx_format.ui_force_link || Hashtbl.mem required info.ui_name
         then begin
           Lazy.force trace;
           List.iter add_required info.ui_imports_cmx
         end
      )
      (List.rev infos.lib_units)
  end else
    failwith (Printf.sprintf "Not an object file: %s" file_name)

let () =
  let files = ref [] in
  Arg.parse
    [ "-I", Arg.String Load_path.add_dir, "" ]
    (fun file -> files := file :: !files) "Usage: ...";
  List.iter scan_file !files; (* reverse order *)
  List.iter print_endline !used_libs

Note that even if a library is not considered to be needed by the linker, it could still be needed to consider it as dune library dependency to allowing type-checking the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants