4 exception Found of string list
6 let ocamlobjinfo = "ocamlobjinfo"
7 let noautolink = "-noautolink"
8 let dummy_opt_cmd = "dummy_ocamlopt"
9 let opt_cmd = "ocamlopt"
10 let libdirs = [ "/lib"; "/usr/lib"; "/usr/lib/gcc/i486-linux-gnu/4.0.2" ]
11 let exceptions = [ "threads.cma", [ "-lthreads", "-lthreadsnat" ] ]
13 let blanks_RE = Str.regexp "[ \t\r\n]+"
14 let cmxa_RE = Str.regexp "\\.cmxa$"
15 let extra_cfiles_RE = Str.regexp "^.*Extra +C +object +files:\\(.*\\)$"
16 let extra_copts_RE = Str.regexp "^.*Extra +C +options:\\(.*\\)$"
17 let lib_RE = Str.regexp "^lib"
18 let l_RE = Str.regexp "^-l"
19 let opt_line_RE = Str.regexp (sprintf "^\\+ +%s +\\(.*\\)$" dummy_opt_cmd)
20 let trailing_cmxa_RE = Str.regexp ".*\\.cmxa$"
22 let message s = prerr_endline ("STATIC_LINK: " ^ s)
23 let warning s = message ("WARNING: " ^ s)
25 let handle_exceptions ~cma cflag =
27 let cma_exns = List.assoc (Filename.basename cma) exceptions in
28 let cflag' = List.assoc cflag cma_exns in
29 message (sprintf "using %s exception %s -> %s" cma cflag cflag');
31 with Not_found -> cflag
33 let parse_cmdline () =
34 let mine, rest = ref [], ref [] in
35 let is_mine = ref true in
38 | "--" -> is_mine := false
40 if Str.string_match lib_RE s 0 then
42 ("libraries to be statically linked must be specified "
43 ^^ "without heading \"lib\", \"%s\" argument may be wrong") s);
45 | s -> rest := s :: !rest)
47 if !rest = [] then begin
48 prerr_endline "Usage: static_link [ CLIB .. ] -- COMMAND [ ARG .. ]";
49 prerr_endline ("Example: static_link pcre expat --"
50 ^ " ocamlfind opt -package pcre,expat -linkpkg -o foo foo.ml");
53 List.tl (List.rev !mine), List.rev !rest
55 let extract_opt_flags cmd =
56 let ic = Unix.open_process_in cmd in
59 let l = input_line ic in
60 if Str.string_match opt_line_RE l 0 then begin
61 message ("got ocamlopt line: " ^ l);
62 raise (Found (Str.split blanks_RE (Str.matched_group 1 l)));
67 | End_of_file -> failwith "compiler command not found"
72 let cma_of_cmxa = Str.replace_first cmxa_RE ".cma"
74 let find_clib libname =
77 | [] -> raise Not_found
79 let fname = sprintf "%s/lib%s.a" libdir libname in
80 if Sys.file_exists fname then fname else aux tl
84 let a_of_cflag cflag = (* "-lfoo" -> "/usr/lib/libfoo.a" *)
85 let libname = Str.replace_first l_RE "" cflag in
88 let cflags_of_cma fname =
89 let ic = Unix.open_process_in (sprintf "%s %s" ocamlobjinfo fname) in
90 let extra_copts = ref "" in
91 let extra_cfiles = ref "" in
94 match input_line ic with
95 | s when Str.string_match extra_copts_RE s 0 ->
96 extra_copts := Str.matched_group 1 s
97 | s when Str.string_match extra_cfiles_RE s 0 ->
98 extra_cfiles := Str.matched_group 1 s
101 with End_of_file -> ());
103 let extra_cfiles = List.rev (Str.split blanks_RE !extra_cfiles) in
104 let extra_copts = Str.split blanks_RE !extra_copts in
105 extra_copts @ extra_cfiles
107 let staticize static_libs flags =
108 let static_flags = List.map ((^) "-l") static_libs in
109 let aux ~add_cclib ~cma cflag =
111 if List.mem cflag static_flags
114 let a = a_of_cflag cflag in
115 message (sprintf "using static %s instead of shared %s" a cflag);
117 with Not_found -> warning ("can't find lib for " ^ cflag); cflag)
118 else (handle_exceptions ~cma cflag)
120 if add_cclib then [ "-cclib"; cflag ] else [ cflag ]
124 let cma = cma_of_cmxa flag in
125 if Str.string_match trailing_cmxa_RE flag 0 then begin
126 message ("processing native archive: " ^ flag);
127 let cflags = cflags_of_cma cma in
130 (fun cflag acc -> (aux ~add_cclib:true ~cma cflag) @ acc)
133 flag :: (cflags' @ acc)
135 (aux ~add_cclib:false ~cma flag) @ acc)
138 let quote_if_needed s =
140 ignore (Str.search_forward blanks_RE s 0);
145 let static_libs, args = parse_cmdline () in
146 printf "C libraries to be linked-in: %s\n" (String.concat " " static_libs);
149 sprintf "OCAMLFIND_COMMANDS='ocamlopt=%s' %s -verbose 2>&1" dummy_opt_cmd
150 (String.concat " " (List.map quote_if_needed args))
152 let orig_opt_flags = extract_opt_flags verbose_cmd in
153 message ("original ocamlopt flags: " ^ String.concat " " orig_opt_flags);
154 let opt_flags = staticize static_libs orig_opt_flags in
155 message ("new ocamlopt flags: " ^ String.concat " " opt_flags);
156 let flags = noautolink :: opt_flags in
157 let cmd = String.concat " " (opt_cmd :: flags) in
158 message ("executing command: " ^ cmd);
159 exit (Sys.command cmd)