let link_gen cmX_ext cma_ext a_ext extensions linker tagger cmX out env build =
  let cmX = env cmX and out = env out in
  let tags = tagger (tags_of_pathname out) in
  let dyndeps = Rule.build_deps_of_tags build (tags++"link_with"in
  let cmi = Pathname.update_extensions "cmi" cmX in
  prepare_link cmX cmi extensions build;
  let libs = prepare_libs cma_ext a_ext out build in
  let hidden_packages = List.map (fun x -> x-.-cmX_ext) !hidden_packages in
  let deps =
    caml_transitive_closure
      ~caml_obj_ext:cmX_ext ~caml_lib_ext:cma_ext
      ~used_libraries:libs ~hidden_packages (cmX :: dyndeps) in
  let deps = (List.filter (fun l -> not (List.mem l deps)) libs) @ deps in

  (* Hack to avoid linking twice with the standard library. *)
  let stdlib = "stdlib/stdlib"-.-cma_ext in
  let is_not_stdlib x = x <> stdlib in
  let deps = List.filter is_not_stdlib deps in

  if deps = [] then failwith "Link list cannot be empty";
  let () = dprintf 6 "link: %a -o %a" print_string_list deps Pathname.print out in
  linker (tags++"dont_link_with") deps out