aboutsummaryrefslogtreecommitdiffhomepage
path: root/myocamlbuild.ml
blob: b518c50d046536ff7ae18c32197efafe18da287e (plain)
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
(** * Plugin for building Coq via Ocamlbuild *)

open Ocamlbuild_plugin
open Ocamlbuild_pack
open Printf

(** WARNING !! this is preliminary stuff, able only to build
    coqtop.opt and coqtop.byte, and only in a precise environment
    (ocaml 3.11 with natdynlink)

    Support for other rules and other configurations will be
    added later...

    Usage: 

    ocamlbuild coq.otarget

    Then you can (hopefully) launch coq (with no input state) via:
    
    _build/bin/coqtop.opt -nois -coqlib .

    or

    CAML_LD_LIBRARY_PATH=_build/kernel/byterun _build/bin/coqtop.byte -nois -coqlib .
 
    TODO: understand how to create the right symlinks towards _build ...

*)



(** Parse a config file such as config/Makefile: 
    valid lines are NAME=value, comments start by # *)

let read_env f =
  let ic = open_in f in
  let vars = ref [] in
  begin try while true do
    let l = input_line ic in
    if l <> "" && l.[0] <> '#' && l.[0] <> ' ' then
      try
	let i = String.index l '=' in
	let var = String.sub l 0 i
	and def = if i+1 >= String.length l then "" else
	  String.sub l (i+1) (String.length l - i - 1)
	in
	let def = if String.length def >= 2 &&
	  def.[0]='\"' && def.[String.length def - 1] = '\"'
	then String.sub def 1 (String.length def - 2) else def
	in
	vars:=(var,def)::!vars
      with Not_found -> ()
  done with End_of_file -> () end;
  close_in ic;
  !vars

let env_vars =
  let f = "config/Makefile" in
  try read_env f with _ -> (eprintf "Error while reading %s\n" f; exit 1)

let get_env s =
  try List.assoc s env_vars
  with Not_found -> (eprintf "Unknown environment variable %s\n" s; exit 1)


(** Configuration *)

let _ = Options.ocamlc := A(get_env "OCAMLC")

let camlp4o = get_env "CAMLP4O"
let camlp4lib = get_env "MYCAMLP4LIB"
let camlp4compat = get_env "CAMLP4COMPAT"
let hasdynlink = (get_env "HASNATDYNLINK" = "true")
let flag_dynlink = if hasdynlink then "-DHasDynLink" else ""

(** Do we want to inspect .ml generated from .ml4 ? *)
let readable_genml = false
let readable_flag = if readable_genml then A"pr_o.cmo" else N

let core_libs =
  ["lib/lib"; "kernel/kernel"; "library/library";
   "pretyping/pretyping"; "interp/interp";  "proofs/proofs";
   "parsing/parsing"; "tactics/tactics"; "toplevel/toplevel";
   "parsing/highparsing"; "tactics/hightactics"]
let core_cma = List.map (fun s -> s^".cma") core_libs
let core_cmxa = List.map (fun s -> s^".cmxa") core_libs
let core_mllib = List.map (fun s -> s^".mllib") core_libs


let _ = dispatch begin function
 | After_rules ->  (* Add our rules after the standard ones. *)

(** Camlp4 extensions *)

     rule "ml4ml" ~dep:"%.ml4" ~prod:"%.ml"
       (fun env _ ->
	  let ml4 = env "%.ml4" and ml = env "%.ml" in
	  Cmd (S[A camlp4o;T(tags_of_pathname ml4 ++ "p4mod");readable_flag;
		 T(tags_of_pathname ml4 ++ "p4option");
		 Sh camlp4compat; A"-o"; P ml; A"-impl"; P ml4]));

     flag ["is_ml4"; "p4mod"; "use_macro"] (A"pa_macro.cmo");
     flag ["is_ml4"; "p4mod"; "use_extend"] (A"pa_extend.cmo");
     flag ["is_ml4"; "p4mod"; "use_MLast"] (A"q_MLast.cmo");

     flag_and_dep ["is_ml4"; "p4mod"; "use_grammar"] (P"parsing/grammar.cma");
     flag_and_dep ["is_ml4"; "p4mod"; "use_constr"] (P"parsing/q_constr.cmo");

(** Special case of toplevel/mltop.ml4: 
    - mltop.ml will be the old mltop.optml and be used to obtain mltop.cmx
    - we add a special mltop.ml4 --> mltop.cmo rule, before all the others
*)
     flag ["is_mltop"; "p4option"] (A flag_dynlink);

(*TODO: this is rather ugly for a simple file, we should try to
        benefit more from predefined rules *)
     let mltop = "toplevel/mltop" in
     let ml4 = mltop^".ml4" and mlo = mltop^".cmo" and
	 ml = mltop^".ml" and mld = mltop^".ml.depends"
     in
     rule "mltop_byte" ~deps:[ml4;mld]  ~prod:mlo ~insert:`top
       (fun env build ->
	  Ocaml_compiler.prepare_compile build ml;
	  Cmd (S [!Options.ocamlc; A"-c";A"-rectypes"; A"-I"; A camlp4lib;
		  A"-pp";
		  Quote (S [A camlp4o; T(tags_of_pathname ml4 ++ "p4mod");
			    A"-DByte"; A"-DHasDynLink"; Sh camlp4compat;
			    A"-impl"]);
		  A"-rectypes"; A"-I"; A camlp4lib;
		  Ocaml_utils.ocaml_include_flags ml4;
		  A"-impl"; P ml4]));

(** All caml files are compiled with -rectypes and +camlp5 *)

     flag ["compile"; "ocaml"] (S [A"-rectypes"; A"-I"; A camlp4lib]);
     flag ["link"; "ocaml"] (S [A"-rectypes"; A"-I"; A camlp4lib]);

(** Extra libraries *)

     ocaml_lib ~extern:true "gramlib";

(** C code for the VM *)

     let headers = List.map (fun s -> "kernel/byterun/"^s)
       ["coq_fix_code.h";"coq_instruct.h"; "coq_memory.h"; "int64_emul.h";
	"coq_gc.h"; "coq_interp.h"; "coq_values.h"; "int64_native.h";
	"coq_jumptbl.h"]
     in
     dep ["compile"; "c"] headers;
     flag ["compile"; "c"] (S[A"-ccopt";A"-fno-defer-pop -Wall -Wno-unused"]);
     dep ["link"; "ocaml"; "use_libcoqrun"] ["kernel/byterun/libcoqrun.a"];

(** Generation of coq_jumbtbl.h for the VM *)

     let coqjump = "kernel/byterun/coq_jumptbl.h"
     and coqinstr = "kernel/byterun/coq_instruct.h" in
     let cmd = Printf.sprintf
       "sed -n -e '/^  /s/ \\([A-Z]\\)/ \\&\\&coq_lbl_\\1/gp' -e '/^}/q' %s > %s"
       coqinstr coqjump
     in
     rule "coqjump" ~deps:[coqinstr] ~prod:coqjump
       (fun _ _ -> Cmd (Sh cmd));

(** Generation of opcodes for the VM *)

     let copcodes = "kernel/copcodes.ml"
     and coqinstr = "kernel/byterun/coq_instruct.h"
     and script = "kernel/make-opcodes" in
     let cmd = Printf.sprintf
       "sed -n -e '/^enum/p' -e 's/,//g' -e '/^  /p' %s | awk -f %s > %s"
       coqinstr script copcodes
     in
     rule "copcodes" ~deps:[coqinstr;script] ~prod:copcodes
       (fun _ _ -> Cmd (Sh cmd));

(** Generation of tolink.ml *)

     let tolink = "scripts/tolink.ml" in
     let core_cma_s = String.concat " " core_cma in
     let core_mllib_s = String.concat " " core_mllib in
     let cmd =
       "(echo \'let copts = \"-cclib -lcoqrun\"\'; "^
       "echo \'let core_libs = \"config/coq_config.cmo "^core_cma_s^"\"\'; "^
       "echo \'let core_objs = \"Coq_config `cat "^core_mllib_s^"`\"\'; "^
       "echo \'let ide = \"`cat ide/ide.mllib`\"\' " ^
       ") > " ^ tolink
     in
     rule "tolink.ml" ~deps:core_mllib ~prod:tolink
       (fun _ _ -> Cmd (Sh cmd));

(** Coqtop *)

     let coqtopopt = "bin/coqtop.opt"
     and coqtopbyte = "bin/coqtop.byte" in
     let deps = ["scripts/coqmktop.native";"kernel/byterun/libcoqrun.a"] in
     let depsopt = [ "config/coq_config.cmx"] @ deps @ core_cmxa
     and depsbyte = [ "config/coq_config.cmo"] @ deps @ core_cma
     in begin
     rule "coqtop.opt" ~deps:depsopt ~prod:coqtopopt
       (fun _ _ ->
	  Cmd (S [P "scripts/coqmktop.native";A"-boot";A"-opt";
		  Ocaml_utils.ocaml_include_flags coqtopopt;
		  A"-o";P coqtopopt]));
     rule "coqtop.byte" ~deps:depsbyte ~prod:coqtopbyte
       (fun _ _ ->
	  Cmd (S [P "scripts/coqmktop.native";A"-boot";A"-top";
		  Ocaml_utils.ocaml_include_flags coqtopbyte;
		  A"-o";P coqtopbyte]));
     end;

(** bin : directory bin doesn't get made by default ??!! *)

     rule "bin dir" ~prod:"bin/.foo" (fun _ _ -> Cmd (Sh "mkdir -p bin && touch bin/.foo"));

 | _ -> ()

end