2016-02-18 07:11:59 -08:00
|
|
|
(**************************************************************************)
|
|
|
|
(* *)
|
|
|
|
(* OCaml *)
|
|
|
|
(* *)
|
|
|
|
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
|
|
|
|
(* *)
|
|
|
|
(* Copyright 2002 Institut National de Recherche en Informatique et *)
|
|
|
|
(* en Automatique. *)
|
|
|
|
(* *)
|
|
|
|
(* All rights reserved. This file is distributed under the terms of *)
|
|
|
|
(* the GNU Lesser General Public License version 2.1, with the *)
|
|
|
|
(* special exception on linking described in the file LICENSE. *)
|
|
|
|
(* *)
|
|
|
|
(**************************************************************************)
|
2002-02-08 08:55:44 -08:00
|
|
|
|
|
|
|
(* "Package" a set of .cmo files into one .cmo file having the
|
|
|
|
original compilation units as sub-modules. *)
|
|
|
|
|
|
|
|
open Misc
|
|
|
|
open Instruct
|
2006-05-11 08:50:53 -07:00
|
|
|
open Cmo_format
|
2018-07-23 05:19:41 -07:00
|
|
|
module String = Misc.Stdlib.String
|
2014-04-06 08:06:22 -07:00
|
|
|
|
2002-02-08 08:55:44 -08:00
|
|
|
type error =
|
|
|
|
Forward_reference of string * Ident.t
|
|
|
|
| Multiple_definition of string * Ident.t
|
|
|
|
| Not_an_object_file of string
|
2013-04-29 07:57:38 -07:00
|
|
|
| Illegal_renaming of string * string * string
|
2002-02-08 08:55:44 -08:00
|
|
|
| File_not_found of string
|
|
|
|
|
|
|
|
exception Error of error
|
|
|
|
|
2010-05-21 05:00:49 -07:00
|
|
|
(* References accumulating information on the .cmo files *)
|
2002-02-08 08:55:44 -08:00
|
|
|
|
|
|
|
let relocs = ref ([] : (reloc_info * int) list)
|
|
|
|
let events = ref ([] : debug_event list)
|
2018-07-23 05:19:41 -07:00
|
|
|
let debug_dirs = ref String.Set.empty
|
2002-02-08 08:55:44 -08:00
|
|
|
let primitives = ref ([] : string list)
|
|
|
|
let force_link = ref false
|
|
|
|
|
|
|
|
(* Record a relocation. Update its offset, and rename GETGLOBAL and
|
|
|
|
SETGLOBAL relocations that correspond to one of the units being
|
|
|
|
consolidated. *)
|
|
|
|
|
2011-07-20 02:17:07 -07:00
|
|
|
let rename_relocation packagename objfile mapping defined base (rel, ofs) =
|
2002-02-08 08:55:44 -08:00
|
|
|
let rel' =
|
|
|
|
match rel with
|
|
|
|
Reloc_getglobal id ->
|
|
|
|
begin try
|
|
|
|
let id' = List.assoc id mapping in
|
|
|
|
if List.mem id defined
|
|
|
|
then Reloc_getglobal id'
|
|
|
|
else raise(Error(Forward_reference(objfile, id)))
|
|
|
|
with Not_found ->
|
2011-07-20 02:17:07 -07:00
|
|
|
(* PR#5276: unique-ize dotted global names, which appear
|
|
|
|
if one of the units being consolidated is itself a packed
|
|
|
|
module. *)
|
|
|
|
let name = Ident.name id in
|
|
|
|
if String.contains name '.' then
|
|
|
|
Reloc_getglobal (Ident.create_persistent (packagename ^ "." ^ name))
|
|
|
|
else
|
|
|
|
rel
|
2002-02-08 08:55:44 -08:00
|
|
|
end
|
|
|
|
| Reloc_setglobal id ->
|
|
|
|
begin try
|
|
|
|
let id' = List.assoc id mapping in
|
|
|
|
if List.mem id defined
|
|
|
|
then raise(Error(Multiple_definition(objfile, id)))
|
|
|
|
else Reloc_setglobal id'
|
|
|
|
with Not_found ->
|
2011-07-20 02:17:07 -07:00
|
|
|
(* PR#5276, as above *)
|
|
|
|
let name = Ident.name id in
|
|
|
|
if String.contains name '.' then
|
2012-07-30 11:04:46 -07:00
|
|
|
Reloc_setglobal (Ident.create_persistent (packagename ^ "." ^ name))
|
2011-07-20 02:17:07 -07:00
|
|
|
else
|
|
|
|
rel
|
2002-02-08 08:55:44 -08:00
|
|
|
end
|
|
|
|
| _ ->
|
|
|
|
rel in
|
|
|
|
relocs := (rel', base + ofs) :: !relocs
|
|
|
|
|
|
|
|
(* Record and relocate a debugging event *)
|
|
|
|
|
2009-05-20 04:52:42 -07:00
|
|
|
let relocate_debug base prefix subst ev =
|
|
|
|
let ev' = { ev with ev_pos = base + ev.ev_pos;
|
|
|
|
ev_module = prefix ^ "." ^ ev.ev_module;
|
|
|
|
ev_typsubst = Subst.compose ev.ev_typsubst subst } in
|
|
|
|
events := ev' :: !events
|
2002-02-08 08:55:44 -08:00
|
|
|
|
|
|
|
(* Read the unit information from a .cmo file. *)
|
|
|
|
|
2004-04-09 06:32:28 -07:00
|
|
|
type pack_member_kind = PM_intf | PM_impl of compilation_unit
|
|
|
|
|
|
|
|
type pack_member =
|
|
|
|
{ pm_file: string;
|
|
|
|
pm_name: string;
|
|
|
|
pm_kind: pack_member_kind }
|
|
|
|
|
2013-04-29 07:57:38 -07:00
|
|
|
let read_member_info file = (
|
2004-04-09 06:32:28 -07:00
|
|
|
let name =
|
2014-12-21 03:46:14 -08:00
|
|
|
String.capitalize_ascii(Filename.basename(chop_extensions file)) in
|
2004-04-09 06:32:28 -07:00
|
|
|
let kind =
|
2017-02-19 08:47:33 -08:00
|
|
|
(* PR#7479: make sure it is either a .cmi or a .cmo *)
|
|
|
|
if Filename.check_suffix file ".cmi" then
|
|
|
|
PM_intf
|
|
|
|
else begin
|
|
|
|
let ic = open_in_bin file in
|
|
|
|
try
|
|
|
|
let buffer =
|
|
|
|
really_input_string ic (String.length Config.cmo_magic_number)
|
|
|
|
in
|
|
|
|
if buffer <> Config.cmo_magic_number then
|
|
|
|
raise(Error(Not_an_object_file file));
|
|
|
|
let compunit_pos = input_binary_int ic in
|
|
|
|
seek_in ic compunit_pos;
|
|
|
|
let compunit = (input_value ic : compilation_unit) in
|
|
|
|
if compunit.cu_name <> name
|
|
|
|
then raise(Error(Illegal_renaming(name, file, compunit.cu_name)));
|
|
|
|
close_in ic;
|
|
|
|
PM_impl compunit
|
|
|
|
with x ->
|
|
|
|
close_in ic;
|
|
|
|
raise x
|
|
|
|
end in
|
2004-04-09 06:32:28 -07:00
|
|
|
{ pm_file = file; pm_name = name; pm_kind = kind }
|
2013-04-29 07:57:38 -07:00
|
|
|
)
|
2002-02-08 08:55:44 -08:00
|
|
|
|
|
|
|
(* Read the bytecode from a .cmo file.
|
|
|
|
Write bytecode to channel [oc].
|
|
|
|
Rename globals as indicated by [mapping] in reloc info.
|
|
|
|
Accumulate relocs, debug info, etc.
|
|
|
|
Return size of bytecode. *)
|
|
|
|
|
2018-07-15 12:00:47 -07:00
|
|
|
let rename_append_bytecode packagename oc mapping defined ofs prefix subst
|
2013-03-09 14:38:52 -08:00
|
|
|
objfile compunit =
|
2002-02-08 08:55:44 -08:00
|
|
|
let ic = open_in_bin objfile in
|
|
|
|
try
|
2018-07-15 12:00:47 -07:00
|
|
|
Bytelink.check_consistency objfile compunit;
|
2002-02-08 08:55:44 -08:00
|
|
|
List.iter
|
2011-07-20 02:17:07 -07:00
|
|
|
(rename_relocation packagename objfile mapping defined ofs)
|
2002-02-08 08:55:44 -08:00
|
|
|
compunit.cu_reloc;
|
|
|
|
primitives := compunit.cu_primitives @ !primitives;
|
|
|
|
if compunit.cu_force_link then force_link := true;
|
|
|
|
seek_in ic compunit.cu_pos;
|
|
|
|
Misc.copy_file_chunk ic oc compunit.cu_codesize;
|
|
|
|
if !Clflags.debug && compunit.cu_debug > 0 then begin
|
|
|
|
seek_in ic compunit.cu_debug;
|
2009-05-20 04:52:42 -07:00
|
|
|
List.iter (relocate_debug ofs prefix subst) (input_value ic);
|
2014-04-06 08:06:22 -07:00
|
|
|
debug_dirs := List.fold_left
|
2018-07-23 05:19:41 -07:00
|
|
|
(fun s e -> String.Set.add e s)
|
2014-04-06 08:06:22 -07:00
|
|
|
!debug_dirs
|
|
|
|
(input_value ic);
|
2002-02-08 08:55:44 -08:00
|
|
|
end;
|
|
|
|
close_in ic;
|
|
|
|
compunit.cu_codesize
|
|
|
|
with x ->
|
|
|
|
close_in ic;
|
|
|
|
raise x
|
|
|
|
|
2004-04-09 06:32:28 -07:00
|
|
|
(* Same, for a list of .cmo and .cmi files.
|
|
|
|
Return total size of bytecode. *)
|
2002-02-08 08:55:44 -08:00
|
|
|
|
2018-07-15 12:00:47 -07:00
|
|
|
let rec rename_append_bytecode_list packagename oc mapping defined ofs
|
2013-03-09 14:38:52 -08:00
|
|
|
prefix subst =
|
|
|
|
function
|
2002-02-08 08:55:44 -08:00
|
|
|
[] ->
|
|
|
|
ofs
|
2004-04-09 06:32:28 -07:00
|
|
|
| m :: rem ->
|
|
|
|
match m.pm_kind with
|
|
|
|
| PM_intf ->
|
2018-07-15 12:00:47 -07:00
|
|
|
rename_append_bytecode_list packagename oc mapping defined ofs
|
2013-03-09 14:38:52 -08:00
|
|
|
prefix subst rem
|
2004-04-09 06:32:28 -07:00
|
|
|
| PM_impl compunit ->
|
|
|
|
let size =
|
2018-07-15 12:00:47 -07:00
|
|
|
rename_append_bytecode packagename oc mapping defined ofs
|
2013-03-09 14:38:52 -08:00
|
|
|
prefix subst m.pm_file compunit in
|
2009-05-20 04:52:42 -07:00
|
|
|
let id = Ident.create_persistent m.pm_name in
|
|
|
|
let root = Path.Pident (Ident.create_persistent prefix) in
|
2018-07-15 12:00:47 -07:00
|
|
|
rename_append_bytecode_list packagename oc mapping (id :: defined)
|
2013-03-09 14:38:52 -08:00
|
|
|
(ofs + size) prefix
|
2018-02-08 09:51:47 -08:00
|
|
|
(Subst.add_module id (Path.Pdot (root, Ident.name id))
|
2013-03-09 14:38:52 -08:00
|
|
|
subst)
|
|
|
|
rem
|
2002-02-08 08:55:44 -08:00
|
|
|
|
2003-03-06 07:59:55 -08:00
|
|
|
(* Generate the code that builds the tuple representing the package module *)
|
|
|
|
|
2018-07-27 00:51:53 -07:00
|
|
|
let build_global_target ~ppf_dump oc target_name members mapping pos coercion =
|
2004-04-09 06:32:28 -07:00
|
|
|
let components =
|
|
|
|
List.map2
|
2016-03-09 02:40:16 -08:00
|
|
|
(fun m (_id1, id2) ->
|
2004-04-09 06:32:28 -07:00
|
|
|
match m.pm_kind with
|
|
|
|
| PM_intf -> None
|
|
|
|
| PM_impl _ -> Some id2)
|
|
|
|
members mapping in
|
2003-03-06 07:59:55 -08:00
|
|
|
let lam =
|
2004-04-09 06:32:28 -07:00
|
|
|
Translmod.transl_package
|
|
|
|
components (Ident.create_persistent target_name) coercion in
|
2019-06-28 06:31:42 -07:00
|
|
|
let lam = Simplif.simplify_lambda lam in
|
2014-02-17 06:03:54 -08:00
|
|
|
if !Clflags.dump_lambda then
|
2018-07-27 00:51:53 -07:00
|
|
|
Format.fprintf ppf_dump "%a@." Printlambda.lambda lam;
|
2003-03-06 07:59:55 -08:00
|
|
|
let instrs =
|
|
|
|
Bytegen.compile_implementation target_name lam in
|
|
|
|
let rel =
|
|
|
|
Emitcode.to_packed_file oc instrs in
|
|
|
|
relocs := List.map (fun (r, ofs) -> (r, pos + ofs)) rel @ !relocs
|
2002-02-08 08:55:44 -08:00
|
|
|
|
|
|
|
(* Build the .cmo file obtained by packaging the given .cmo files. *)
|
|
|
|
|
2018-07-27 00:51:53 -07:00
|
|
|
let package_object_files ~ppf_dump files targetfile targetname coercion =
|
2004-04-09 06:32:28 -07:00
|
|
|
let members =
|
|
|
|
map_left_right read_member_info files in
|
2016-06-03 04:21:22 -07:00
|
|
|
let required_globals =
|
2016-10-11 01:32:36 -07:00
|
|
|
List.fold_right (fun compunit required_globals -> match compunit with
|
2016-06-03 04:21:22 -07:00
|
|
|
| { pm_kind = PM_intf } ->
|
|
|
|
required_globals
|
2016-10-11 01:32:36 -07:00
|
|
|
| { pm_kind = PM_impl { cu_required_globals; cu_reloc } } ->
|
|
|
|
let remove_required (rel, _pos) required_globals =
|
|
|
|
match rel with
|
|
|
|
Reloc_setglobal id ->
|
|
|
|
Ident.Set.remove id required_globals
|
|
|
|
| _ ->
|
|
|
|
required_globals
|
|
|
|
in
|
|
|
|
let required_globals =
|
|
|
|
List.fold_right remove_required cu_reloc required_globals
|
|
|
|
in
|
2016-06-03 04:21:22 -07:00
|
|
|
List.fold_right Ident.Set.add cu_required_globals required_globals)
|
2016-10-11 01:32:36 -07:00
|
|
|
members Ident.Set.empty
|
2016-06-03 04:21:22 -07:00
|
|
|
in
|
2002-02-08 08:55:44 -08:00
|
|
|
let unit_names =
|
2004-04-09 06:32:28 -07:00
|
|
|
List.map (fun m -> m.pm_name) members in
|
2002-02-08 08:55:44 -08:00
|
|
|
let mapping =
|
|
|
|
List.map
|
|
|
|
(fun name ->
|
|
|
|
(Ident.create_persistent name,
|
|
|
|
Ident.create_persistent(targetname ^ "." ^ name)))
|
|
|
|
unit_names in
|
|
|
|
let oc = open_out_bin targetfile in
|
|
|
|
try
|
|
|
|
output_string oc Config.cmo_magic_number;
|
|
|
|
let pos_depl = pos_out oc in
|
|
|
|
output_binary_int oc 0;
|
|
|
|
let pos_code = pos_out oc in
|
2018-07-15 12:00:47 -07:00
|
|
|
let ofs = rename_append_bytecode_list targetname oc mapping [] 0
|
2013-03-09 14:38:52 -08:00
|
|
|
targetname Subst.identity members in
|
2018-07-27 00:51:53 -07:00
|
|
|
build_global_target ~ppf_dump oc targetname members mapping ofs coercion;
|
2002-02-08 08:55:44 -08:00
|
|
|
let pos_debug = pos_out oc in
|
2014-10-15 06:34:58 -07:00
|
|
|
if !Clflags.debug && !events <> [] then begin
|
2003-03-06 07:59:55 -08:00
|
|
|
output_value oc (List.rev !events);
|
2018-07-23 05:19:41 -07:00
|
|
|
output_value oc (String.Set.elements !debug_dirs);
|
2014-10-15 06:34:58 -07:00
|
|
|
end;
|
2002-02-08 08:55:44 -08:00
|
|
|
let pos_final = pos_out oc in
|
|
|
|
let imports =
|
|
|
|
List.filter
|
2016-03-09 02:40:16 -08:00
|
|
|
(fun (name, _crc) -> not (List.mem name unit_names))
|
2002-02-08 08:55:44 -08:00
|
|
|
(Bytelink.extract_crc_interfaces()) in
|
|
|
|
let compunit =
|
|
|
|
{ cu_name = targetname;
|
|
|
|
cu_pos = pos_code;
|
|
|
|
cu_codesize = pos_debug - pos_code;
|
|
|
|
cu_reloc = List.rev !relocs;
|
2014-05-06 17:34:20 -07:00
|
|
|
cu_imports =
|
|
|
|
(targetname, Some (Env.crc_of_unit targetname)) :: imports;
|
2002-02-08 08:55:44 -08:00
|
|
|
cu_primitives = !primitives;
|
2016-06-03 04:21:22 -07:00
|
|
|
cu_required_globals = Ident.Set.elements required_globals;
|
2002-02-08 08:55:44 -08:00
|
|
|
cu_force_link = !force_link;
|
|
|
|
cu_debug = if pos_final > pos_debug then pos_debug else 0;
|
|
|
|
cu_debugsize = pos_final - pos_debug } in
|
2017-05-04 23:18:40 -07:00
|
|
|
Emitcode.marshal_to_channel_with_possibly_32bit_compat
|
|
|
|
~filename:targetfile ~kind:"bytecode unit"
|
|
|
|
oc compunit;
|
2002-02-08 08:55:44 -08:00
|
|
|
seek_out oc pos_depl;
|
|
|
|
output_binary_int oc pos_final;
|
|
|
|
close_out oc
|
|
|
|
with x ->
|
|
|
|
close_out oc;
|
|
|
|
raise x
|
|
|
|
|
|
|
|
(* The entry point *)
|
|
|
|
|
2018-07-27 00:51:53 -07:00
|
|
|
let package_files ~ppf_dump initial_env files targetfile =
|
2010-09-12 22:28:30 -07:00
|
|
|
let files =
|
2002-02-08 08:55:44 -08:00
|
|
|
List.map
|
2012-07-30 11:04:46 -07:00
|
|
|
(fun f ->
|
2018-09-18 06:49:18 -07:00
|
|
|
try Load_path.find f
|
2002-02-08 08:55:44 -08:00
|
|
|
with Not_found -> raise(Error(File_not_found f)))
|
2012-07-30 11:04:46 -07:00
|
|
|
files in
|
2010-09-12 22:28:30 -07:00
|
|
|
let prefix = chop_extensions targetfile in
|
|
|
|
let targetcmi = prefix ^ ".cmi" in
|
2014-12-21 03:46:14 -08:00
|
|
|
let targetname = String.capitalize_ascii(Filename.basename prefix) in
|
2015-12-23 13:40:21 -08:00
|
|
|
Misc.try_finally (fun () ->
|
|
|
|
let coercion =
|
|
|
|
Typemod.package_units initial_env files targetcmi targetname in
|
2018-07-27 00:51:53 -07:00
|
|
|
package_object_files ~ppf_dump files targetfile targetname coercion
|
2015-12-23 13:40:21 -08:00
|
|
|
)
|
|
|
|
~exceptionally:(fun () -> remove_file targetfile)
|
2002-02-08 08:55:44 -08:00
|
|
|
|
|
|
|
(* Error report *)
|
|
|
|
|
|
|
|
open Format
|
|
|
|
|
|
|
|
let report_error ppf = function
|
|
|
|
Forward_reference(file, ident) ->
|
2012-03-07 09:50:17 -08:00
|
|
|
fprintf ppf "Forward reference to %s in file %a" (Ident.name ident)
|
|
|
|
Location.print_filename file
|
2002-02-08 08:55:44 -08:00
|
|
|
| Multiple_definition(file, ident) ->
|
2012-03-07 09:50:17 -08:00
|
|
|
fprintf ppf "File %a redefines %s"
|
|
|
|
Location.print_filename file
|
|
|
|
(Ident.name ident)
|
2002-02-08 08:55:44 -08:00
|
|
|
| Not_an_object_file file ->
|
2012-03-07 09:50:17 -08:00
|
|
|
fprintf ppf "%a is not a bytecode object file"
|
|
|
|
Location.print_filename file
|
2013-04-29 07:57:38 -07:00
|
|
|
| Illegal_renaming(name, file, id) ->
|
2013-09-04 08:12:37 -07:00
|
|
|
fprintf ppf "Wrong file naming: %a@ contains the code for\
|
|
|
|
@ %s when %s was expected"
|
|
|
|
Location.print_filename file name id
|
2002-02-08 08:55:44 -08:00
|
|
|
| File_not_found file ->
|
|
|
|
fprintf ppf "File %s not found" file
|
2013-09-12 07:34:13 -07:00
|
|
|
|
|
|
|
let () =
|
|
|
|
Location.register_error_of_exn
|
|
|
|
(function
|
|
|
|
| Error err -> Some (Location.error_of_printer_file report_error err)
|
|
|
|
| _ -> None
|
|
|
|
)
|
2014-05-09 05:01:21 -07:00
|
|
|
|
|
|
|
let reset () =
|
|
|
|
relocs := [];
|
|
|
|
events := [];
|
|
|
|
primitives := [];
|
|
|
|
force_link := false
|