1995-08-09 08:06:35 -07:00
|
|
|
(***********************************************************************)
|
|
|
|
(* *)
|
1996-04-30 07:53:58 -07:00
|
|
|
(* Objective Caml *)
|
1995-08-09 08:06:35 -07:00
|
|
|
(* *)
|
|
|
|
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
|
|
|
|
(* *)
|
1996-04-30 07:53:58 -07:00
|
|
|
(* Copyright 1996 Institut National de Recherche en Informatique et *)
|
1999-11-17 10:59:06 -08:00
|
|
|
(* en Automatique. All rights reserved. This file is distributed *)
|
|
|
|
(* under the terms of the Q Public License version 1.0. *)
|
1995-08-09 08:06:35 -07:00
|
|
|
(* *)
|
|
|
|
(***********************************************************************)
|
|
|
|
|
|
|
|
(* $Id$ *)
|
|
|
|
|
1995-07-02 09:45:21 -07:00
|
|
|
(* Link a set of .cmo files and produce a bytecode executable. *)
|
|
|
|
|
|
|
|
open Sys
|
|
|
|
open Misc
|
|
|
|
open Config
|
1996-11-29 10:36:42 -08:00
|
|
|
open Instruct
|
1995-07-02 09:45:21 -07:00
|
|
|
open Emitcode
|
|
|
|
|
|
|
|
type error =
|
|
|
|
File_not_found of string
|
|
|
|
| Not_an_object_file of string
|
|
|
|
| Symbol_error of string * Symtable.error
|
|
|
|
| Inconsistent_import of string * string * string
|
|
|
|
| Custom_runtime
|
1996-11-07 02:56:52 -08:00
|
|
|
| File_exists of string
|
1995-07-02 09:45:21 -07:00
|
|
|
|
|
|
|
exception Error of error
|
|
|
|
|
|
|
|
type link_action =
|
|
|
|
Link_object of string * compilation_unit
|
|
|
|
(* Name of .cmo file and descriptor of the unit *)
|
|
|
|
| Link_archive of string * compilation_unit list
|
|
|
|
(* Name of .cma file and descriptors of the units to be linked. *)
|
|
|
|
|
|
|
|
(* First pass: determine which units are needed *)
|
|
|
|
|
|
|
|
module IdentSet =
|
|
|
|
Set.Make(struct
|
|
|
|
type t = Ident.t
|
|
|
|
let compare = compare
|
|
|
|
end)
|
|
|
|
|
|
|
|
let missing_globals = ref IdentSet.empty
|
|
|
|
|
|
|
|
let is_required (rel, pos) =
|
|
|
|
match rel with
|
|
|
|
Reloc_setglobal id ->
|
|
|
|
IdentSet.mem id !missing_globals
|
|
|
|
| _ -> false
|
|
|
|
|
|
|
|
let add_required (rel, pos) =
|
|
|
|
match rel with
|
|
|
|
Reloc_getglobal id ->
|
|
|
|
missing_globals := IdentSet.add id !missing_globals
|
|
|
|
| _ -> ()
|
|
|
|
|
|
|
|
let remove_required (rel, pos) =
|
|
|
|
match rel with
|
|
|
|
Reloc_setglobal id ->
|
|
|
|
missing_globals := IdentSet.remove id !missing_globals
|
|
|
|
| _ -> ()
|
|
|
|
|
1995-07-11 11:05:47 -07:00
|
|
|
let scan_file obj_name tolink =
|
1995-07-02 09:45:21 -07:00
|
|
|
let file_name =
|
|
|
|
try
|
|
|
|
find_in_path !load_path obj_name
|
|
|
|
with Not_found ->
|
|
|
|
raise(Error(File_not_found obj_name)) in
|
|
|
|
let ic = open_in_bin file_name in
|
|
|
|
try
|
|
|
|
let buffer = String.create (String.length cmo_magic_number) in
|
|
|
|
really_input ic buffer 0 (String.length cmo_magic_number);
|
|
|
|
if buffer = cmo_magic_number then begin
|
|
|
|
(* This is a .cmo file. It must be linked in any case.
|
|
|
|
Read the relocation information to see which modules it
|
|
|
|
requires. *)
|
|
|
|
let compunit_pos = input_binary_int ic in (* Go to descriptor *)
|
|
|
|
seek_in ic compunit_pos;
|
|
|
|
let compunit = (input_value ic : compilation_unit) in
|
|
|
|
close_in ic;
|
|
|
|
List.iter add_required compunit.cu_reloc;
|
|
|
|
Link_object(file_name, compunit) :: tolink
|
|
|
|
end
|
|
|
|
else if buffer = cma_magic_number then begin
|
|
|
|
(* This is an archive file. Each unit contained in it will be linked
|
|
|
|
in only if needed. *)
|
|
|
|
let pos_toc = input_binary_int ic in (* Go to table of contents *)
|
|
|
|
seek_in ic pos_toc;
|
|
|
|
let toc = (input_value ic : compilation_unit list) in
|
|
|
|
close_in ic;
|
|
|
|
let required =
|
1995-07-11 11:05:47 -07:00
|
|
|
List.fold_right
|
|
|
|
(fun compunit reqd ->
|
1996-04-18 09:28:28 -07:00
|
|
|
if compunit.cu_force_link
|
1995-07-02 09:45:21 -07:00
|
|
|
or !Clflags.link_everything
|
1996-04-18 09:28:28 -07:00
|
|
|
or List.exists is_required compunit.cu_reloc
|
1995-07-02 09:45:21 -07:00
|
|
|
then begin
|
|
|
|
List.iter remove_required compunit.cu_reloc;
|
|
|
|
List.iter add_required compunit.cu_reloc;
|
|
|
|
compunit :: reqd
|
|
|
|
end else
|
|
|
|
reqd)
|
1995-07-11 11:05:47 -07:00
|
|
|
toc [] in
|
1995-07-02 09:45:21 -07:00
|
|
|
Link_archive(file_name, required) :: tolink
|
|
|
|
end
|
|
|
|
else raise(Error(Not_an_object_file file_name))
|
1998-10-01 05:38:09 -07:00
|
|
|
with
|
|
|
|
End_of_file -> close_in ic; raise(Error(Not_an_object_file file_name))
|
|
|
|
| x -> close_in ic; raise x
|
1995-07-02 09:45:21 -07:00
|
|
|
|
|
|
|
(* Second pass: link in the required units *)
|
|
|
|
|
|
|
|
(* Consistency check between interfaces *)
|
|
|
|
|
1996-04-22 04:15:41 -07:00
|
|
|
let crc_interfaces =
|
|
|
|
(Hashtbl.create 17 : (string, string * Digest.t) Hashtbl.t)
|
1995-07-02 09:45:21 -07:00
|
|
|
|
|
|
|
let check_consistency file_name cu =
|
1995-10-09 06:37:11 -07:00
|
|
|
List.iter
|
|
|
|
(fun (name, crc) ->
|
1997-05-15 06:25:14 -07:00
|
|
|
if name = cu.cu_name then begin
|
|
|
|
Hashtbl.add crc_interfaces name (file_name, crc)
|
|
|
|
end else begin
|
|
|
|
try
|
|
|
|
let (auth_name, auth_crc) = Hashtbl.find crc_interfaces name in
|
|
|
|
if crc <> auth_crc then
|
|
|
|
raise(Error(Inconsistent_import(name, file_name, auth_name)))
|
|
|
|
with Not_found ->
|
|
|
|
(* Can only happen for unit for which only a .cmi file was used,
|
|
|
|
but no .cmo is provided *)
|
|
|
|
Hashtbl.add crc_interfaces name (file_name, crc)
|
|
|
|
end)
|
|
|
|
cu.cu_imports
|
1995-07-02 09:45:21 -07:00
|
|
|
|
1998-10-20 05:45:45 -07:00
|
|
|
(* Record compilation events *)
|
1996-11-29 10:36:42 -08:00
|
|
|
|
1998-10-20 05:45:45 -07:00
|
|
|
let debug_info = ref ([] : (int * string) list)
|
1996-11-29 10:36:42 -08:00
|
|
|
|
1995-07-02 09:45:21 -07:00
|
|
|
(* Link in a compilation unit *)
|
|
|
|
|
1996-11-29 10:36:42 -08:00
|
|
|
let link_compunit output_fun currpos_fun inchan file_name compunit =
|
1995-07-02 09:45:21 -07:00
|
|
|
check_consistency file_name compunit;
|
|
|
|
seek_in inchan compunit.cu_pos;
|
|
|
|
let code_block = String.create compunit.cu_codesize in
|
|
|
|
really_input inchan code_block 0 compunit.cu_codesize;
|
|
|
|
Symtable.patch_object code_block compunit.cu_reloc;
|
1997-02-19 08:08:05 -08:00
|
|
|
if !Clflags.debug && compunit.cu_debug > 0 then begin
|
|
|
|
seek_in inchan compunit.cu_debug;
|
1998-10-20 05:45:45 -07:00
|
|
|
let buffer = String.create compunit.cu_debugsize in
|
|
|
|
really_input inchan buffer 0 compunit.cu_debugsize;
|
|
|
|
debug_info := (currpos_fun(), buffer) :: !debug_info
|
1997-02-19 08:08:05 -08:00
|
|
|
end;
|
1996-11-07 02:56:52 -08:00
|
|
|
output_fun code_block;
|
1995-11-05 09:32:12 -08:00
|
|
|
if !Clflags.link_everything then
|
|
|
|
List.iter Symtable.require_primitive compunit.cu_primitives
|
1995-07-02 09:45:21 -07:00
|
|
|
|
|
|
|
(* Link in a .cmo file *)
|
|
|
|
|
1996-11-29 10:36:42 -08:00
|
|
|
let link_object output_fun currpos_fun file_name compunit =
|
1995-07-02 09:45:21 -07:00
|
|
|
let inchan = open_in_bin file_name in
|
|
|
|
try
|
1996-11-29 10:36:42 -08:00
|
|
|
link_compunit output_fun currpos_fun inchan file_name compunit;
|
1995-07-02 09:45:21 -07:00
|
|
|
close_in inchan
|
|
|
|
with
|
|
|
|
Symtable.Error msg ->
|
|
|
|
close_in inchan; raise(Error(Symbol_error(file_name, msg)))
|
|
|
|
| x ->
|
|
|
|
close_in inchan; raise x
|
|
|
|
|
|
|
|
(* Link in a .cma file *)
|
|
|
|
|
1996-11-29 10:36:42 -08:00
|
|
|
let link_archive output_fun currpos_fun file_name units_required =
|
1995-07-02 09:45:21 -07:00
|
|
|
let inchan = open_in_bin file_name in
|
|
|
|
try
|
1996-11-29 10:36:42 -08:00
|
|
|
List.iter
|
1997-02-19 08:08:05 -08:00
|
|
|
(fun cu ->
|
|
|
|
let name = file_name ^ "(" ^ cu.cu_name ^ ")" in
|
|
|
|
try
|
|
|
|
link_compunit output_fun currpos_fun inchan name cu
|
|
|
|
with Symtable.Error msg ->
|
|
|
|
raise(Error(Symbol_error(name, msg))))
|
1996-11-29 10:36:42 -08:00
|
|
|
units_required;
|
1995-07-02 09:45:21 -07:00
|
|
|
close_in inchan
|
1997-02-19 08:08:05 -08:00
|
|
|
with x -> close_in inchan; raise x
|
1995-07-02 09:45:21 -07:00
|
|
|
|
|
|
|
(* Link in a .cmo or .cma file *)
|
|
|
|
|
1996-11-29 10:36:42 -08:00
|
|
|
let link_file output_fun currpos_fun = function
|
|
|
|
Link_object(file_name, unit) ->
|
|
|
|
link_object output_fun currpos_fun file_name unit
|
|
|
|
| Link_archive(file_name, units) ->
|
|
|
|
link_archive output_fun currpos_fun file_name units
|
1995-07-02 09:45:21 -07:00
|
|
|
|
1998-10-20 05:45:45 -07:00
|
|
|
(* Output the debugging information *)
|
|
|
|
(* Format is:
|
|
|
|
<int32> number of event lists
|
|
|
|
<int32> offset of first event list
|
|
|
|
<output_value> first event list
|
|
|
|
...
|
|
|
|
<int32> offset of last event list
|
|
|
|
<output_value> last event list *)
|
|
|
|
|
|
|
|
let output_debug_info oc =
|
|
|
|
output_binary_int oc (List.length !debug_info);
|
|
|
|
List.iter
|
|
|
|
(fun (ofs, evl) -> output_binary_int oc ofs; output_string oc evl)
|
|
|
|
!debug_info;
|
|
|
|
debug_info := []
|
|
|
|
|
1998-04-14 07:48:34 -07:00
|
|
|
(* Transform a file name into an absolute file name *)
|
|
|
|
|
|
|
|
let make_absolute file =
|
|
|
|
if Filename.is_relative file
|
|
|
|
then Filename.concat (Sys.getcwd()) file
|
|
|
|
else file
|
|
|
|
|
1995-07-02 09:45:21 -07:00
|
|
|
(* Create a bytecode executable file *)
|
|
|
|
|
|
|
|
let link_bytecode objfiles exec_name copy_header =
|
1996-11-25 07:52:23 -08:00
|
|
|
let tolink = List.fold_right scan_file objfiles [] in
|
|
|
|
if Sys.os_type = "MacOS" then begin
|
|
|
|
(* Create it as a text file for bytecode scripts *)
|
|
|
|
let c = open_out_gen [Open_wronly; Open_creat] 0o777 exec_name in
|
|
|
|
close_out c
|
|
|
|
end;
|
|
|
|
let outchan = open_out_gen [Open_wronly; Open_trunc; Open_creat; Open_binary]
|
|
|
|
0o777 exec_name in
|
1995-07-02 09:45:21 -07:00
|
|
|
try
|
|
|
|
(* Copy the header *)
|
|
|
|
if copy_header then begin
|
|
|
|
try
|
1998-06-01 07:53:28 -07:00
|
|
|
let header =
|
|
|
|
if String.length !Clflags.use_runtime > 0
|
|
|
|
then "camlheader_ur" else "camlheader" in
|
|
|
|
let inchan = open_in_bin (find_in_path !load_path header) in
|
1995-07-02 09:45:21 -07:00
|
|
|
copy_file inchan outchan;
|
|
|
|
close_in inchan
|
|
|
|
with Not_found | Sys_error _ -> ()
|
|
|
|
end;
|
2000-03-05 11:18:50 -08:00
|
|
|
Bytesections.init_record outchan;
|
1998-10-02 05:40:44 -07:00
|
|
|
(* The path to the bytecode interpreter (in use_runtime mode) *)
|
1998-06-01 07:53:28 -07:00
|
|
|
if String.length !Clflags.use_runtime > 0 then begin
|
|
|
|
output_string outchan (make_absolute !Clflags.use_runtime);
|
2000-03-05 11:18:50 -08:00
|
|
|
output_char outchan '\n';
|
|
|
|
Bytesections.record outchan "RNTM"
|
1998-06-01 07:53:28 -07:00
|
|
|
end;
|
1995-07-02 09:45:21 -07:00
|
|
|
(* The bytecode *)
|
2000-03-05 11:18:50 -08:00
|
|
|
let start_code = pos_out outchan in
|
1995-07-02 09:45:21 -07:00
|
|
|
Symtable.init();
|
|
|
|
Hashtbl.clear crc_interfaces;
|
1996-11-29 10:36:42 -08:00
|
|
|
let output_fun = output_string outchan
|
2000-03-05 11:18:50 -08:00
|
|
|
and currpos_fun () = pos_out outchan - start_code in
|
1996-11-29 10:36:42 -08:00
|
|
|
List.iter (link_file output_fun currpos_fun) tolink;
|
1995-07-02 09:45:21 -07:00
|
|
|
(* The final STOP instruction *)
|
|
|
|
output_byte outchan Opcodes.opSTOP;
|
|
|
|
output_byte outchan 0; output_byte outchan 0; output_byte outchan 0;
|
2000-03-05 11:18:50 -08:00
|
|
|
Bytesections.record outchan "CODE";
|
1997-06-13 08:48:53 -07:00
|
|
|
(* The names of all primitives *)
|
|
|
|
Symtable.output_primitive_names outchan;
|
2000-03-05 11:18:50 -08:00
|
|
|
Bytesections.record outchan "PRIM";
|
1997-06-13 08:48:53 -07:00
|
|
|
(* The table of global data *)
|
1995-08-09 06:17:15 -07:00
|
|
|
output_value outchan (Symtable.initial_global_table());
|
2000-03-05 11:18:50 -08:00
|
|
|
Bytesections.record outchan "DATA";
|
1996-02-15 08:19:09 -08:00
|
|
|
(* The map of global identifiers *)
|
1995-07-02 09:45:21 -07:00
|
|
|
Symtable.output_global_map outchan;
|
2000-03-05 11:18:50 -08:00
|
|
|
Bytesections.record outchan "SYMB";
|
1996-11-29 10:36:42 -08:00
|
|
|
(* Debug info *)
|
2000-03-05 11:18:50 -08:00
|
|
|
if !Clflags.debug then begin
|
|
|
|
output_debug_info outchan;
|
|
|
|
Bytesections.record outchan "DBUG"
|
|
|
|
end;
|
|
|
|
(* The table of contents and the trailer *)
|
|
|
|
Bytesections.write_toc_and_trailer outchan;
|
1995-07-02 09:45:21 -07:00
|
|
|
close_out outchan
|
|
|
|
with x ->
|
|
|
|
close_out outchan;
|
|
|
|
remove_file exec_name;
|
|
|
|
raise x
|
|
|
|
|
1996-11-07 02:56:52 -08:00
|
|
|
(* Output a string as a C array of unsigned ints *)
|
|
|
|
|
|
|
|
let output_code_string_counter = ref 0
|
|
|
|
|
|
|
|
let output_code_string outchan code =
|
|
|
|
let pos = ref 0 in
|
|
|
|
let len = String.length code in
|
|
|
|
while !pos < len do
|
|
|
|
let c1 = Char.code(code.[!pos]) in
|
|
|
|
let c2 = Char.code(code.[!pos + 1]) in
|
|
|
|
let c3 = Char.code(code.[!pos + 2]) in
|
|
|
|
let c4 = Char.code(code.[!pos + 3]) in
|
|
|
|
pos := !pos + 4;
|
|
|
|
Printf.fprintf outchan "0x%02x%02x%02x%02x, " c4 c3 c2 c1;
|
|
|
|
incr output_code_string_counter;
|
|
|
|
if !output_code_string_counter >= 6 then begin
|
|
|
|
output_char outchan '\n';
|
|
|
|
output_code_string_counter := 0
|
|
|
|
end
|
|
|
|
done
|
|
|
|
|
|
|
|
(* Output a string as a C string *)
|
|
|
|
|
|
|
|
let output_data_string outchan data =
|
|
|
|
let counter = ref 0 in
|
|
|
|
for i = 0 to String.length data - 1 do
|
1998-06-01 07:53:28 -07:00
|
|
|
Printf.fprintf outchan "%d, " (Char.code(data.[i]));
|
1996-11-07 02:56:52 -08:00
|
|
|
incr counter;
|
1998-06-01 07:53:28 -07:00
|
|
|
if !counter >= 12 then begin
|
|
|
|
output_string outchan "\n";
|
1996-11-07 02:56:52 -08:00
|
|
|
counter := 0
|
|
|
|
end
|
1998-06-01 07:53:28 -07:00
|
|
|
done
|
1996-11-07 02:56:52 -08:00
|
|
|
|
|
|
|
(* Output a bytecode executable as a C file *)
|
|
|
|
|
|
|
|
let link_bytecode_as_c objfiles outfile =
|
|
|
|
let tolink = List.fold_right scan_file objfiles [] in
|
|
|
|
let outchan = open_out outfile in
|
|
|
|
try
|
|
|
|
(* The bytecode *)
|
|
|
|
output_string outchan "static int caml_code[] = {\n";
|
|
|
|
Symtable.init();
|
|
|
|
Hashtbl.clear crc_interfaces;
|
1996-11-29 10:36:42 -08:00
|
|
|
let output_fun = output_code_string outchan
|
1998-01-05 04:43:08 -08:00
|
|
|
and currpos_fun () = 0 in
|
1996-11-29 10:36:42 -08:00
|
|
|
List.iter (link_file output_fun currpos_fun) tolink;
|
1996-11-07 02:56:52 -08:00
|
|
|
(* The final STOP instruction *)
|
|
|
|
Printf.fprintf outchan "\n0x%x};\n\n" Opcodes.opSTOP;
|
|
|
|
(* The table of global data *)
|
1998-06-01 07:53:28 -07:00
|
|
|
output_string outchan "static char caml_data[] = {\n";
|
1996-11-07 02:56:52 -08:00
|
|
|
output_data_string outchan
|
1997-07-02 11:16:15 -07:00
|
|
|
(Marshal.to_string (Symtable.initial_global_table()) []);
|
1998-06-01 07:53:28 -07:00
|
|
|
Printf.fprintf outchan "\n};\n\n";
|
1996-11-07 02:56:52 -08:00
|
|
|
(* The table of primitives *)
|
1997-06-13 08:48:53 -07:00
|
|
|
Symtable.output_primitive_table outchan;
|
1996-11-07 02:56:52 -08:00
|
|
|
(* The entry point *)
|
|
|
|
output_string outchan "\n
|
|
|
|
void caml_startup(argv)
|
|
|
|
char ** argv;
|
|
|
|
{
|
1996-11-08 06:44:48 -08:00
|
|
|
caml_startup_code(caml_code, sizeof(caml_code), caml_data, argv);
|
1996-11-07 02:56:52 -08:00
|
|
|
}\n";
|
|
|
|
close_out outchan
|
|
|
|
with x ->
|
|
|
|
close_out outchan;
|
|
|
|
raise x
|
1996-11-02 09:55:06 -08:00
|
|
|
|
1996-02-15 08:19:09 -08:00
|
|
|
(* Build a custom runtime *)
|
|
|
|
|
1996-11-02 09:55:06 -08:00
|
|
|
let rec extract suffix l =
|
|
|
|
match l with
|
|
|
|
| [] -> []
|
|
|
|
| h::t when Filename.check_suffix h suffix -> h :: (extract suffix t)
|
|
|
|
| h::t -> extract suffix t
|
|
|
|
;;
|
|
|
|
|
1996-02-15 08:19:09 -08:00
|
|
|
let build_custom_runtime prim_name exec_name =
|
1997-01-05 06:05:42 -08:00
|
|
|
let libname = "libcamlrun" ^ ext_lib in
|
|
|
|
let runtime_lib =
|
|
|
|
try
|
|
|
|
find_in_path !load_path libname
|
|
|
|
with Not_found ->
|
|
|
|
raise(Error(File_not_found libname)) in
|
1996-11-07 02:56:52 -08:00
|
|
|
match Sys.os_type with
|
|
|
|
"Unix" ->
|
1997-05-15 06:25:14 -07:00
|
|
|
Ccomp.command
|
1996-11-07 02:56:52 -08:00
|
|
|
(Printf.sprintf
|
1997-01-05 06:05:42 -08:00
|
|
|
"%s -o %s -I%s %s %s -L%s %s %s %s"
|
1998-11-06 07:39:43 -08:00
|
|
|
!Clflags.c_compiler
|
1996-11-07 02:56:52 -08:00
|
|
|
exec_name
|
|
|
|
Config.standard_library
|
|
|
|
(String.concat " " (List.rev !Clflags.ccopts))
|
|
|
|
prim_name
|
|
|
|
Config.standard_library
|
|
|
|
(String.concat " " (List.rev !Clflags.ccobjs))
|
1997-01-05 06:05:42 -08:00
|
|
|
runtime_lib
|
1996-11-07 02:56:52 -08:00
|
|
|
Config.c_libraries)
|
1996-11-02 09:55:06 -08:00
|
|
|
| "Win32" ->
|
1997-05-15 06:25:14 -07:00
|
|
|
Ccomp.command
|
1996-02-15 08:19:09 -08:00
|
|
|
(Printf.sprintf
|
1997-01-05 06:05:42 -08:00
|
|
|
"%s /Fe%s -I%s %s %s %s %s %s"
|
1998-11-06 07:39:43 -08:00
|
|
|
!Clflags.c_compiler
|
1996-02-15 08:19:09 -08:00
|
|
|
exec_name
|
|
|
|
Config.standard_library
|
|
|
|
(String.concat " " (List.rev !Clflags.ccopts))
|
|
|
|
prim_name
|
1998-12-02 06:39:27 -08:00
|
|
|
(String.concat " " (List.map Ccomp.expand_libname
|
|
|
|
(List.rev !Clflags.ccobjs)))
|
1997-01-05 06:05:42 -08:00
|
|
|
runtime_lib
|
1996-02-15 08:19:09 -08:00
|
|
|
Config.c_libraries)
|
1996-11-02 09:55:06 -08:00
|
|
|
| "MacOS" ->
|
|
|
|
let c68k = "sc"
|
1999-11-29 11:04:49 -08:00
|
|
|
and libs68k = "\"{libraries}IntEnv.far.o\" \
|
|
|
|
\"{libraries}MacRuntime.o\" \
|
|
|
|
\"{clibraries}StdCLib.far.o\" \
|
|
|
|
\"{libraries}MathLib.far.o\" \
|
|
|
|
\"{libraries}ToolLibs.o\" \
|
|
|
|
\"{libraries}Interface.o\""
|
1996-11-02 09:55:06 -08:00
|
|
|
and link68k = "ilink -compact -state nouse -model far -msg nodup"
|
|
|
|
and cppc = "mrc"
|
1999-11-29 11:04:49 -08:00
|
|
|
and libsppc = "\"{sharedlibraries}MathLib\" \
|
|
|
|
\"{ppclibraries}PPCCRuntime.o\" \
|
|
|
|
\"{ppclibraries}PPCToolLibs.o\" \
|
|
|
|
\"{sharedlibraries}StdCLib\" \
|
|
|
|
\"{ppclibraries}StdCRuntime.o\" \
|
|
|
|
\"{sharedlibraries}InterfaceLib\""
|
1996-11-02 09:55:06 -08:00
|
|
|
and linkppc = "ppclink -d"
|
|
|
|
and objs68k = extract ".o" (List.rev !Clflags.ccobjs)
|
|
|
|
and objsppc = extract ".x" (List.rev !Clflags.ccobjs)
|
1999-11-29 11:04:49 -08:00
|
|
|
and q_prim_name = Filename.quote prim_name
|
|
|
|
and q_stdlib = Filename.quote Config.standard_library
|
|
|
|
and q_exec_name = Filename.quote exec_name
|
1996-11-02 09:55:06 -08:00
|
|
|
in
|
1999-11-29 11:04:49 -08:00
|
|
|
Ccomp.run_command (Printf.sprintf "%s -i %s %s %s -o %s.o"
|
1997-05-19 08:42:21 -07:00
|
|
|
c68k
|
1999-11-29 11:04:49 -08:00
|
|
|
q_stdlib
|
|
|
|
(String.concat " " (List.rev_map Filename.quote !Clflags.ccopts))
|
|
|
|
q_prim_name
|
|
|
|
q_prim_name);
|
|
|
|
Ccomp.run_command (Printf.sprintf "%s -i %s %s %s -o %s.x"
|
1997-05-19 08:42:21 -07:00
|
|
|
cppc
|
1999-11-29 11:04:49 -08:00
|
|
|
q_stdlib
|
|
|
|
(String.concat " " (List.rev_map Filename.quote !Clflags.ccopts))
|
|
|
|
q_prim_name
|
|
|
|
q_prim_name);
|
|
|
|
Ccomp.run_command ("delete -i " ^ q_exec_name);
|
1998-11-12 06:51:27 -08:00
|
|
|
Ccomp.run_command (Printf.sprintf
|
1999-11-29 11:04:49 -08:00
|
|
|
"%s -t MPST -c 'MPS ' -o %s %s.o %s %s %s"
|
1997-05-19 08:42:21 -07:00
|
|
|
link68k
|
1999-11-29 11:04:49 -08:00
|
|
|
q_exec_name
|
|
|
|
q_prim_name
|
|
|
|
(String.concat " " (List.map Filename.quote objs68k))
|
|
|
|
(Filename.quote
|
|
|
|
(Filename.concat Config.standard_library "libcamlrun.o"))
|
1996-11-02 09:55:06 -08:00
|
|
|
libs68k);
|
1997-05-15 06:25:14 -07:00
|
|
|
Ccomp.command (Printf.sprintf
|
1999-11-29 11:04:49 -08:00
|
|
|
"%s -t MPST -c 'MPS ' -o %s %s.x %s %s %s"
|
1997-05-19 08:42:21 -07:00
|
|
|
linkppc
|
1999-11-29 11:04:49 -08:00
|
|
|
q_exec_name
|
|
|
|
q_prim_name
|
|
|
|
(String.concat " " (List.map Filename.quote objsppc))
|
|
|
|
(Filename.quote
|
|
|
|
(Filename.concat Config.standard_library "libcamlrun.x"))
|
1996-11-02 09:55:06 -08:00
|
|
|
libsppc)
|
1999-11-29 11:04:49 -08:00
|
|
|
| _ -> assert false
|
1996-11-07 02:56:52 -08:00
|
|
|
|
|
|
|
let append_bytecode_and_cleanup bytecode_name exec_name prim_name =
|
1999-11-29 11:04:49 -08:00
|
|
|
let oc = open_out_gen [Open_wronly; Open_append; Open_binary] 0 exec_name in
|
|
|
|
let ic = open_in_bin bytecode_name in
|
|
|
|
copy_file ic oc;
|
|
|
|
close_in ic;
|
|
|
|
close_out oc;
|
|
|
|
remove_file bytecode_name;
|
|
|
|
remove_file prim_name
|
1996-02-15 08:19:09 -08:00
|
|
|
|
1997-10-24 08:51:36 -07:00
|
|
|
(* Fix the name of the output file, if the C compiler changes it behind
|
|
|
|
our back. *)
|
|
|
|
|
|
|
|
let fix_exec_name name =
|
|
|
|
match Sys.os_type with
|
|
|
|
"Win32" ->
|
1998-11-12 06:51:27 -08:00
|
|
|
if String.contains name '.' then name else name ^ ".exe"
|
1997-10-24 08:51:36 -07:00
|
|
|
| _ -> name
|
|
|
|
|
1995-07-02 09:45:21 -07:00
|
|
|
(* Main entry point (build a custom runtime if needed) *)
|
|
|
|
|
|
|
|
let link objfiles =
|
1999-11-08 07:25:41 -08:00
|
|
|
let objfiles = if !Clflags.nopervasives then objfiles
|
|
|
|
else "stdlib.cma" :: (objfiles @ ["std_exit.cmo"]) in
|
1995-07-02 09:45:21 -07:00
|
|
|
if not !Clflags.custom_runtime then
|
|
|
|
link_bytecode objfiles !Clflags.exec_name true
|
1996-11-07 02:56:52 -08:00
|
|
|
else if not !Clflags.output_c_object then begin
|
|
|
|
let bytecode_name = Filename.temp_file "camlcode" "" in
|
|
|
|
let prim_name = Filename.temp_file "camlprim" ".c" in
|
|
|
|
try
|
1995-07-02 09:45:21 -07:00
|
|
|
link_bytecode objfiles bytecode_name false;
|
1996-11-07 02:56:52 -08:00
|
|
|
let poc = open_out prim_name in
|
1997-06-13 08:48:53 -07:00
|
|
|
Symtable.output_primitive_table poc;
|
1996-11-07 02:56:52 -08:00
|
|
|
close_out poc;
|
1997-10-24 08:51:36 -07:00
|
|
|
let exec_name = fix_exec_name !Clflags.exec_name in
|
|
|
|
if build_custom_runtime prim_name exec_name <> 0
|
1995-07-02 09:45:21 -07:00
|
|
|
then raise(Error Custom_runtime);
|
1998-04-14 07:48:34 -07:00
|
|
|
if !Clflags.make_runtime
|
|
|
|
then (remove_file bytecode_name; remove_file prim_name)
|
|
|
|
else append_bytecode_and_cleanup bytecode_name exec_name prim_name
|
1995-07-02 09:45:21 -07:00
|
|
|
with x ->
|
|
|
|
remove_file bytecode_name;
|
|
|
|
remove_file prim_name;
|
|
|
|
raise x
|
1996-11-07 02:56:52 -08:00
|
|
|
end else begin
|
|
|
|
let c_file =
|
|
|
|
Filename.chop_suffix !Clflags.object_name Config.ext_obj ^ ".c" in
|
|
|
|
if Sys.file_exists c_file then raise(Error(File_exists c_file));
|
|
|
|
try
|
|
|
|
link_bytecode_as_c objfiles c_file;
|
1998-11-06 07:39:43 -08:00
|
|
|
if Ccomp.compile_file c_file <> 0
|
1996-11-07 02:56:52 -08:00
|
|
|
then raise(Error Custom_runtime);
|
|
|
|
remove_file c_file
|
|
|
|
with x ->
|
|
|
|
remove_file c_file;
|
|
|
|
remove_file !Clflags.object_name;
|
|
|
|
raise x
|
1996-11-02 09:55:06 -08:00
|
|
|
end
|
1995-07-02 09:45:21 -07:00
|
|
|
|
|
|
|
(* Error report *)
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
open Format
|
1995-07-02 09:45:21 -07:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let report_error ppf = function
|
|
|
|
| File_not_found name ->
|
|
|
|
fprintf ppf "Cannot find file %s" name
|
1995-07-02 09:45:21 -07:00
|
|
|
| Not_an_object_file name ->
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "The file %s is not a bytecode object file" name
|
1995-07-02 09:45:21 -07:00
|
|
|
| Symbol_error(name, err) ->
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "Error while linking %s:@ %a" name
|
1995-07-02 09:45:21 -07:00
|
|
|
Symtable.report_error err
|
|
|
|
| Inconsistent_import(intf, file1, file2) ->
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf
|
2000-02-08 12:00:06 -08:00
|
|
|
"@[<hv 0>Files %s and %s@ \
|
|
|
|
make inconsistent assumptions over interface %s@]"
|
|
|
|
file1 file2 intf
|
1995-07-02 09:45:21 -07:00
|
|
|
| Custom_runtime ->
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "Error while building custom runtime system"
|
1996-11-07 02:56:52 -08:00
|
|
|
| File_exists file ->
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "Cannot overwrite existing file %s" file
|