File: mkcamlp5.ml

package info (click to toggle)
camlp5 8.04.00-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,968 kB
  • sloc: ml: 137,918; makefile: 2,055; perl: 1,729; sh: 1,653; python: 38
file content (185 lines) | stat: -rw-r--r-- 5,269 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
(**pp -syntax camlp5o -ppopt -pa_ppx_regexp-nostatic -package bos *)
open Rresult
open Bos
open Fpath

let ( let* ) x f = Rresult.(>>=) x f ;;


module L = struct
let sub l n = List.nth !l n
let push l x = (l := x :: !l)
let pop l =
  match !l with
    [] -> failwith "pop: empty list"
  | h::t -> l := t ; h
let len l = List.length !l
end

let read_ic_fully ?(msg="") ?(channel=stdin) () =
  let fd = Unix.descr_of_in_channel channel in
  if Unix.isatty fd && msg <> "" then
    Fmt.(pf stdout "%s\n%!" msg) ;
  let b = Buffer.create 23 in
  let rec rrec () =
    match input_char channel with
      exception End_of_file -> Buffer.contents b
    | c -> Buffer.add_char b c ; rrec ()
  in
  rrec()

let write_fully ~mode ofile txt =
  OS.File.write ~mode (v ofile) txt |> R.failwith_error_msg

let capturex cmd =
  let channel = Unix.open_process_in cmd in
  let txt = read_ic_fully ~channel () in close_in channel; txt

let join s l = String.concat s l

let chomp s =
  [%subst {|\n+$|} / {||} / s] s
;;


let usage_msg = {|
Options:
  -I <dir>   Add directory in search path for object files
  -verbose   verbosely print command executed, pass along to ocamlfind/ocamlc
  -random-pid use PID as random number for generated tmpfile
  -preserve  preserve temp-files
  -opt       same as invoking "mkcamlp5.opt": create opt executable instead of bytecode
  -n         no-execute, just print command

All options of ocamlc (and ocamlfind) are also available

Files:
  .cmi file  Add visible interface for possible future loading
  .cmo file  Load this file in core
  .cma file  Load this file in core

|} ;;

let usage () = Fmt.(pf stdout "%s" usage_msg)

let toremove = ref []
let ocaml_version = chomp (capturex("ocamlc -version"))
let ocaml_lib = chomp (capturex("ocamlc -where"))
let verbose = ref false
let preserve = ref false
let noexecute = ref false
let rev_interfaces = ref []
let rev_options = ref []
let rev_predicates = ref ["preprocessor"; "syntax"]
let rev_packages = ref ["camlp5"]
let randpid = ref (Unix.getpid())
let opt = ref false

let main cmd args =
opt := ([%match {|mkcamlp5.opt$|}/pred] cmd) ;

Stdlib.at_exit (fun () ->
    !toremove
    |>  List.iter (fun f ->
            (let* existsp = OS.File.exists (v f) in
             if existsp then
               if !preserve then
                 Ok (Fmt.(pf stderr "Preserving tmpfile %s\n%!" f))
               else
                 OS.Path.delete (v f)
             else Ok()) |> ignore
          )
  )
;

let rec parec = function
    "-help"::l ->
     usage() ;
     exit 0
  | "-verbose"::l ->
     verbose := true ;
     parec l
  | "-random-pid"::pid::l ->
     randpid := int_of_string pid ;
     parec l
  | "-preserve"::l ->
     preserve := true ;
     parec l
  | "-opt"::l ->
     opt := true ;
     parec l
  | "-n"::l ->
     noexecute := true ;
     parec l
  | "-package"::s::l ->
     List.iter (L.push rev_packages) ([%split {|,|}] s) ;
     parec l
  | "-predicates"::s::l ->
     List.iter (L.push rev_predicates) ([%split {|,|}] s) ;
     parec l
  | s::l ->
     (match ([%match {|([^\./]+)\.cmi$|}/strings !1] s) with
       Some s ->
        if !opt then failwith Fmt.(str "%s: cannot specify .cmi file for %s" cmd cmd) ;
        L.push rev_interfaces (String.capitalize_ascii s)
       | None ->
          L.push rev_options s) ;
     parec l
  | [] -> ()
    in
    parec args ;

if !opt then
  L.push rev_predicates "native"
else
  L.push rev_predicates "byte" ;

let interfaces = List.rev !rev_interfaces in
let options = List.rev !rev_options in
let packages = List.rev !rev_packages in
let predicates = List.rev !rev_predicates in

let link =
if not !opt then begin
    let stringified = Fmt.(str "%a" (list ~sep:(const string "; ") (quote string)) interfaces) in
    let txt = [%pattern {|Dynlink.set_allowed_units [
  ${stringified}
] ;;
|}] in
    let linkbase = Fmt.(str "link%04d" !randpid) in
    List.iter (L.push toremove) [[%pattern {|${linkbase}.ml|}]; [%pattern {|${linkbase}.cmi|}]; [%pattern {|${linkbase}.cmo|}]; [%pattern {|${linkbase}.cmx|}]] ;
    write_fully ~mode:0o755 [%pattern {|${linkbase}.ml|}] txt ;
    [[%pattern {|${linkbase}.ml|}]]
  end
else [] in

let cmd = ["ocamlfind"]
	  @[if !opt then "ocamlopt" else "ocamlc"]
	     @["-predicates"; join"," predicates]
	    @["-package"; join "," packages]
	    @(if !verbose then ["-verbose"] else [])
	    @["-linkall"; "-linkpkg"; "-I" ; "+dynlink"]
	    @ link @ options
	    @[if !opt then "odyl.cmx" else "odyl.cmo"] in
    if !verbose then Fmt.(pf stderr "%a\n%!" (list ~sep:(const string " ") string) cmd) ;
    if not !noexecute then
      match Unix.system (Filename.quote_command (List.hd cmd) (List.tl cmd)) with
        WEXITED 0 -> ()
      | WEXITED n ->
         Fmt.(pf stderr "Maybe an error? Command exited with code %d\n%!" n) ;
         Stdlib.exit n
      | WSIGNALED n -> 
         Fmt.(pf stderr "Maybe an error? Command signaled (??) with code %d\n%!" n) ;
         Stdlib.exit (-1)
      | WSTOPPED n -> 
         Fmt.(pf stderr "Maybe an error? Command stopped (??) with code %d\n%!" n) ;
         Stdlib.exit (-1)

(*
      Unix.execvp "ocamlfind" (Array.of_list cmd)
 *)
;;

let cmd = Sys.argv.(0) ;;
let argv = List.tl (Array.to_list Sys.argv) ;;
main cmd argv ;;