1 #
2 "myocamlbuild.ml.in"
4 * This file is a plugin that provides the needed customization of
5 * calls to the ocaml compiler needed for components of coccinelle.
6 * The classification of particular components is done by tags, which
7 * are specified in the _tags file.
9 * This file is also a compromise: some aspects of coccocinelle's
10 * build process are somehwat complicated due to packaging some
11 * bundled software, having no requirement on ocamlfind, etc.
12 * We therefore let 'configure' find out the configuration and
13 * paths to tools and libraries, and this plugin is transformed
14 * by that configuration to customize ocamlbuild accordingly.
17 (* Some useful commandline arguments to ocamlbuild are:
18 * -yaccflag -v verbose ocamlyacc and menhir output
19 * -classic-display see the individual build steps
20 * -j 0 parallel building
21 * -tag "-custom" pure bytecode building
22 * -tag "-dtypes" no type annotation generation
26 (* Configuration of this build plugin
29 let ocamlc_path = "@OCAMLC@"
30 let ocamlopt_path = "@OCAMLOPT@"
31 let ocamldep_path = "@OCAMLDEP@"
32 let ocamldoc_path = "@OCAMLDOC@"
33 let ocamlyacc_path = "@OCAMLYACC@"
34 let ocamllex_path = "@OCAMLLEX@"
35 let ocamlmklib_path = "@OCAMLMKLIB@"
36 let ocamlmktop_path = "@OCAMLMKTOP@"
37 let camlp4o_path = "@CAMLP4O@"
38 let menhir_path = "@MENHIR@"
40 let pycaml_path = "@PATH_pycaml@"
41 let pcre_path = "@PATH_pcre@"
42 let menhirLib_path = "@PATH_menhirLib@"
43 let dynlink_path = "@PATH_dynlink@"
45 let pcre_cflags = "@PCRE_CFLAGS@"
46 let pcre_ldflags = "@PCRE_LIBS@"
47 let python_cflags = "@PYTHON_CFLAGS@"
48 let python_ldflags = "@PYTHON_LIBS@"
49 let python_major_version = "@PYVER_MAJOR@"
51 let profiling_modules = "@MODULES_profiling@"
54 (* The plugin code starts here. *)
55 open Ocamlbuild_plugin
58 (* Removes double separators and single dots from
59 * a path. It does not resolve symlinks or turn
60 * relative paths in absolute paths.
62 let rec normalize_path path
=
63 let parent = Pathname.dirname path
in
64 if Pathname.equal path
"/" || Pathname.equal
parent "/" || Pathname.equal
parent path
66 else let name = Pathname.basename path
in
67 if Pathname.equal
name "."
68 then normalize_path parent
69 else normalize_path parent / name
71 (* Makes path relative and implicit, if it is a child of the
72 * current directory. Relative paths are a must when dealing
73 * with the build directory.
74 * Todo: find out if there is a library function for
75 * exactly this purpose.
77 let relative_path path
=
78 let current = normalize_path Pathname.pwd
in
79 let target = normalize_path path
in
80 if Pathname.is_prefix
current target
81 then let len_current = String.length
current in
82 let len_target = String.length
target in
83 if len_current == len_target
85 else let len_tail = len_target - len_current - 1 in
86 let ind_tail = len_current + 1 in
87 String.sub
target ind_tail len_tail
90 let add_flags flag_ref flags
=
91 flag_ref
:= List.append flags
!flag_ref
94 let mk_use_tag name = "use_" ^
name
97 (* Sets up a tag for compiling c and library files against
98 * an external c library.
100 let setup_clib name compile_flags link_flags
=
101 let tag = mk_use_tag name in
102 flag
[tag; "c"; "compile"] (S
[A
"-ccopt"; A compile_flags
]);
103 flag
[tag; "c"; "ocamlmklib"] (S
[A
"-ldopt"; A link_flags
]);
104 flag
[tag; "ocaml"; "link"] (S
[A
"-ccopt"; A compile_flags
]);
105 flag
[tag; "ocaml"; "link"] (S
[A
"-ccopt"; A link_flags
])
107 (* Sets up a tag for declaring a dependency on a stubs library,
108 * and linking it in. The dependency includes both a .a archive
111 let setup_stubs name stubs_dir
=
112 let tag = mk_use_tag name in
113 let path_a = Printf.sprintf
"%s/lib%s_stubs.a" stubs_dir
name in
114 if not
(Pathname.exists
path_a) then
115 dep
[tag; "link"; "ocaml"] [path_a];
116 let stubs_arg = Printf.sprintf
"-l%s_stubs" name in
117 flag
[tag; "ocaml"; "link"; "byte"]
118 (S
[A
"-I"; P stubs_dir
; A
"-dllib"; A
stubs_arg; A
"-cclib"; A
stubs_arg]);
119 flag
[tag; "ocaml"; "link"; "native"]
120 (S
[A
"-I"; P stubs_dir
; A
"-cclib"; A
stubs_arg]);
121 flag
[tag; "ocaml"; "doc"]
122 (S
[A
"-I"; P stubs_dir
])
124 (* The use of bundled software is simply the
125 * inclusion of the appropriate source directory.
126 * The build system can find automatically how to
127 * deal with the bundled sources.
129 let setup_bundle rootdir
=
130 tag_file rootdir
["include"; "traverse"]
132 (* Sets up a tag that adds the given module directory and module
133 * as additional argument to ocaml when it processes a
134 * file with that tag.
135 * Todo: it may be beneficial to add a dependency on the target
138 let setup_module name modname rootdir
=
139 let tag = mk_use_tag name in
140 let link_args isNative
= S
[A
"-I"; P rootdir
; A
(modname isNative
) ] in
141 let compile_args = S
[A
"-I"; P rootdir
] in
142 flag
[tag; "ocaml"; "compile"] compile_args;
143 flag
[tag; "ocaml"; "byte"; "link"; "program"] (link_args false);
144 flag
[tag; "ocaml"; "native"; "link"; "program"] (link_args true);
145 flag
[tag; "ocaml"; "doc"] (S
[A
"-I"; P rootdir
])
147 (* Sets up the use of either a bundled source package or precompiled module. *)
148 let setup_package name modname rootdir
=
149 let exists_path isNative
= Pathname.exists
(rootdir
/ modname isNative
) in
150 let is_binary = exists_path false || exists_path true in
152 then setup_module name modname rootdir
153 else setup_bundle rootdir
156 (* Most files depend on these standard modules, hence we setup a
157 * single tag for them.
158 * This setup routine should be called before the others to ensure
159 * that these modules appear first on the ocaml commandlines.
161 let setup_basic_libs use_dynlink
=
162 ocaml_lib ~extern
:true ~tag_name
:"use_base" "unix";
163 ocaml_lib ~extern
:true ~tag_name
:"use_base" "str";
164 ocaml_lib ~extern
:true ~tag_name
:"use_base" "nums";
165 ocaml_lib ~extern
:true ~tag_name
:"use_base" "bigarray";
167 ocaml_lib ~extern
:true ~tag_name
:"use_base" "dynlink";
170 (* The menhir package provides individual object files
171 * instead of an archive.
173 let setup_menhirLib () =
174 let menhirLib_dir = relative_path menhirLib_path in
175 let modname isNative
= match isNative
with
176 true -> "menhirLib.cmx"
177 | false -> "menhirLib.cmo" in
179 setup_package "menhirLib" modname menhirLib_dir
181 (* Pycaml is a stubs library with some conditional
182 * code that depends on the python version. We
183 * additionally introduce a tag pp_pycaml which
184 * runs the appropriate preprocessors.
186 let setup_pycaml () =
187 let pycaml_dir = relative_path pycaml_path in
188 let modname isNative
= match isNative
with
189 true -> "pycaml.cmxa"
190 | false -> "pycaml.cma" in
192 setup_package "pycaml" modname pycaml_dir;
193 setup_stubs "pycaml" pycaml_dir;
194 setup_clib "pycaml" python_cflags python_ldflags;
196 let macrodef = Printf.sprintf
"-D PYMAJOR%s" python_major_version in
197 flag
["pp_pycaml"; "c"; "compile"] (S
[A
"-ccopt"; A
macrodef]);
198 let camlp4cmd = Printf.sprintf
"%s -parser Camlp4MacroParser -D PYMAJOR%s"
199 camlp4o_path python_major_version in
200 flag
["pp_pycaml"; "ocaml"; "pp"] (Sh
camlp4cmd)
202 (* Pcre is a standard stub library. *)
204 let pcre_dir = relative_path pcre_path in
205 let modname isNative
= match isNative
with
207 | false -> "pcre.cma" in
209 setup_package "pcre" modname pcre_dir;
210 setup_stubs "pcre" pcre_dir;
211 setup_clib "pcre" pcre_cflags pcre_ldflags
213 (* Some utility code on strings and paths. *)
214 let any_non_space str
=
215 let have_non_space = ref false in
217 fun c
-> match c
with
220 | _
-> have_non_space := true
225 String.length str
> 0 && any_non_space str
227 let is_path_configured path
=
228 not_empty path
&& Pathname.exists path
230 (* Note: the setup of the modules is done before the hygiene phase
231 * in order to benefit from additional "include" tags that may be
232 * given to directories.
234 let _ = dispatch
begin
237 Options.hygiene
:= true;
238 Options.sanitize
:= true;
239 Options.make_links
:= false;
240 Options.catch_errors
:= true;
241 Options.use_menhir
:= true;
243 let menhir_wrapper = Printf.sprintf
244 "%s/setup/wrapper-menhir.sh" Pathname.pwd
in
245 Options.ocamlc
:= Sh
ocamlc_path;
246 Options.ocamlopt
:= Sh
ocamlopt_path;
247 Options.ocamldep
:= Sh
ocamldep_path;
248 Options.ocamldoc
:= Sh
ocamldoc_path;
249 Options.ocamlyacc
:= S
[P
menhir_wrapper; P
ocamlyacc_path; P
menhir_path];
250 Options.ocamllex
:= Sh
ocamllex_path;
251 Options.ocamlmklib
:= Sh
ocamlmklib_path;
252 Options.ocamlmktop
:= Sh
ocamlmktop_path;
256 let use_dynlink = is_path_configured dynlink_path in
257 setup_basic_libs use_dynlink;
259 if is_path_configured menhirLib_path then
262 if is_path_configured pcre_path then
265 if is_path_configured pycaml_path then
270 (* produces a slightly faster native version *)
271 (* flag ["ocaml"; "compile"; "native"] (A "-unsafe"); *)
273 (* adds debugging info (including exception backtraces) *)
274 flag
["ocaml"; "compile"] (A
"-g");
276 (* flags to parameterize ocamldoc to produce web pages *)
277 flag
["gen_html"; "ocaml"; "doc"]
278 (S
[A
"-colorize-code"; A
"-short-functors"; A
"-all-params"]);
279 flag
["gen_man"; "ocaml"; "doc"]
280 (S
[A
"-man"; A
"-man-mini"]);
282 (* when profiling, link with profiling.cmo *)
283 if not_empty profiling_modules then
284 flag
["ocaml"; "link"; "byte"]
285 (S
[A
profiling_modules]);
287 (* the warning about unused function arguments are disabled
288 * for files with this tag. *)
289 flag
["nowarn20"; "ocaml"; "compile"] (S
[A
"-w"; A
"-20"]);
291 (* adds the custom option, unless 'nocustom' is given as a tag *)
292 if not
(Tags.mem
"nocustom" (tags_of_pathname
"myocamlbuild.ml"))
293 then flag
["ocaml"; "link"; "byte"] (A
"-custom");