summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Pouillard <np@nicolaspouillard.fr>2007-02-07 08:59:16 +0000
committerNicolas Pouillard <np@nicolaspouillard.fr>2007-02-07 08:59:16 +0000
commit381e325c0f7c9f4188c2a4e6421b46d41c0c007c (patch)
tree194fbc6442deb3d79b6c595f30f356ed58f063cb
parent2d26308ad4d34ea0c00e44db62c4c24c7031c78c (diff)
downloadocaml-381e325c0f7c9f4188c2a4e6421b46d41c0c007c.tar.gz
Add the ocamlbuild directory
git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@7823 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
-rw-r--r--ocamlbuild/AUTHORS2
-rw-r--r--ocamlbuild/ChangeLog3147
-rw-r--r--ocamlbuild/Makefile95
-rw-r--r--ocamlbuild/TODO30
-rw-r--r--ocamlbuild/_tags12
-rw-r--r--ocamlbuild/bool.ml38
-rw-r--r--ocamlbuild/bool.mli34
-rw-r--r--ocamlbuild/command.ml295
-rw-r--r--ocamlbuild/command.mli30
-rw-r--r--ocamlbuild/configuration.ml63
-rw-r--r--ocamlbuild/configuration.mli34
-rw-r--r--ocamlbuild/discard_printf.ml16
-rw-r--r--ocamlbuild/discard_printf.mli19
-rw-r--r--ocamlbuild/display.ml385
-rw-r--r--ocamlbuild/display.mli33
-rw-r--r--ocamlbuild/examples/example1/hello.ml5
-rw-r--r--ocamlbuild/examples/example2/greet.ml6
-rw-r--r--ocamlbuild/examples/example2/hello.ml14
-rw-r--r--ocamlbuild/examples/example3/epoch.ml6
-rwxr-xr-xocamlbuild/examples/example3/make.sh32
-rw-r--r--ocamlbuild/executor.ml315
-rw-r--r--ocamlbuild/executor.mli35
-rw-r--r--ocamlbuild/fda.ml76
-rw-r--r--ocamlbuild/fda.mli18
-rw-r--r--ocamlbuild/flags.ml43
-rw-r--r--ocamlbuild/flags.mli19
-rw-r--r--ocamlbuild/glob.ml398
-rw-r--r--ocamlbuild/glob.mli18
-rw-r--r--ocamlbuild/glob_ast.ml31
-rw-r--r--ocamlbuild/glob_ast.mli25
-rw-r--r--ocamlbuild/glob_lexer.mli27
-rw-r--r--ocamlbuild/glob_lexer.mll114
-rw-r--r--ocamlbuild/hooks.ml26
-rw-r--r--ocamlbuild/hooks.mli23
-rw-r--r--ocamlbuild/hygiene.ml171
-rw-r--r--ocamlbuild/hygiene.mli47
-rw-r--r--ocamlbuild/lexers.mli30
-rw-r--r--ocamlbuild/lexers.mll116
-rw-r--r--ocamlbuild/log.ml49
-rw-r--r--ocamlbuild/log.mli34
-rw-r--r--ocamlbuild/main.ml266
-rw-r--r--ocamlbuild/main.mli14
-rw-r--r--ocamlbuild/man/ocamlbuild.1253
-rw-r--r--ocamlbuild/manual/Makefile11
-rw-r--r--ocamlbuild/manual/manual.tex943
-rw-r--r--ocamlbuild/misc/opentracer.ml101
-rw-r--r--ocamlbuild/my_std.ml359
-rw-r--r--ocamlbuild/my_std.mli65
-rw-r--r--ocamlbuild/my_unix.ml139
-rw-r--r--ocamlbuild/my_unix.mli73
-rw-r--r--ocamlbuild/my_unix_with_unix.ml75
-rw-r--r--ocamlbuild/my_unix_with_unix.mli14
-rw-r--r--ocamlbuild/ocaml_arch.ml135
-rw-r--r--ocamlbuild/ocaml_arch.mli16
-rw-r--r--ocamlbuild/ocaml_compiler.ml315
-rw-r--r--ocamlbuild/ocaml_compiler.mli81
-rw-r--r--ocamlbuild/ocaml_dependencies.ml219
-rw-r--r--ocamlbuild/ocaml_dependencies.mli43
-rw-r--r--ocamlbuild/ocaml_specific.ml373
-rw-r--r--ocamlbuild/ocaml_specific.mli17
-rw-r--r--ocamlbuild/ocaml_tools.ml73
-rw-r--r--ocamlbuild/ocaml_tools.mli22
-rw-r--r--ocamlbuild/ocaml_utils.ml87
-rw-r--r--ocamlbuild/ocaml_utils.mli30
-rw-r--r--ocamlbuild/ocamlbuild-presentation.rslide116
-rw-r--r--ocamlbuild/ocamlbuild.ml15
-rw-r--r--ocamlbuild/ocamlbuild.mli15
-rw-r--r--ocamlbuild/ocamlbuild.odocl38
-rw-r--r--ocamlbuild/ocamlbuild_pack.mlpack38
-rw-r--r--ocamlbuild/ocamlbuild_plugin.ml53
-rw-r--r--ocamlbuild/ocamlbuild_plugin.mli5
-rw-r--r--ocamlbuild/ocamlbuild_where.mli14
-rw-r--r--ocamlbuild/ocamlbuildlib.mllib4
-rw-r--r--ocamlbuild/ocamlbuildlight.ml14
-rw-r--r--ocamlbuild/ocamlbuildlight.mli14
-rw-r--r--ocamlbuild/ocamlbuildlightlib.mllib2
-rw-r--r--ocamlbuild/ocamldep.ml72
-rw-r--r--ocamlbuild/ocamldep.mli26
-rw-r--r--ocamlbuild/options.ml194
-rw-r--r--ocamlbuild/options.mli18
-rw-r--r--ocamlbuild/pathname.ml194
-rw-r--r--ocamlbuild/pathname.mli22
-rw-r--r--ocamlbuild/plugin.ml111
-rw-r--r--ocamlbuild/plugin.mli16
-rw-r--r--ocamlbuild/ppcache.ml88
-rw-r--r--ocamlbuild/ppcache.mli14
-rw-r--r--ocamlbuild/report.ml61
-rw-r--r--ocamlbuild/report.mli18
-rw-r--r--ocamlbuild/resource.ml324
-rw-r--r--ocamlbuild/resource.mli63
-rw-r--r--ocamlbuild/rule.ml296
-rw-r--r--ocamlbuild/rule.mli90
-rw-r--r--ocamlbuild/shell.ml71
-rw-r--r--ocamlbuild/shell.mli26
-rw-r--r--ocamlbuild/signatures.mli506
-rw-r--r--ocamlbuild/slurp.ml186
-rw-r--r--ocamlbuild/slurp.mli48
-rw-r--r--ocamlbuild/solver.ml119
-rw-r--r--ocamlbuild/solver.mli23
-rwxr-xr-xocamlbuild/start.sh91
-rw-r--r--ocamlbuild/std_signatures.mli94
-rw-r--r--ocamlbuild/tags.ml43
-rw-r--r--ocamlbuild/tags.mli15
-rw-r--r--ocamlbuild/test/good-output1022
-rwxr-xr-xocamlbuild/test/runtest.sh34
-rw-r--r--ocamlbuild/test/test1/foo.ml1
-rw-r--r--ocamlbuild/test/test10/dbdi12
-rwxr-xr-xocamlbuild/test/test10/test.sh6
-rw-r--r--ocamlbuild/test/test2/_tags1
-rw-r--r--ocamlbuild/test/test2/tata.ml1
-rw-r--r--ocamlbuild/test/test2/tata.mli2
-rwxr-xr-xocamlbuild/test/test2/test.sh18
-rw-r--r--ocamlbuild/test/test2/titi.ml1
-rw-r--r--ocamlbuild/test/test2/toto.ml5
-rw-r--r--ocamlbuild/test/test2/tutu.ml2
-rw-r--r--ocamlbuild/test/test2/tutu.mli3
-rw-r--r--ocamlbuild/test/test2/tyty.mli1
-rw-r--r--ocamlbuild/test/test2/vivi1.ml2
-rw-r--r--ocamlbuild/test/test2/vivi2.ml2
-rw-r--r--ocamlbuild/test/test2/vivi3.ml2
-rw-r--r--ocamlbuild/test/test3/_tags1
-rw-r--r--ocamlbuild/test/test3/a.ml1
-rw-r--r--ocamlbuild/test/test3/a.mli1
-rw-r--r--ocamlbuild/test/test3/b.ml1
-rw-r--r--ocamlbuild/test/test3/b.mli1
-rw-r--r--ocamlbuild/test/test3/c.ml1
-rw-r--r--ocamlbuild/test/test3/c.mli1
-rw-r--r--ocamlbuild/test/test3/d.ml1
-rw-r--r--ocamlbuild/test/test3/d.mli1
-rw-r--r--ocamlbuild/test/test3/e.ml1
-rw-r--r--ocamlbuild/test/test3/e.mli1
-rw-r--r--ocamlbuild/test/test3/f.ml2
-rw-r--r--ocamlbuild/test/test3/f.mli1
-rw-r--r--ocamlbuild/test/test3/proj.odocl1
-rwxr-xr-xocamlbuild/test/test3/test.sh11
-rw-r--r--ocamlbuild/test/test4/_tags2
-rw-r--r--ocamlbuild/test/test4/a/aa.ml1
-rw-r--r--ocamlbuild/test/test4/a/aa.mli1
-rw-r--r--ocamlbuild/test/test4/b/bb.ml2
-rwxr-xr-xocamlbuild/test/test4/test.sh11
-rw-r--r--ocamlbuild/test/test5/_tags1
-rw-r--r--ocamlbuild/test/test5/a.ml1
-rw-r--r--ocamlbuild/test/test5/a.mli1
-rw-r--r--ocamlbuild/test/test5/b.ml1
-rw-r--r--ocamlbuild/test/test5/c.mlpack1
-rw-r--r--ocamlbuild/test/test5/d.ml1
-rwxr-xr-xocamlbuild/test/test5/test.sh11
-rw-r--r--ocamlbuild/test/test6/a.ml1
-rw-r--r--ocamlbuild/test/test6/a.mli1
-rw-r--r--ocamlbuild/test/test6/b.ml1
-rw-r--r--ocamlbuild/test/test6/b.mli1
-rw-r--r--ocamlbuild/test/test6/b.mli.v11
-rw-r--r--ocamlbuild/test/test6/b.mli.v22
-rw-r--r--ocamlbuild/test/test6/d.ml2
-rw-r--r--ocamlbuild/test/test6/d.mli1
-rw-r--r--ocamlbuild/test/test6/d.mli.v12
-rw-r--r--ocamlbuild/test/test6/d.mli.v21
-rw-r--r--ocamlbuild/test/test6/main.ml1
-rw-r--r--ocamlbuild/test/test6/main.mli1
-rwxr-xr-xocamlbuild/test/test6/test.sh26
-rw-r--r--ocamlbuild/test/test7/_tags1
-rw-r--r--ocamlbuild/test/test7/aa.ml1
-rw-r--r--ocamlbuild/test/test7/bb.ml1
-rw-r--r--ocamlbuild/test/test7/bb.mli1
-rw-r--r--ocamlbuild/test/test7/bb2.ml3
-rw-r--r--ocamlbuild/test/test7/bb3.ml3
-rw-r--r--ocamlbuild/test/test7/bbcc.mllib1
-rw-r--r--ocamlbuild/test/test7/c2.ml1
-rw-r--r--ocamlbuild/test/test7/c2.mli1
-rw-r--r--ocamlbuild/test/test7/c3.ml1
-rw-r--r--ocamlbuild/test/test7/cc.ml1
-rw-r--r--ocamlbuild/test/test7/cool_plugin.ml1
-rw-r--r--ocamlbuild/test/test7/main.ml1
-rw-r--r--ocamlbuild/test/test7/myocamlbuild.ml3
-rwxr-xr-xocamlbuild/test/test7/test.sh19
-rw-r--r--ocamlbuild/test/test8/a.ml1
-rw-r--r--ocamlbuild/test/test8/myocamlbuild.ml9
-rwxr-xr-xocamlbuild/test/test8/test.sh11
-rw-r--r--ocamlbuild/test/test9/dbgl10
-rwxr-xr-xocamlbuild/test/test9/test.sh6
-rw-r--r--ocamlbuild/test/test9/testglob.ml91
-rw-r--r--ocamlbuild/tools.ml48
-rw-r--r--ocamlbuild/tools.mli20
183 files changed, 14243 insertions, 0 deletions
diff --git a/ocamlbuild/AUTHORS b/ocamlbuild/AUTHORS
new file mode 100644
index 0000000000..0b27a5b1a8
--- /dev/null
+++ b/ocamlbuild/AUTHORS
@@ -0,0 +1,2 @@
+Nicolas Pouillard
+Berke Durak
diff --git a/ocamlbuild/ChangeLog b/ocamlbuild/ChangeLog
new file mode 100644
index 0000000000..3d02e2607f
--- /dev/null
+++ b/ocamlbuild/ChangeLog
@@ -0,0 +1,3147 @@
+2007-02-06 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Make -a more static, to avoid some complications.
+
+ * ocaml_utils.ml,
+ * ocaml_compiler.ml,
+ * ocaml_compiler.ml,
+ * ocaml_specific.ml: Ditto.
+
+2007-02-06 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ A fix.
+
+ * ocaml_compiler.ml: Don't use these refs too early.
+ * ocamlbuild-presentation.rslide: .
+
+2007-02-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Plugin signature.
+
+ Somewhat a big patch, but that's just moving things around.
+
+ * signatures.mli: Add TAGS, OUTCOME, MISC, OPTIONS, ARCH and PLUGIN.
+ * ocamlbuild_plugin.mli: New.
+ * ocamlbuild_plugin.ml: Conform to the sig.
+
+ * command.ml,
+ * command.mli: Add a tags type.
+ * main.ml: Quit early if no targets.
+ * my_std.ml,
+ * my_std.mli: More things are in signatures.
+ * resource.ml,
+ * resource.mli: Remove the type t that was an Pathname.t alias.
+ * options.ml,
+ * options.mli: Add ext_lib, ext_obj, ext_dll.
+ * ocaml_compiler.ml: Update.
+ * ocaml_tools.ml: Update to Outcome.
+ * ocaml_specific.ml: Update.
+ * ocaml_utils.mli: Remove *ext_*.
+ * ocaml_arch.mli: Now in signatures.
+ * pathname.ml: Add readdir.
+ * slurp.ml: open Outcome.
+ * rule.ml,
+ * rule.mli,
+ * solver.ml,
+ * solver.mli: Update to Resource.t and Outcome.t.
+ * tags.mli: Now in Signatures.
+ * test/good-output: Update.
+ * test/test8/test.sh,
+ * test/test3/test.sh,
+ * test/test4/test.sh,
+ * test/test5/test.sh,
+ * test/test6/test.sh,
+ * test/test7/test.sh,
+ * test/test2/test.sh: Update to -verbose 0.
+
+2007-02-05 Berke Durak <berke.durak@inria.fr>
+
+ Continuing doc.
+
+ * manual/manual.tex: .
+ * .: .
+
+2007-02-05 Berke Durak <berke.durak@inria.fr>
+
+ Described display line.
+
+ * manual/manual.tex: .
+
+2007-02-05 Berke Durak <berke.durak@inria.fr>
+
+ Renamed -debug as -verbose. Authorized spaces etc. in flags. Continuing documentation.
+
+ * lexers.mll: .
+ * manual/manual.tex: .
+ * options.ml: .
+
+2007-02-05 Berke Durak <berke.durak@inria.fr>
+
+ Added man page.
+
+ * main.ml: .
+ * man: New.
+ * man/ocamlbuild.1: New.
+ * manual/manual.tex: .
+ * TODO: .
+
+2007-02-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Update start.sh.
+
+ * start.sh: Update.
+
+2007-02-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Typo s/Orignal/Original/g.
+
+2007-02-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Make signatures and std_signatures mliS.
+
+ * signatures.ml: Remove.
+ * std_signatures.ml: Remove.
+ * signatures.mli: New.
+ * std_signatures.mli: New.
+ * Makefile: Update.
+ * lexers.mll: Allow any prefix: for tags.
+
+2007-02-04 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ The beginning of a presentation.
+
+ * ocamlbuild-presentation.rslide: New.
+
+2007-02-04 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Also add who is the original author of the file.
+
+ * ocamlbuild.ml,
+ * ocamlbuild_plugin.ml,
+ * ocamlbuildlight.ml,
+ * ocamlbuild_where.mli,
+ * ocamlbuild.mli,
+ * ocamlbuildlight.mli,
+ * bool.ml,
+ * bool.mli,
+ * configuration.ml,
+ * configuration.mli,
+ * command.ml,
+ * command.mli,
+ * display.ml,
+ * discard_printf.ml,
+ * display.mli,
+ * discard_printf.mli,
+ * executor.ml,
+ * executor.mli,
+ * flags.ml,
+ * fda.ml,
+ * flags.mli,
+ * fda.mli,
+ * glob.ml,
+ * glob_ast.ml,
+ * glob_ast.mli,
+ * glob.mli,
+ * glob_lexer.mli,
+ * glob_lexer.mll,
+ * hygiene.ml,
+ * hooks.ml,
+ * hygiene.mli,
+ * hooks.mli,
+ * log.ml,
+ * lexers.mli,
+ * log.mli,
+ * lexers.mll,
+ * my_unix_with_unix.ml,
+ * main.ml,
+ * my_unix.ml,
+ * my_std.ml,
+ * my_unix_with_unix.mli,
+ * my_std.mli,
+ * my_unix.mli,
+ * main.mli,
+ * ocaml_utils.ml,
+ * ocaml_tools.ml,
+ * ocaml_arch.ml,
+ * ocaml_specific.ml,
+ * ocaml_compiler.ml,
+ * ocaml_dependencies.ml,
+ * ocaml_utils.mli,
+ * ocaml_specific.mli,
+ * ocaml_dependencies.mli,
+ * ocaml_tools.mli,
+ * ocaml_arch.mli,
+ * ocaml_compiler.mli,
+ * options.ml,
+ * options.mli,
+ * ocamldep.ml,
+ * ocamldep.mli,
+ * plugin.ml,
+ * ppcache.ml,
+ * pathname.ml,
+ * ppcache.mli,
+ * plugin.mli,
+ * pathname.mli,
+ * resource.ml,
+ * resource.mli,
+ * rule.ml,
+ * rule.mli,
+ * report.ml,
+ * report.mli,
+ * signatures.ml,
+ * slurp.ml,
+ * std_signatures.ml,
+ * solver.ml,
+ * shell.ml,
+ * shell.mli,
+ * slurp.mli,
+ * solver.mli,
+ * tags.ml,
+ * tools.ml,
+ * tags.mli,
+ * tools.mli: Ditto.
+
+2007-02-04 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add the header license.
+
+ * ocamlbuildlight.ml,
+ * ocamlbuild.ml,
+ * ocamlbuild_plugin.ml,
+ * ocamlbuild_where.mli,
+ * ocamlbuild.mli,
+ * ocamlbuildlight.mli,
+ * bool.ml,
+ * bool.mli,
+ * configuration.ml,
+ * configuration.mli,
+ * command.ml,
+ * command.mli,
+ * discard_printf.ml,
+ * display.ml,
+ * display.mli,
+ * discard_printf.mli,
+ * executor.ml,
+ * executor.mli,
+ * fda.ml,
+ * flags.ml,
+ * flags.mli,
+ * fda.mli,
+ * glob.ml,
+ * glob_ast.ml,
+ * glob.mli,
+ * glob_ast.mli,
+ * glob_lexer.mli,
+ * glob_lexer.mll,
+ * hygiene.ml,
+ * hooks.ml,
+ * hygiene.mli,
+ * hooks.mli,
+ * log.ml,
+ * lexers.mli,
+ * log.mli,
+ * lexers.mll,
+ * my_unix.ml,
+ * main.ml,
+ * my_std.ml,
+ * my_unix_with_unix.ml,
+ * misc/opentracer.ml,
+ * my_std.mli,
+ * main.mli,
+ * my_unix.mli,
+ * my_unix_with_unix.mli,
+ * ocaml_arch.ml,
+ * ocaml_compiler.ml,
+ * ocaml_specific.ml,
+ * ocaml_tools.ml,
+ * ocaml_utils.ml,
+ * ocaml_dependencies.ml,
+ * ocaml_utils.mli,
+ * ocaml_tools.mli,
+ * ocaml_dependencies.mli,
+ * ocaml_compiler.mli,
+ * ocaml_specific.mli,
+ * ocaml_arch.mli,
+ * options.ml,
+ * options.mli,
+ * ocamldep.ml,
+ * ocamldep.mli,
+ * plugin.ml,
+ * pathname.ml,
+ * ppcache.ml,
+ * plugin.mli,
+ * ppcache.mli,
+ * pathname.mli,
+ * resource.ml,
+ * resource.mli,
+ * rule.ml,
+ * rule.mli,
+ * report.ml,
+ * report.mli,
+ * slurp.ml,
+ * std_signatures.ml,
+ * signatures.ml,
+ * solver.ml,
+ * shell.ml,
+ * shell.mli,
+ * slurp.mli,
+ * solver.mli,
+ * tools.ml,
+ * tags.ml,
+ * tags.mli,
+ * tools.mli: Ditto.
+
+2007-02-03 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix a bug in copy_file.
+
+ * my_std.ml: Also use the binary mode for the output channel.
+
+2007-02-03 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add nopervasives, and nolabels.
+
+ * ocaml_specific.ml: Ditto.
+
+2007-02-03 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Windows cannot use executor.
+
+ * shell.ml: As in command.ml use executor only in non-windows and
+ non-degraded mode.
+ * rule.ml: Update two error messages.
+
+2007-02-02 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Some minor things for the ocaml myocamlbuild for instance.
+
+ * configuration.ml,
+ * configuration.mli: Add has_tag.
+ * my_std.ml,
+ * my_std.mli: Add getenv and copy_chan.
+ * ocaml_utils.ml,
+ * ocaml_utils.mli: Move some commands to rule.
+ * ocaml_specific.ml: Improve the menhir switching.
+ * options.ml,
+ * options.mli: Add -use-menhir and -menhir options.
+ * rule.ml,
+ * rule.mli: Add copy_rule and move some commands from ocaml_utils.
+ * signatures.ml: .
+
+2007-02-01 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Move main sigs in signatures.ml and std_signatures.ml.
+
+ * ocamlbuild_pack.mlpack: .
+ * ocamlbuildlib.mllib: .
+ * ocamlbuildlightlib.mllib: .
+ * ocamlbuild.odocl: .
+ * command.mli: .
+ * glob.mli: .
+ * log.mli: .
+ * my_unix_with_unix.ml: .
+ * my_std.ml: .
+ * my_std.mli: .
+ * ocaml_specific.ml: .
+ * pathname.mli: .
+ * std_signatures.ml: New.
+ * signatures.ml: New.
+ * start.sh: .
+ * tags.ml: .
+ * tags.mli: .
+ * test/test5/_tags: .
+ * Makefile: .
+ * _tags: .
+
+2007-02-01 Berke Durak <berke.durak@inria.fr>
+
+ Shell.run doesn't use execute_many in degraded mode.
+
+ * shell.ml: .
+
+2007-02-01 Berke Durak <berke.durak@inria.fr>
+
+ cp, rm -rf and mv-like commands use Executor to better play with display.
+
+ * display.ml: .
+ * my_unix.ml: .
+ * main.ml: .
+ * my_std.ml: .
+ * my_unix.mli: .
+ * shell.ml: .
+ * shell.mli: .
+ * start.sh: .
+ * _tags: .
+
+2007-02-01 Berke Durak <berke.durak@inria.fr>
+
+ Systematizing exit codes.
+
+ * executor.ml: .
+ * main.ml: .
+
+2007-02-01 Berke Durak <berke.durak@inria.fr>
+
+ Added automatic file: tag, changed flag syntax.
+
+ * lexers.mli: .
+ * lexers.mll: .
+ * main.ml: .
+ * ocamldep.ml: .
+ * ocamldep.mli: .
+ * tools.ml: .
+
+2007-01-31 Berke Durak <berke.durak@inria.fr>
+
+ Cleans up links to the _build directory.
+
+ * main.ml: .
+ * options.ml: .
+ * options.mli: .
+ * pathname.ml: .
+ * pathname.mli: .
+
+2007-01-31 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Restore the link to binary targets functionality.
+
+ * main.ml: Make it separate from target running.
+
+2007-01-31 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add an hygiene hook pair.
+
+ * ocamlbuild_plugin.ml,
+ * hooks.ml,
+ * hooks.mli,
+ * main.ml: Ditto.
+
+2007-01-31 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ The Killer feature about a fine grained dependency injection control.
+
+ * rule.ml,
+ * rule.mli: Add build_deps_of_tags and call it automatically before
+ * ocaml_compiler.ml,
+ * ocaml_compiler.mli: Rework tags, to have them when callinng
+ build_deps_of_tags.
+ executing a command.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Move the exception Exit_build_error to main and
+ remove the old dep function.
+ * ocamlbuild_plugin.ml: Export some new functions.
+ * test/test7/myocamlbuild.ml: Add a dep declaration.
+ * test/test7/cool_plugin.ml: New.
+ * test/test7/_tags: New.
+ * test/good-output: Update.
+ * flags.ml,
+ * command.ml,
+ * command.mli: Rename flags_of_tags as tag_handler.
+ * main.ml: Update error handling.
+ * TODO: Done.
+
+2007-01-30 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix and improve the new link/deps system.
+
+ * ocaml_dependencies.ml,
+ * ocaml_dependencies.mli: Some fixes and improvements.
+ * pathname.ml,
+ * pathname.mli: Add check_extension.
+ * ocaml_compiler.ml,
+ * ocaml_compiler.mli: Add support for hidden_packages and update.
+
+2007-01-30 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Reverse the last 2 patches, since there is fact no name clash.
+
+2007-01-30 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Shell -> Oshell second part.
+
+ * ocamlbuild.odocl: Ditto.
+ * test/good-output: Update.
+
+2007-01-30 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Rename the Shell module as Oshell to avoid a name clash with labltk.
+
+ * shell.ml: Remove.
+ * shell.mli: Remove.
+ * oshell.ml: New.
+ * oshell.mli: New.
+ * ocamlbuild_pack.mlpack,
+ * command.ml,
+ * display.ml,
+ * main.ml,
+ * options.ml,
+ * ppcache.ml,
+ * pathname.ml,
+ * plugin.ml,
+ * resource.ml,
+ * start.sh: Update.
+
+2007-01-30 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix 2 bugs.
+
+ * test/test9/testglob.ml: More tests.
+ * glob_lexer.mll: Fix "/**".
+ * _tags: Restore my warnings.
+ * executor.ml: Use the unused variable.
+
+2007-01-30 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Improve dprintf and update.
+
+ * log.ml, log.mli: dprintf now wraps the message between "@[<2>" and "@]@.".
+ * command.ml,
+ * display.ml,
+ * fda.ml,
+ * main.ml,
+ * ocaml_dependencies.ml,
+ * ocaml_compiler.ml,
+ * ocaml_utils.ml,
+ * ocamldep.ml,
+ * pathname.ml,
+ * resource.ml,
+ * rule.ml,
+ * solver.ml: Update the dprintf usage.
+
+2007-01-30 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add the new dependency linking system (plz test it !).
+
+ * ocamlbuild_pack.mlpack: Add a brand new module.
+ * ocaml_dependencies.ml: New.
+ * ocaml_dependencies.mli: New.
+ * ocaml_compiler.ml,
+ * ocaml_compiler.mli: Use this new module.
+ * resource.ml,
+ * resource.mli: Export a folding function on dependencies.
+ * TODO: Add something to do.
+ * start.sh: .
+ * main.ml: Update.
+
+2007-01-29 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Executor exit codes.
+
+ * executor.ml: Use the standard exit.
+ * main.ml: Some exit codes are reserved for Executor.
+
+2007-01-29 Berke Durak <berke.durak@inria.fr>
+
+ Executor returns finer-grained results.
+
+ * executor.ml: .
+ * manual/manual.tex: .
+
+2007-01-29 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Toward a working command execute feature :).
+
+ * executor.ml,
+ * executor.mli: FIXME.
+ * command.ml,
+ * command.mli: Update to the new signature and merge the degraded mode
+ to avoid duplication.
+ * my_unix.ml,
+ * my_unix.mli,
+ * ocaml_utils.ml,
+ * ocamldep.ml,
+ * plugin.ml,
+ * resource.ml,
+ * rule.ml,
+ * solver.ml,
+ * test/good-output: Update.
+
+2007-01-29 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Revert almost all of the 2 last patches.
+
+ * command.ml: .
+ * command.mli: .
+ * executor.ml: .
+ * executor.mli: .
+ * my_unix.ml: .
+ * my_unix.mli: .
+ * ocaml_utils.ml: .
+ * ocaml_specific.ml: .
+ * ocamldep.ml: .
+ * plugin.ml: .
+ * resource.ml: .
+ * rule.ml: .
+ * solver.ml: .
+
+2007-01-29 Berke Durak <berke.durak@inria.fr>
+
+ Fixing before/after thunks.
+
+ * command.ml: .
+ * command.mli: .
+ * ocaml_utils.ml: .
+ * ocamldep.ml: .
+ * plugin.ml: .
+ * resource.ml: .
+ * rule.ml: .
+ * solver.ml: .
+ * TODO: .
+
+2007-01-29 Berke Durak <berke.durak@inria.fr>
+
+ Adding before and after handlers to Executor.
+
+ * command.ml: .
+ * executor.ml: .
+ * executor.mli: .
+ * my_unix.ml: .
+ * my_unix.mli: .
+ * manual/manual.tex: .
+
+2007-01-29 Berke Durak <berke.durak@inria.fr>
+
+ Fixed multi-dir globbing.
+
+ * glob_lexer.mll: .
+ * manual/manual.tex: .
+
+2007-01-29 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add Rule.custom_rule and cleanup the ocamldep meta rule.
+
+ * ocamldep.ml,
+ * ocamldep.mli: Make it a meta rule (or a rule generator).
+ * rule.ml,
+ * rule.mli: Add custom_rule.
+ * ocaml_specific.ml: Update to Ocamldep.
+ * test/good-output: Minor update.
+
+2007-01-29 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ MakefileS...
+
+ * manual/Makefile: More things to remove (sometimes).
+ * Makefile: Use $(BUILDDIR) instead of _build.
+
+2007-01-26 Berke Durak <berke.durak@inria.fr>
+
+ Documenting glob expressions.
+
+ * glob_lexer.mll: Added negative character classes.
+ * manual/manual.tex: .
+
+2007-01-26 Berke Durak <berke.durak@inria.fr>
+
+ Started documenting glob syntax.
+
+ * manual/manual.tex: .
+
+2007-01-25 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ One other include dir fix.
+
+ * main.ml: Ditto.
+ * test/test9/testglob.ml: Add a failing test (request for feature).
+ * test/good-output: Update.
+
+2007-01-25 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Include dirs and Backtrace.
+
+ * main.ml: Fix -I, and restore the backtrace.
+ * report.ml,
+ * report.mli: Fix the backtrace and rename analyze to
+ print_backtrace_analyze.
+
+2007-01-25 Berke Durak <berke.durak@inria.fr>
+
+ Added cross-directory globbing.
+
+ * glob_ast.ml: .
+ * glob.ml: .
+ * glob_ast.mli: .
+ * glob_lexer.mll: .
+ * test/test9/testglob.ml: .
+
+2007-01-25 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Inlcude dirs trought tags.
+
+ * main.ml: Ditto.
+ * my_unix_with_unix.ml: Imrpove stat errors.
+ * my_std.ml,
+ * my_std.mli: .
+ * pathname.ml: bmla.
+ * slurp.ml,
+ * slurp.mli: Add force, fix bugs.
+
+2007-01-25 Berke Durak <berke.durak@inria.fr>
+
+ Fixed double display of error status.
+
+ * command.ml: .
+ * display.ml: .
+ * display.mli: .
+ * log.ml: .
+ * log.mli: .
+ * main.ml: .
+ * my_std.ml: .
+ * my_std.mli: .
+ * plugin.ml: .
+
+2007-01-25 Berke Durak <berke.durak@inria.fr>
+
+ Stupid bug.
+
+ * log.ml: .
+ * main.ml: .
+ * options.ml: .
+
+2007-01-25 Berke Durak <berke.durak@inria.fr>
+
+ Fixed interface, handling of -- with no argument.
+
+ * ocamlbuild_plugin.mli: Remove.
+ * manual/manual.tex: .
+ * options.ml: .
+
+2007-01-25 Berke Durak <berke.durak@inria.fr>
+
+ Updated start.sh.
+
+ * start.sh: .
+
+2007-01-25 Berke Durak <berke.durak@inria.fr>
+
+ Added .mlis.
+
+ * ocamlbuild_plugin.mli: New.
+ * fda.mli: New.
+ * main.ml: .
+ * ocaml_specific.ml: .
+ * plugin.ml: .
+ * plugin.mli: New.
+
+2007-01-25 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Cut down ocaml_specific in pieces.
+
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Split.
+ * ocamlbuild_plugin.ml: Update.
+ * ocamlbuild_pack.mlpack: Add new modules.
+ * my_std.ml,
+ * my_std.mli: Add good_outcome.
+ * ocaml_utils.ml: New.
+ * ocaml_tools.ml: New.
+ * ocaml_compiler.ml: New.
+ * ocaml_utils.mli: New.
+ * ocaml_compiler.mli: New.
+ * ocaml_tools.mli: New.
+ * ocamldep.ml: New.
+ * ocamldep.mli: New.
+ * start.sh: Update.
+ * TODO: Move things done.
+
+2007-01-25 Berke Durak <berke.durak@inria.fr>
+
+ Fixer return codes and error message flushing issues.
+
+ * display.ml: .
+ * log.ml: .
+ * log.mli: .
+ * main.ml: .
+ * report.ml: .
+ * report.mli: .
+
+2007-01-25 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add a warning.
+
+ * ocaml_specific.ml: In -debug 1 mode there is a now a warning when
+ ocamlbuild skip a seliently a module, supposing that's an error of
+ ocamldep.
+
+2007-01-24 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ More hooks.
+
+ * ocamlbuild_plugin.ml,
+ * hooks.ml,
+ * hooks.mli,
+ * main.ml: Add {Before,After}_rules.
+
+2007-01-24 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Call these hooks.
+
+ * main.ml: Call these hooks.
+
+2007-01-24 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add a first version of dispatch.
+
+ * ocamlbuild_plugin.ml: Export dispatch and the hooks type.
+ * ocamlbuild_pack.mlpack: Add Hooks.
+ * hooks.ml: New.
+ * hooks.mli: New.
+ * ocaml_specific.mli: New line.
+
+2007-01-24 Berke Durak <berke.durak@inria.fr>
+
+ Mini slurp bug.
+
+ * slurp.ml: .
+ * TODO: .
+
+2007-01-24 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix few more things.
+
+ * ocamlbuildlight.ml: .
+ * ocamlbuild_version.ml: Remove.
+ * ocamlbuild.ml: .
+ * ocamlbuild_pack.mlpack: .
+ * main.ml: .
+ * ocaml_specific.ml: .
+ * ocaml_specific.mli: .
+ * start.sh: .
+ * test/test2/toto.ml: .
+ * test/good-output: .
+
+2007-01-24 Berke Durak <berke.durak@inria.fr>
+
+ Read directories before files in Slurp.
+
+ * slurp.ml: .
+ * TODO: .
+
+2007-01-24 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix some bugs.
+
+ * ocamlbuild_version.ml: Remove.
+ * ocamlbuild.ml,
+ * ocamlbuildlight.ml: Main is now in the pack.
+ * ocamlbuild_pack.mlpack: more things.
+ * ocaml_specific.ml: One fix and one comment.
+ * start.sh: Update.
+
+2007-01-24 Berke Durak <berke.durak@inria.fr>
+
+ Splitting ocaml_specific into multiple files.
+
+ * ocamlbuildlight.ml: .
+ * ocamlbuild.ml: .
+ * ocamlbuild_version.ml: New.
+ * ocamlbuild.mli: .
+ * ocamlbuildlight.mli: .
+ * ocamlbuild_pack.mlpack: .
+ * command.ml: .
+ * fda.ml: New.
+ * hygiene.ml: .
+ * main.ml: New.
+ * my_std.ml: .
+ * my_std.mli: .
+ * main.mli: New.
+ * manual/manual.tex: .
+ * ocaml_specific.ml: .
+ * ocaml_specific.mli: .
+ * options.ml: .
+ * options.mli: .
+ * plugin.ml: New.
+ * rule.ml: .
+ * report.ml: .
+ * tools.ml: New.
+ * tools.mli: New.
+ * TODO: .
+ * _tags: .
+
+2007-01-24 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Minor changes.
+
+ * manual/manual.tex: Typo s/the the/the/g.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Add some function to deal with linking of a
+ module list. Add a better lib declaration function.
+ * TODO: Update.
+
+2007-01-17 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ A new pathname operator and a bug fix.
+
+ * pathname.ml,
+ * pathname.mli: add the ( -.- ) operator to add an extension to a
+ pathname.
+ * ocaml_specific.ml: Use that new operator.
+ * resource.ml: Fix a bug.
+
+2007-01-17 Berke Durak <berke.durak@inria.fr>
+
+ More examples.
+
+ * examples/example3/epoch.ml: .
+ * examples/example3/make.sh: New.
+ * manual/manual.tex: .
+ * TODO: .
+
+2007-01-17 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Infered mli's, and bug fixes.
+
+ * my_unix.ml: Fix a bug.
+ * my_std.mli: Doc.
+ * manual/manual.tex: Use \verb.
+ * ocaml_arch.ml: Don't always overide the forpack_flags_of_pathname
+ function reference.
+ * ocaml_arch.mli: Remove the reference.
+ * ocaml_specific.ml: Update for forpack and add infered mli's.
+ * pathname.ml,
+ * pathname.mli: Add is_directory.
+
+2007-01-17 Berke Durak <berke.durak@inria.fr>
+
+ More examples.
+
+ * examples/example3/epoch.ml: New.
+ * examples/example2/hello.ml: .
+ * examples/example2/greet.ml: New.
+ * examples/example3: New.
+ * examples/example2: New.
+ * manual/manual.tex: .
+ * TODO: .
+
+2007-01-17 Berke Durak <berke.durak@inria.fr>
+
+ Started examples.
+
+ * examples/example1/hello.ml: New.
+ * examples/example1: New.
+ * examples: New.
+ * manual/manual.tex: .
+ * .vcs: .
+ * TODO: .
+
+2007-01-17 Berke Durak <berke.durak@inria.fr>
+
+ Wrote limitations and features.
+
+ * manual/manual.tex: .
+
+2007-01-17 Berke Durak <berke.durak@inria.fr>
+
+ Wrote motivations.
+
+ * manual/manual.tex: .
+ * _tags: .
+
+2007-01-17 Berke Durak <berke.durak@inria.fr>
+
+ Started manual.
+
+ * manual/Makefile: New.
+ * manual/manual.tex: New.
+ * manual: New.
+
+2007-01-17 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Bugs, menhir, path variables.
+
+ * display.ml: Fix a bug.
+ * glob.mli: Fix a typo.
+ * lexers.mli,
+ * lexers.mll: Extend ocamldep_output lexer and meta_path lexer.
+ * my_std.ml,
+ * my_std.mli: Add memo and String.rev.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Better rules for C lib linking and menhir rules.
+ * resource.ml,
+ * resource.mli: Handle naively some multiple variables.
+ * rule.ml,
+ * rule.mli: Update.
+ * start.sh: Update.
+
+2007-01-11 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Integrate dprintf to the display.
+
+ * display.ml,
+ * display.mli: Add dprintf and log_level.
+ * log.ml,
+ * log.mli: Add dprintf and level.
+ * debug.ml: Remove.
+ * debug.mli: Remove.
+ * options.ml: Update.
+ * command.ml, ocaml_specific.ml, my_std.ml,
+ * pathname.ml, ppcache.ml, resource.ml,
+ * rule.ml, report.ml, slurp.ml, solver.ml,
+ * configuration.ml, tags.ml: Update to Log.
+ * ocamlbuild.odocl: Add Log, remove Debug.
+ * ocamlbuild_pack.mlpack: Remove Debug.
+ * bool.ml: Remove the debug dependency.
+
+2007-01-10 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Execute and windows...
+
+ * command.ml: Test windows here.
+ * my_unix_with_unix.ml: Revert a little.
+
+2007-01-10 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Don't use executor on windows.
+
+ * my_unix_with_unix.ml: Since at least set_nonblock does not works on
+ windows.
+
+2007-01-10 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add the -no-log option and fix a log bug.
+
+ * log.mli,
+ * log.ml: Log is now a lazy to have the good setup order.
+ * options.ml: Add the -no-log option.
+
+2007-01-10 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix a bug with quoting of the nil string.
+
+ * shell.ml: Quote the nil string.
+
+2007-01-09 Berke Durak <berke.durak@inria.fr>
+
+ Documented the interface of the glob module.
+
+ * glob.mli: .
+
+2007-01-09 Berke Durak <berke.durak@inria.fr>
+
+ Continuing to document interfaces.
+
+ * bool.mli: .
+ * debug.mli: .
+ * discard_printf.mli: .
+ * executor.mli: .
+ * hygiene.mli: .
+ * my_std.mli: .
+ * slurp.mli: .
+ * Makefile: .
+
+2007-01-09 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix a bug with directory links to build dir.
+
+ * ocaml_specific.ml,
+ * options.ml,
+ * options.mli: Keep the Slurp.entry instead of a set.
+ * pathname.ml: Clean the entry instead of the set, that more precise.
+ * Makefile: Add doc phonny rules.
+
+2007-01-09 Berke Durak <berke.durak@inria.fr>
+
+ Doc for Configuration.
+
+ * ocamlbuild_plugin.ml: .
+ * bool.mli: .
+ * configuration.ml: .
+ * configuration.mli: .
+ * command.mli: .
+ * doc: New.
+ * glob.ml: .
+ * ocaml_specific.ml: .
+ * Makefile: .
+
+2007-01-09 Berke Durak <berke.durak@inria.fr>
+
+ Started documentation.
+
+ * bool.mli: .
+ * command.ml: .
+ * command.mli: .
+
+2007-01-09 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Export the doc.
+
+ * Makefile: Use a link.
+ * _tags: Don't spend times in that dir.
+
+2007-01-09 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Put the log file in the source dir and not when building plugin.
+
+ * log.ml,
+ * log.mli: Use an optional.
+ * options.ml: Update.
+ * pathname.mli: Export in_source_dir.
+ * .vcs: Add _log.
+
+2007-01-09 Berke Durak <berke.durak@inria.fr>
+
+ Added doc target.
+
+ * report.ml: .
+ * Makefile: .
+ * TODO: .
+
+2007-01-09 Berke Durak <berke.durak@inria.fr>
+
+ Writes tags to log file.
+
+ * display.ml: .
+
+2007-01-09 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add the Log module.
+
+ * ocamlbuild_pack.mlpack: Add Log.
+ * command.ml,
+ * command.mli: Use Log.
+ * log.ml: New.
+ * log.mli: New.
+ * options.ml: Use Log.
+ * start.sh: Update.
+
+2007-01-09 Berke Durak <berke.durak@inria.fr>
+
+ Added -log option.
+
+ * command.ml: .
+ * command.mli: .
+ * display.ml: .
+ * display.mli: .
+ * executor.mli: .
+ * options.ml: .
+ * _tags: .
+
+2007-01-09 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Make usable the ocamldoc support.
+
+ * ocaml_specific.ml: Add rules for ocamldoc.
+ * ocamlbuild.odocl: New.
+ * test/test3/proj.odocl: New.
+ * test/good-output: Update.
+ * test/test3/test.sh: Add a odoc test.
+
+2007-01-09 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Some cleanups.
+
+ * ocamlbuild_plugin.ml: Add tag_file that simule one simple line in the
+ _tags file.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Add ln_s, touch, chmod.
+ * pathname.ml,
+ * pathname.mli: Remove map_extension*, split_extension* and compiled
+ files hack skipping.
+ * rule.ml: Improve logging.
+ * solver.ml: Use another level.
+
+2007-01-07 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix a bug with debug rules.
+
+ * ocaml_specific.ml: Move %.cmi from prods to deps.
+ * test/good-output: Update.
+
+2007-01-07 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add debugging rules.
+ To get a ocamlbuild with debugging info you can
+ call `make debug' that will produce ocamlbuild.d.byte
+ and x.d.cmo files.
+
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Add debugging rules, reorder warnings flag to
+ have 'A' and 'a' before others.
+ * Makefile: Add the debug target.
+ * _tags: Cleanup (remove the debug tag that was set by default).
+
+2007-01-07 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add profiling support directly in rules.
+ This means that you can now request for building a target such as
+ my_main.p.native or my_lib.p.cmxa, that will create %.p.cmx
+ intermediate files that do not interfer with non-profiling ones.
+
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Add rules and functions for native link and
+ comilation in profiling mode.
+ * Makefile: Add a profile target (require a fixed ocamlopt w.r.t pack).
+ * _tags: Take care also of .p.cmx files.
+ * glob.ml: IS.print is equivalent to print_is.
+ * my_std.ml: Fix a bug.
+
+2007-01-07 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add some functions...
+
+ * glob.ml: Extract is_suffix and is_prefix.
+ * my_std.ml,
+ * my_std.mli: Add String.{is_suffix,is_prefix,first_chars,last_chars}
+ and List.union.
+ * pathname.ml,
+ * pathname.mli: Add get_extensions, remove_extensions,
+ update_extensions, map_extensions that treat all extensions instead of
+ just the last.
+ * tags.ml,
+ * tags.mli: Add +++ and --- that treat optional tags.
+
+2007-01-06 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Change the default display in degraded mode.
+
+ * command.ml: Ditto.
+
+2007-01-06 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Cleanup Makefile options.
+
+ * Makefile: Ditto.
+
+2007-01-06 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add a simple opened files tracer.
+
+ * misc/opentracer.ml: New.
+ Just support ktrace for now. A strace one will be appreciated the
+ interface to follow is quite simple anyway.
+ * misc: New.
+
+2007-01-06 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Handle better commands without Px atom.
+
+ * command.ml: Display the whole command if no Px is found.
+ * display.mli: No longer export these strings.
+
+2007-01-06 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Handle myocamlbuild_config.mli.
+
+ * ocaml_specific.ml: Add support for an interface to the config.
+
+2007-01-06 Berke Durak <berke.durak@inria.fr>
+
+ Improved language of explanations in Report.
+
+ * report.ml: .
+
+2007-01-06 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Factor and fix the plugin building.
+
+ * ocamlbuildlight.mli: New.
+ * executor.ml: Call cleanup, add a fixme.
+ * ocaml_specific.ml: Factor and fix plugin stuffs.
+ * start.sh: Update.
+ * Makefile: Update.
+ * TODO: Update.
+ * _tags: No longer do favors to some modules.
+
+2007-01-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix plugins.
+
+ * ocamlbuildlib.mllib: Add missing modules.
+ * ocamlbuildlightlib.mllib: New.
+ * Makefile: Update.
+
+2007-01-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Change the my_unix system.
+
+ * ocamlbuildlight.ml: Just call the main.
+ * ocamlbuild.ml: Setup my_unix_with_unix.
+ * ocamlbuildlib.mllib: Remove executor and exit_codes for the lib.
+ * ocamlbuild_pack.mlpack: Remove my_std and my_unix.
+ * exit_codes.ml: Remove. Put them directly in executor.
+ * executor.ml: Add exitcodes.
+ * my_unix.ml: New. Default implem.
+ * my_unix_with_unix.ml: Extend the default implem.
+ * my_unix_without_unix.ml: Remove.
+ * my_unix.mli: Add the implem type and val.
+ * my_unix_with_unix.mli: New.
+ * ocaml_specific.ml,
+ * pathname.ml,
+ * slurp.ml,
+ * Makefile,
+ * command.ml,
+ * _tags: Update.
+
+2007-01-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Don't use executor for the myocamlbuild call.
+
+ * ocaml_specific.ml: Use sys_command directly.
+
+2007-01-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix a stupid bug.
+
+ * command.ml: That cause to have reversed sequences.
+
+2007-01-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Some libs and ocamldoc changes.
+
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Improve ocaml_lib_flag, add fews libs.
+ Fix ocamldoc support update tags, and use Px only once.
+
+2007-01-05 Berke Durak <berke.durak@inria.fr>
+
+ Started ocamldoc support.
+
+ * ocaml_specific.ml: .
+ * options.ml: .
+ * options.mli: .
+
+2007-01-05 Berke Durak <berke.durak@inria.fr>
+
+ Pretend option didn't work.
+
+ * command.ml: .
+
+2007-01-05 Berke Durak <berke.durak@inria.fr>
+
+ TODO + typo.
+
+ * options.ml: .
+ * TODO: .
+
+2007-01-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Really call executor all time.
+
+ * command.ml,
+ * command.mli: Remove normalization.
+ And execute_many, it's now execute that do all the job.
+ In degraded mode it's execute_degraded.
+ * my_unix_without_unix.ml: Update.
+ * ocaml_specific.ml,
+ * resource.ml,
+ * rule.ml,
+ * solver.ml: Update to Command.execute type.
+
+2007-01-05 Berke Durak <berke.durak@inria.fr>
+
+ Isatty detection logic.
+
+ * command.ml: .
+ * executor.ml: .
+ * my_unix_with_unix.ml: .
+ * my_unix_without_unix.ml: .
+ * my_unix.mli: .
+
+2007-01-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Always call executor.
+
+ * command.ml: Unless in degraded mode.
+
+2007-01-05 Berke Durak <berke.durak@inria.fr>
+
+ Removed debugging output, added period argument for ticker.
+
+ * display.ml: .
+ * executor.ml: .
+ * executor.mli: .
+ * my_unix.mli: .
+
+2007-01-05 Berke Durak <berke.durak@inria.fr>
+
+ Somewhat slow but executor seems to work.
+
+ * executor.ml: .
+
+2007-01-05 Berke Durak <berke.durak@inria.fr>
+
+ Added an Exit_codes module. Fixing Executor...
+
+ * ocamlbuild.ml: .
+ * ocamlbuildlib.mllib: .
+ * executor.ml: .
+ * exit_codes.ml: New.
+ * solver.ml: .
+
+2007-01-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix the max_jobs argument passing.
+
+ * command.ml: Use an optional argument.
+
+2007-01-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Subway changes...
+
+ * my_unix_without_unix.ml,
+ * my_unix_with_unix.ml,
+ * my_unix.mli,
+ * command.ml: Call the new execute_many.
+ * executor.ml,
+ * executor.mli: Handle command sequences.
+
+2007-01-04 Berke Durak <berke.durak@inria.fr>
+
+ Added Display.update.
+
+ * display.ml: .
+ * display.mli: .
+ * executor.ml: .
+
+2007-01-04 Berke Durak <berke.durak@inria.fr>
+
+ Added display function, indentation, language.
+
+ * display.ml: .
+ * display.mli: .
+ * hygiene.ml: .
+
+2007-01-04 Berke Durak <berke.durak@inria.fr>
+
+ Fixing interface of Executor.
+
+ * executor.ml: .
+ * executor.mli: .
+ * my_unix_with_unix.ml: .
+
+2007-01-04 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add attributes to entries. Add the -byte-plugin option.
+
+ * slurp.ml,
+ * slurp.mli: Add an attribute field, add map, rename fold_pathnames to
+ fold and filter_on_names to filter.
+ * hygiene.ml,
+ * hygiene.mli: Perform hygiene only on entries with a true attribute.
+ * options.ml,
+ * options.mli: Add the native_plugin reference and the -byte-plugin
+ option.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Exclude files tagged not_hygienic or precious
+ from hygiene.
+
+2007-01-04 Berke Durak <berke.durak@inria.fr>
+
+ Fixed pack issues.
+
+ * ocamlbuild.ml: .
+ * executor.ml: .
+ * executor.mli: New.
+ * _tags: .
+
+2007-01-04 Berke Durak <berke.durak@inria.fr>
+
+ Started executor module.
+
+ * executor.ml: New.
+ * hygiene.ml: .
+ * my_unix_with_unix.ml: .
+
+2007-01-04 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add virtual commands.
+
+ * command.ml,
+ * command.mli: Add the V constructor for virtual commands that
+ will query a virtual command solver to use the best implementation
+ of that virtual command.
+
+2007-01-04 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Mainly, prepare for parallel display.
+
+ * ocamlbuild_plugin.ml: Export file_rule.
+ * command.ml,
+ * command.mli: Some cleanup and preparation.
+ * lexers.mll: Remove the dirty hack.
+ * my_std.ml,
+ * my_std.mli: Move search_in_path to Command and add ( @:= ).
+ * my_unix_with_unix.ml,
+ * my_unix_without_unix.ml,
+ * my_unix.mli: Change the execute_many_using_fork type.
+ * ocaml_specific.ml: Use the nopervasives tag for
+ pervasives dependencies.
+ * start.sh: Update.
+ * test/test8/myocamlbuild.ml: Update.
+ * test/good-output: Update.
+ * Makefile: Update.
+
+2007-01-03 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ I don't like microbes.
+
+ * hygiene.ml: Reverse the bool.
+
+2007-01-03 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix the stat problem.
+
+ * ocaml_specific.ml: Use the filtered entry for source_dir_path_set.
+
+2007-01-03 Berke Durak <berke.durak@inria.fr>
+
+ Hygiene filters cleaned out microbes.
+
+ * hygiene.ml: .
+ * hygiene.mli: .
+ * ocaml_specific.ml: .
+ * ocaml_specific.mli: .
+ * slurp.ml: .
+ * slurp.mli: .
+
+2007-01-03 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Filename concat cleanup.
+
+ * my_std.ml,
+ * my_std.mli: Add filename_concat.
+ * glob.ml,
+ * hygiene.ml,
+ * lexers.mll,
+ * pathname.ml,
+ * resource.ml,
+ * report.ml,
+ * solver.ml,
+ * slurp.ml,
+ * solver.mli:
+ Use filename_concat.
+ * flags.ml: FIXME.
+
+2007-01-03 Berke Durak <berke.durak@inria.fr>
+
+ Revert to old.
+
+ * slurp.ml: .
+
+2007-01-03 Berke Durak <berke.durak@inria.fr>
+
+ Debugging tags for myocamlbuild.ml.
+
+ * ocaml_specific.ml: .
+ * slurp.ml: .
+
+2007-01-02 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Another atempt to fix the slurp bug and lazy.
+
+ * slurp.ml: Ditto.
+
+2007-01-02 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix slurp w.r.t lazyness: keep the cwd.
+
+ * slurp.ml: Ditto.
+
+2007-01-02 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ My_unix, slurp in degraded mode, _tags in subdirs, fix the bug with -j...
+
+ * ocamlbuild_version.mli: Remove.
+ * ocamlbuild_where.mli: New.
+ * display.mli: New.
+ * shell.ml: New.
+ * shell.mli: New.
+ * glob.ml,
+ * glob.mli,
+ * configuration.ml,
+ * lexers.mli,
+ * lexers.mll,
+ * configuration.mli: Honor _tags files in subdirs.
+ * my_unix_with_unix.ml,
+ * command.ml,
+ * command.mli,
+ * resource.ml,
+ * resource.mli,
+ * solver.ml: Fix the bug with the -j option.
+ * slurp.ml,
+ * slurp.mli: New degraded mode using the find command.
+ Use lazy values to avoid computing useless directories.
+ * options.ml,
+ * options.mli: Update -version and -where.
+ * pathname.ml,
+ * pathname.mli: Remove the init section.
+ * rule.ml,
+ * rule.mli: Add file_rule useful for rules that don't run a command but
+ just write a file.
+ * ocaml_specific.ml: Fix some plugin bugs. Remove -I to ocamldep.
+ Handle msvc .obj,.lib instead of .o,.a.
+ * my_unix_without_unix.ml: Make works link stuffs running the readlink
+ command.
+ * display.ml,
+ * hygiene.ml,
+ * my_std.ml,
+ * my_unix.mli,
+ * my_std.mli,
+ * start.sh,
+ * test/test5/test.sh,
+ * test/good-output,
+ * test/test6/test.sh,
+ * test/test7/test.sh,
+ * test/test4/test.sh,
+ * test/test8/test.sh,
+ * test/test3/test.sh,
+ * test/test2/test.sh,
+ * Makefile,
+ * _tags,
+ * ocamlbuild_pack.mlpack: Update.
+
+2007-01-02 Berke Durak <berke.durak@inria.fr>
+
+ Fixed ticker.
+
+ * display.ml: .
+
+2006-12-21 Berke Durak <berke.durak@inria.fr>
+
+ Cosmetic.
+
+ * command.ml: .
+ * display.ml: .
+
+2006-12-21 Berke Durak <berke.durak@inria.fr>
+
+ Computing display length.
+
+ * display.ml: .
+
+2006-12-21 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add -classic-display.
+
+ * command.ml,
+ * command.mli: Provide a way to use the classic display.
+ * options.ml: Add the -classic-display option.
+ * Makefile: Remove ppcache form the default.
+
+2006-12-21 Berke Durak <berke.durak@inria.fr>
+
+ Finish display only once ; display number of jobs cached.
+
+ * command.ml: .
+ * display.ml: .
+
+2006-12-21 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Oops fix a bug.
+
+ * command.ml: Add begin .. end.
+
+2006-12-21 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Some display fixes.
+
+ * command.ml: Select the display mode and remove the assert false.
+ * display.ml: Change the print function to have a more compact one.
+ * start.sh: Update.
+
+2006-12-21 Berke Durak <berke.durak@inria.fr>
+
+ Error support in Display.finish.
+
+ * display.ml: .
+
+2006-12-21 Berke Durak <berke.durak@inria.fr>
+
+ Support for cache.
+
+ * display.ml: .
+
+2006-12-21 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Integrate display mode.
+
+ * ocamlbuild_pack.mlpack: Add display.
+ * command.mli: Add Px to indicate to highligth this pathname.
+ * command.ml: Support Px and call Display.
+ * display.ml: Fix minor bugs.
+ * ocaml_specific.ml: Declare some Px, and quiet ocamlyacc, ocamllex.
+ * options.ml: Add quiet to default tags.
+ * ppcache.ml: Detect more accuratly ocamlrun.
+ * pathname.ml: Improve concat.
+ * _tags: No profile.
+
+2006-12-21 Berke Durak <berke.durak@inria.fr>
+
+ Added pretend.
+
+ * display.ml: .
+
+2006-12-21 Berke Durak <berke.durak@inria.fr>
+
+ Added ticker.
+
+ * display.ml: .
+
+2006-12-21 Berke Durak <berke.durak@inria.fr>
+
+ Display module.
+
+ * display.ml: .
+ * my_unix_with_unix.ml: .
+ * my_unix_without_unix.ml: .
+ * my_unix.mli: .
+ * test/test10/test.sh: New.
+ * test/test10: New.
+ * test/test10/dbdi: New.
+
+2006-12-21 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Use a better init order, and fix a Filename.concat usage.
+
+ * ocaml_specific.ml: The plugin should act before any initialization.
+ * ocaml_arch.ml: Use Pathname.(/).
+
+2006-12-21 Berke Durak <berke.durak@inria.fr>
+
+ Started user-friendly display module.
+
+ * display.ml: New.
+
+2006-12-21 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix init order.
+
+ * ocaml_specific.ml: Config must be available for plugin building.
+
+2006-12-21 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Some fixes.
+
+ * command.ml: Quote if needed.
+ * my_std.mli: Comment String.contains_string.
+ * resource.ml: Remove a useless separator.
+ * test/good-output: Update.
+
+2006-12-21 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Plugin config file and profile mode.
+
+ * ocaml_specific.ml: Fix a bug due to the lazyness of &&.
+ * ocaml_specific.mli: Move some functions.
+
+2006-12-21 Berke Durak <berke.durak@inria.fr>
+
+ Now compiles patterns for fast matching. Removed regexp support.
+
+ * glob_ast.ml: .
+ * glob.ml: .
+ * glob_lexer.mli: .
+ * glob_ast.mli: .
+ * glob_lexer.mll: .
+ * test/test9/testglob.ml: .
+ * test/test9/dbgl: New.
+
+2006-12-20 Berke Durak <berke.durak@inria.fr>
+
+ Pattern matching seems to start to work.
+
+ * glob.ml: .
+
+2006-12-20 Berke Durak <berke.durak@inria.fr>
+
+ Started faster pattern matching code.
+
+ * ocaml_specific.ml: .
+ * _tags: .
+
+2006-12-20 Berke Durak <berke.durak@inria.fr>
+
+ myocamlbuild is rebuilt only as needed.
+
+ * hygiene.ml: .
+ * ocaml_specific.ml: .
+ * pathname.ml: .
+ * pathname.mli: .
+ * resource.ml: .
+
+2006-12-20 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Some changes mainly for windows support.
+
+ * command.ml,
+ * command.mli: Add the Quote constructor to help quoting building in
+ commands.
+ * my_unix_with_unix.ml,
+ * my_unix_without_unix.ml,
+ * glob.ml: Commented reslash mode.
+ * my_std.ml,
+ * my_std.mli: Some new functions.
+ * my_unix.mli: Export sys_command.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Update and windows support.
+ * options.ml,
+ * options.mli: Remove the ocamlmklib option.
+ * ppcache.ml: Fix a bug.
+ * pathname.ml: Add more dirseps. Use a custom Filename.concat (for now).
+ * resource.ml,
+ * rule.ml,
+ * Makefile,
+ * _tags: Update.
+
+2006-12-15 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Update start order.
+
+ * start.sh: Ditto.
+
+2006-12-11 Berke Durak <berke.durak@inria.fr>
+
+ Added -custom, fixed paths for installation.
+
+ * ocaml_specific.ml: .
+ * Makefile: .
+
+2006-12-11 Berke Durak <berke.durak@inria.fr>
+
+ Typo.
+
+ * report.ml: .
+
+2006-12-08 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add a basic ocamlmklib support.
+
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Use ocamlmklib to make libraries if enabled.
+ * options.ml,
+ * options.mli: Add -ocamlmklib and -use-ocamlmklib.
+
+2006-12-08 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Export more references of options.
+
+ * command.ml,
+ * command.mli: Add ?quiet to execute.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Update to options.
+ * options.ml,
+ * options.mli: Move ocamlc, ocamlopt... to references on command specs.
+ * solver.ml: Update.
+ * Makefile: Use _ocamldistr to avoid hygiene.
+ * .vcs: Use _ocamldistr.
+
+2006-12-08 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Ocaml distrib stuffs.
+
+ * command.ml,
+ * command.mli: Add a normalization callback.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Add a more complete interface.
+ * options.ml,
+ * options.mli: Add nostdlib.
+ * pathname.ml: Add mkdir -p to import in build.
+ * rule.ml,
+ * rule.mli: Call normalization of commands for digest.
+ * report.ml: Add ignore.
+ * start.sh: Add report.ml*.
+ * Makefile: Add distrib exportation (make a link).
+ * .vcs: Unmask ocamldistrib link.
+
+2006-12-07 Berke Durak <berke.durak@inria.fr>
+
+ Added TODO item.
+
+ * .vcs: .
+ * TODO: .
+
+2006-12-07 Berke Durak <berke.durak@inria.fr>
+
+ Added TODO file.
+
+ * TODO: New.
+
+2006-12-07 Berke Durak <berke.durak@inria.fr>
+
+ Very rudimentary report analysis.
+
+ * report.ml: .
+ * _tags: .
+
+2006-12-07 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Update tests to run ocamlbuild correctly.
+
+ * test/test2/test.sh,
+ * test/test3/test.sh,
+ * test/test4/test.sh,
+ * test/test5/test.sh,
+ * test/test6/test.sh,
+ * test/test7/test.sh,
+ * test/test8/test.sh,
+ * test/test9/test.sh: Ditto.
+ * test/good-output: Update.
+
+2006-12-07 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Make test9 independant.
+
+ * test/test9/test.sh: Ditto.
+
+2006-12-07 Berke Durak <berke.durak@inria.fr>
+
+ Rewrote globbing engine, adding {,} ; moved reporting functions to Report.
+
+ * ocamlbuild_pack.mlpack: .
+ * command.ml: .
+ * glob_ast.ml: .
+ * glob.ml: .
+ * glob_ast.mli: .
+ * glob_lexer.mll: .
+ * ocaml_specific.ml: .
+ * report.ml: New.
+ * report.mli: New.
+ * solver.ml: .
+ * solver.mli: .
+ * start.sh: .
+ * test/test9/testglob.ml: .
+ * test/test9/test.sh: .
+ * test/test3/test.sh: .
+ * _tags: .
+
+2006-12-07 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Degraded mode...
+
+ * ocamlbuildlight.ml: New.
+ * ocamlbuild_pack.mlpack: Include new modules.
+ * bool.ml: Fake dependency.
+ * configuration.ml: Adapt to the glob parser.
+ * command.ml: Export the fork usage.
+ * glob.ml: Use Str through My_unix.
+ * glob_lexer.mli: New.
+ * glob_lexer.mll: Add slashs to valid character patterns.
+ * lexers.mli,
+ * lexers.mll: Use the glob parser.
+ * my_std.ml: Use My_unix.
+ * my_unix_with_unix.ml: New.
+ * my_unix_without_unix.ml: New.
+ * my_unix.mli: New.
+ * my_std.mli: Add search_in_path and change lazy force to ( !* ).
+ * ocaml_specific.ml: Some updates.
+ * options.ml,
+ * options.mli: Add -ocamlrun.
+ * pathname.ml: Adapt to an optional slurp.
+ * ppcache.ml: Use search_in_path of my_std.
+ * resource.ml: Update to ( !* ).
+ * solver.ml: Export Unix errors reporting.
+ * slurp.ml,
+ * slurp.mli: Use My_unix.
+ * start.sh: Update.
+ * test/test9/testglob.ml: Test a constant.
+ * test/test5/_tags,
+ * test/test3/_tags,
+ * test/test4/_tags: Don't use regexp.
+ * test/good-output: Add test9.
+ * test/test9/test.sh: Remove the parent usage.
+ * Makefile: Add the light mode.
+ * .vcs: Update.
+ * _tags: Update.
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ Extra tests for globbing.
+
+ * test/test9/testglob.ml: .
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ First draft of pattern matching.
+
+ * glob_ast.ml: .
+ * glob.ml: .
+ * glob_ast.mli: .
+ * glob_lexer.mll: .
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ More hard-wired but common cases for globbing.
+
+ * glob.ml: .
+ * test/test9/testglob.ml: .
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ Hidden interface in globber.
+
+ * glob.mli: .
+ * test/test9/testglob.ml: .
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ Basic globbing works.
+
+ * glob.ml: .
+ * glob.mli: .
+ * test/test9/testglob.ml: .
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ Improved interface.
+
+ * glob.ml: .
+ * glob_ast.ml: New.
+ * glob_ast.mli: New.
+ * glob.mli: New.
+ * glob_lexer.mll: .
+ * test/test9/testglob.ml: .
+ * _tags: .
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ Added test9.
+
+ * test/test9/testglob.ml: New.
+ * test/test9/parent: New.
+ * test/runtest.sh: .
+ * test/test9: New.
+ * test/test9/test.sh: New.
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ Parser seems to work.
+
+ * glob.ml: .
+ * glob_lexer.mll: .
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ Removed eof_char.
+
+ * glob.ml: .
+ * glob_lexer.mll: .
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ Interface seems to be OK.
+
+ * glob.ml: .
+ * glob_lexer.mll: .
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ Adding files for the globbing module.
+
+ * bool.ml: New.
+ * bool.mli: New.
+ * glob.ml: New.
+ * glob_lexer.mll: New.
+ * _tags: .
+
+2006-12-06 Berke Durak <berke.durak@inria.fr>
+
+ Replaced numeric escapes.
+
+ * lexers.mll: .
+
+2006-12-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Remove most of the Str usage by using ocamllex.
+
+ * ocamlbuild_pack.mlpack: Remove Re, add Lexers.
+ * configuration.ml: Use Lexers.
+ * command.ml: Don't use Re.
+ * lexers.mli: New.
+ * lexers.mll: New.
+ * my_std.ml,
+ * my_std.mli: Add String.before and String.after.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Use Lexers but also provide tags for warnings.
+ * resource.ml,
+ * rule.ml,
+ * options.ml,
+ * ppcache.ml,
+ * pathname.ml: Use Lexers.
+ * re.ml: Remove.
+ * re.mli: Remove.
+ * start.sh: Update.
+ * Makefile: Igonre _build... and gives -ml to ocamllex.
+ * _tags: Warnings for lexers.
+
+2006-12-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Use Sys instead of Unix for readdir.
+
+ * my_std.ml,
+ * my_std.mli: Supress a Unix usage.
+
+2006-12-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add an option to disable the link creation.
+
+ * ocaml_specific.ml: Honor this option.
+ * options.ml: Declare it.
+ * options.mli: Define it.
+
+2006-12-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Don't import compiled files...
+
+ * pathname.ml: For the OCaml compilation itself I need to exclude some
+ dirs that contains compiled files but I want to use some of them with
+ ocamlbuild.
+
+2006-12-05 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Support flags for ocamlyacc and ocamllex.
+
+ * ocaml_specific.ml,
+ * options.ml,
+ * options.mli: Add these options.
+
+2006-12-04 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Two fixes (hygiene and libraries)...
+
+ * hygiene.ml: Exit 0 if sterilize removes some files (since source
+ files are cached in a rather persistent data structure I prefer let the
+ user start on a fresh setup).
+ * ocaml_specific.ml: Use the dirname if there is no directory named by
+ removing the extension.
+
+2006-12-04 Berke Durak <berke.durak@inria.fr>
+
+ Small bug in hygiene.
+
+ * hygiene.ml: .
+
+2006-12-04 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add postition specifications to rules.
+
+ * rule.ml,
+ * rule.mli: Add a way to specifie where to put a new rule
+ (top,bottom,before another,after another).
+ * flags.ml: Reorder.
+ * my_std.ml,
+ * my_std.mli: Add mv, fix an error handling.
+ * ocaml_specific.ml: Better error message for circular dependencies.
+ * ppcache.ml: Handle errors better.
+
+2006-11-29 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add a working multiple job support.
+
+ * command.ml,
+ * command.mli: Add different versions of execute_many including a
+ version that use forks.
+ * options.ml,
+ * options.mli: Restore the -j option.
+ * solver.ml: Call Command.execute_many.
+ * test/runtest.sh: Pass $@ to sub tests.
+ * test/good-output: Update.
+
+2006-11-28 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix the link order.
+
+ * start.sh: Fix the link order.
+
+2006-11-28 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ One step toward multiple jobs: Add the support for suspended building.
+
+ * resource.ml,
+ * resource.mli: Add the notion of suspended building.
+ This represent a resource that is fully ready for evaluation, it's just
+ a command and a function to apply after.
+ * rule.ml: Do not really execute rules that can be safely suspended.
+ * solver.ml: Play with suspended rules to collect as many as possible
+ to get closer to a pararllel execution.
+
+2006-11-27 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix the makefile.
+
+ * Makefile: Fix deps.
+
+2006-11-27 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Activates more warnings, and prepare the -j feature.
+
+ * hygiene.ml: Consolidates fragile patterns.
+ * my_std.ml: Likewise.
+ * ocaml_specific.ml: Mainly update to the new builder prototype.
+ * pathname.ml,
+ * pathname.mli: Kick a useless parameter.
+ * resource.ml: Remove dead code and update.
+ * rule.ml,
+ * rule.mli: The bulider now takes a list of resource lists, it will
+ try to make in parallel the first level of commands.
+ * solver.ml: Update to builder without parallelism.
+ * test/good-output: Update.
+ * Makefile: Warnings are now set to -w A -warn-error A.
+
+2006-11-26 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix packages... again.
+
+ * ocaml_specific.ml: Ditto.
+
+2006-11-26 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix packages.
+
+ * ocaml_specific.ml: Try to handle better packages during link.
+ * Makefile: Add the try_bootstrap rule.
+
+2006-11-26 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add -tag, -tags to options.
+
+ * ocaml_specific.ml: Append default tags from options.
+ * options.ml,
+ * options.mli: Add -tag and -tags.
+ * tags.mli: Indent.
+
+2006-11-26 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix a bug and update tests.
+
+ * resource.ml: Use Hashtbl.replace of course instead of Hashtbl.add to
+ avoid a nasty bug.
+ * test/test7/test.sh,
+ * test/test8/test.sh,
+ * test/test2/test.sh,
+ * test/test6/test.sh,
+ * test/test4/test.sh,
+ * test/test5/test.sh,
+ * test/test3/test.sh: Extract program options to be sure that
+ the -nothing-should-be-rebuilt option is before the -- one.
+ * test/good-output: Update.
+
+2006-11-26 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Use a hashtbl for digests.
+
+ * resource.ml: Ditto.
+ * ocaml_specific.ml: Remove dead code.
+
+2006-11-26 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Use lists instead of sets for rule deps & prods.
+
+ * ocaml_specific.ml: Move the mli dep first.
+ * resource.ml,
+ * resource.mli: No more provide digest_resources but digest_resource.
+ * rule.ml,
+ * rule.mli: Use list instead of sets for deps and prods, since they are
+ not heavily updated and the order matter.
+ * solver.ml: Adapt.
+ * test/good-output: Yeah!
+
+2006-11-26 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ One more fix for libraries.
+
+ * ocaml_specific.ml: Improve the link_exception handling.
+ * test/good-output: Update.
+
+2006-11-25 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix the library linking.
+
+ * ocaml_specific.ml: The test7 is specially made to check that feature.
+
+2006-11-25 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Remove list_set.
+
+ * ocamlbuild_pack.mlpack: Remove list_set
+ * list_set.ml: Remove.
+ * list_set.mli: Remove.
+ * start.sh: Remove list_set.
+ * test/good-output: Regen.
+
+2006-11-25 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix the C rule when dirname = '.'.
+
+ * ocaml_specific.ml: Don't move the output when it's useless.
+
+2006-11-25 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Ignore ocamlbuild_version.ml.
+
+2006-11-25 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ New transitive closure.
+
+ * ocamlbuild_version.ml: Remove.
+ * my_std.ml,
+ * my_std.mli: Add a debug mode for digests and run_and_read.
+ * ocaml_specific.ml: New transitive closure.
+ * pathname.ml,
+ * pathname.mli: Export also parent_dir_name and fix same_contents.
+ * resource.ml,
+ * resource.mli: Add dependencies.
+ * rule.ml: Adapt.
+ * test/good-output: Regen.
+ * Makefile: Improve install.
+ * .vcs: Ignore other _build dirs.
+
+2006-11-20 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Rule definition shortcut and C files.
+
+ * rule.ml,
+ * rule.mli: Allow to pass ~prod and ~dep when there is just one file.
+ * ocaml_specific.ml: Add a rule for C files and use the previous
+ shortcut.
+
+2006-11-18 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ No more extend Format.
+
+ * command.ml,
+ * my_std.ml,
+ * my_std.mli: Put directly ksbprintf and sbprintf in My_std.
+
+2006-11-18 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Clean up and consistent use of Pathname instead of Filename.
+
+ * command.ml,
+ * my_std.ml,
+ * my_std.mli,
+ * ocaml_specific.ml,
+ * pathname.ml,
+ * ppcache.ml,
+ * pathname.mli,
+ * resource.ml: That's it.
+
+2006-11-18 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Restore List_set.
+
+ * ocamlbuild_pack.mlpack,
+ * list_set.ml,
+ * list_set.mli,
+ * resource.ml,
+ * start.sh: Ditto.
+
+2006-11-18 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Remove List_set and List_map.
+
+ * ocamlbuild_pack.mlpack: No more in the pack.
+ * list_set.ml: Remove.
+ * list_map.ml: Remove.
+ * list_map.mli: Remove.
+ * list_set.mli: Remove.
+ * resource.ml: Use a Set.
+ * start.sh: Adapt.
+
+2006-11-18 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Huge speed up, worth updating.
+
+ * resource.ml,
+ * resource.mli: Use a hash instead of map, remove the percent type.
+ * rule.ml,
+ * rule.mli: Remove the function for rule names. Use an exception to
+ choose matching rules.
+
+2006-11-18 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Speedup rule calling.
+
+ * rule.ml,
+ * rule.mli: No more call the code rule twice to compute the digest.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Adapt to Rule.
+ * test/test8/myocamlbuild.ml: Use the exception.
+ * test/good-output: Update.
+ * boot: Update svn:ignore.
+
+2006-11-16 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Remove phony resources and include dependencies.
+
+ * ocaml_specific.ml,
+ * options.ml,
+ * options.mli,
+ * pathname.ml,
+ * pathname.mli,
+ * resource.ml,
+ * resource.mli,
+ * rule.ml,
+ * rule.mli,
+ * solver.ml,
+ * test/test8/myocamlbuild.ml: Simplify a lot the code.
+
+2006-11-16 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Some improvements...
+
+ * ocamlbuild.ml: .
+ * ocamlbuild_version.ml: New.
+ * ocamlbuild_plugin.ml: New.
+ * ocamlbuild_version.mli: New.
+ * ocamlbuildlib.mllib: .
+ * ocamlbuild.sh: Remove.
+ * ocamlbuild_pack.mlpack: New.
+ * boot: .
+ * ocaml_specific.ml: .
+ * ocaml_specific.mli: .
+ * options.ml: .
+ * options.mli: .
+ * rule.ml: .
+ * rule.mli: .
+ * start.sh: .
+ * test/test8/a.ml: New.
+ * test/test7/a2.ml: .
+ * test/test7/a3.ml: New.
+ * test/test8/myocamlbuild.ml: New.
+ * test/test7/myocamlbuild.ml: New.
+ * test/test8: New.
+ * test/test8/test.sh: New.
+ * test/runtest.sh: .
+ * test/test7/test.sh: .
+ * test/good-output: .
+ * Makefile: .
+ * _tags: .
+
+2006-11-15 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add support for libraries.
+
+ * ocamlbuildlib.ml: Remove.
+ * ocamlbuildlib.mllib: New.
+ * ocaml_specific.ml: Rules and actions for libraries.
+ * rule.ml: Improve explanations.
+ * start.sh: Don't make ocamlbuildlib.
+ * test/test7/a.mli: New.
+ * test/runtest.sh: Add test7.
+ * test/test7/test.sh: Add reverts for a.ml.
+ * test/good-output: Update.
+ * Makefile: Remove junk lines.
+
+2006-11-14 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add a tests for libraries.
+
+ * test/test7/e.ml: New.
+ * test/test7/d.ml: New.
+ * test/test7/a.ml: New.
+ * test/test7/b.ml: New.
+ * test/test7/a2.ml: New.
+ * test/test7/c.ml: New.
+ * test/test7/test.sh: New.
+ * test/test7/ablib.mllib: New.
+ * test/test7: New.
+
+2006-11-14 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Simplify dependency rules.
+
+ * ocaml_specific.ml: No more use bytelinkdeps...
+ * rule.ml,
+ * rule.mli: Add a dyndeps set.
+ * ocamlbuild.sh,
+ * pathname.ml,
+ * Makefile: Update.
+
+2006-11-14 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Update tests...
+
+ * test/test2/vivi3.ml: .
+ * test/good-output: .
+
+2006-11-10 Berke Durak <berke.durak@inria.fr>
+
+ Added -sterilize option.
+
+ * hygiene.ml: ditto
+ * hygiene.mli: ditto
+ * ocaml_specific.ml: ditto
+ * options.ml: ditto
+ * options.mli: ditto
+
+2006-11-10 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ View the context dir in first.
+
+ * pathname.ml: Ditto.
+
+2006-11-10 Berke Durak <berke.durak@inria.fr>
+
+ Added thread and profile tags.
+
+ * ocaml_specific.ml: ditto.
+
+2006-11-10 Berke Durak <berke.durak@inria.fr>
+
+ Added law for leftover dependency files.
+
+ * ocaml_specific.ml: ditto.
+
+2006-11-10 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Reverse the ignore_auto default value.
+
+ * options.ml: Add -no-skip, remove -ignore-auto, add -Is and -Xs.
+ * test/test2/test.sh,
+ * test/test5/test.sh,
+ * test/test6/test.sh,
+ * test/test4/test.sh,
+ * test/test3/test.sh,
+ * Makefile: Revert flags.
+
+2006-11-10 Berke Durak <berke.durak@inria.fr>
+
+ Added install target to Makefile.
+
+ * Makefile: .
+
+2006-11-10 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Deal with for-pack flags...
+
+ * ocaml_arch.ml: Define a hook.
+ * ocaml_arch.mli: Declare it.
+ * ocaml_specific.ml: Use it.
+ * test/test6: Ignore main.byte.
+
+2006-11-09 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix start.sh and remove dead code.
+
+ * ocaml_specific.ml: Remove dead code about ignore_auto.
+ * start.sh: Swap two modules.
+ * test/test6/main.byte: Remove.
+
+2006-11-09 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Pack now works great...
+
+ * ocamlbuild.sh: Use ocamlopt.
+ * command.ml: Reset filesys cache.
+ * my_std.ml,
+ * my_std.mli: Add a filesys cache for
+ case sensitive file_exists and digest over files.
+ * ocaml_specific.ml: Work on link and packs.
+ * ppcache.ml: Exit 2 is for unix.
+ * pathname.ml,
+ * resource.ml,
+ * rule.ml,
+ * rule.mli,
+ * slurp.ml,
+ * solver.ml,
+ * solver.mli,
+ * test/test5: Update.
+
+2006-11-07 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Too lazy to fill this up :).
+
+ * ocamlbuild.sh,
+ * configuration.ml,
+ * command.ml,
+ * debug.ml,
+ * debug.mli,
+ * my_std.ml,
+ * my_std.mli,
+ * ocaml_specific.ml,
+ * ocaml_specific.mli,
+ * options.ml,
+ * options.mli,
+ * pathname.ml,
+ * ppcache.ml,ew.
+ * ppcache.mli,ew.
+ * pathname.mli,
+ * resource.ml,
+ * resource.mli,
+ * rule.ml,
+ * rule.mli,
+ * slurp.ml,
+ * solver.ml,
+ * solver.mli,
+ * slurp.mli,
+ * start.sh,
+ * tags.ml,
+ * test/test5/test.sh,
+ * test/test4/test.sh,
+ * test/test3/test.sh,
+ * test/good-output,
+ * test/test2/test.sh,
+ * test/test6/test.sh,
+ * Makefile,
+ * _tags: This too.
+
+2006-11-04 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Some pack,dirs stuffs.
+
+ * ocamlbuild.ml,
+ * ocamlbuildlib.ml,ew.
+ * ocamlbuild.sh,ew.
+ * configuration.ml,
+ * my_std.ml,
+ * my_std.mli,
+ * ocaml_arch.ml,ew.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli,
+ * ocaml_arch.mli,ew.
+ * options.ml,
+ * options.mli,
+ * pathname.ml,
+ * pathname.mli,
+ * resource.ml,
+ * resource.mli,
+ * rule.ml,
+ * solver.ml,
+ * test/good-output,
+ * Makefile,
+ * _tags: That's it.
+
+2006-10-31 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Remove the dirty thing about cmi's.
+
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Moves of files are no more needed.
+ * test/good-output: Update.
+
+2006-10-31 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Some renaming and cleanup...
+
+ * ocamlbuild.ml,
+ * configuration.ml,
+ * configuration.mli,
+ * list_set.ml,
+ * ocaml_specific.ml,
+ * resource.ml,
+ * test/good-output,
+ * test/test6/test.sh: Do that.
+
+2006-10-31 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Use the nothing-should-be-rebuilt for tests and update the output.
+
+ * test/test2,
+ * test/test2/test.sh,
+ * test/test3/test.sh,
+ * test/test4/test.sh,
+ * test/test5/test.sh,
+ * test/test6/test.sh,
+ * test/good-output: Do that.
+
+2006-10-31 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add a mode usefull for tests.
+
+ * options.ml, options.mli, rule.ml:
+ This new mode fails when something needs to be rebuilt.
+
+2006-10-31 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Improve the ocaml rule set.
+
+ * ocaml_specific.ml: Yipee!
+
+2006-10-31 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add scripts to run tests.
+
+ * test/test2/vivi1.ml: New.
+ * test/test2/vivi2.ml: New.
+ * test/test2/vivi3.ml: New.
+ * test/test2/vivi.ml: .
+ * test/test4/test.sh: New.
+ * test/test5/test.sh: New.
+ * test/test2/test.sh: New.
+ * test/test6/test.sh: .
+ * test/good-output: New.
+ * test/test3/test.sh: New.
+ * test/runtest.sh: New.
+
+2006-10-31 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Restore some recursivity for includes.
+
+ * resource.ml,
+ * resource.mli: Remove the digest field.
+ * rule.ml: .
+ * test/test6/test.sh: .
+
+2006-10-30 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Remove the arbitrary deep dependencies.
+
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: No more implicit transitives deps.
+ * resource.ml,
+ * resource.mli: Remove as many things as possible.
+ * rule.ml,
+ * rule.mli,
+ * solver.ml: Simplify.
+ * command.ml: Fix newlines and flush.
+
+2006-10-30 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Separated preprocessing, total order over rules...
+
+ * ocamlbuild.ml,
+ * my_std.ml,
+ * my_std.mli,
+ * ocaml_specific.ml,
+ * ocaml_specific.mli,
+ * options.ml,
+ * options.mli,
+ * pathname.ml,
+ * pathname.mli,
+ * resource.ml,
+ * resource.mli,
+ * rule.ml,
+ * rule.mli,
+ * solver.ml,
+ * test/test2/tutu.ml,
+ * tags.ml,
+ * test/test2/tyty.mli,ew.
+ * test/test6/test.sh,
+ * test/test6,
+ * test/test5/_tags,
+ * test/test5: Update.
+
+2006-10-27 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add options: -ocamlc,-ocamlopt,-ocamldep,-ocamlyacc,-ocamllex.
+
+ * options.ml,
+ * options.mli: Declare them.
+ * ocaml_specific.ml: Use them.
+
+2006-10-27 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix start.sh.
+
+ * start.sh: Fix the output.
+
+2006-10-27 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Regen start.sh.
+
+ * start.sh: Regen.
+
+2006-10-27 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Use the list based implems and fix many bugs.
+
+ * ocamlbuild.ml: Rename some dependency files.
+ * boot: Ignore boot/ocamlbuild.byte.save.* files.
+ * command.ml: Fix command printing.
+ * my_std.ml,
+ * my_std.mli: Add List.equal, use the cp command in Shell.cp.
+ * ocaml_specific.ml,
+ * ocaml_specific.mli: Many things.
+ * pathname.ml, pathname.mli: Make compare obselete prefer equal.
+ * resource.ml, resource.mli: Add print_cache and use list based
+ sets and maps.
+ * Makefile: Add the bootstrap rule.
+
+2006-10-27 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add a test for fine-grained dependencies.
+
+ * test/test6/main.ml: New.
+ * test/test6/d.ml: New.
+ * test/test6/b.ml: New.
+ * test/test6/a.ml: New.
+ * test/test6/main.mli: New.
+ * test/test6/a.mli: New.
+ * test/test6/d.mli: New.
+ * test/test6/b.mli: New.
+ * test/test6/b.mli.v2: New.
+ * test/test6/main.byte: New.
+ * test/test6/d.mli.v1: New.
+ * test/test6/test.sh: New.
+ * test/test6/d.mli.v2: New.
+ * test/test6/b.mli.v1: New.
+ * test/test6: New.
+
+2006-10-26 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Dummy implementations for set and map using lists.
+ The main advantage is to only rely on the equal function that is simpler
+ to maintain correct in an imperative setting.
+
+ * list_map.ml: New.
+ * list_set.ml: New.
+ * list_map.mli: New.
+ * list_set.mli: New.
+
+2006-10-24 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fixes and improvment.
+
+ * ocamlbuild.ml,
+ * my_std.ml,
+ * my_std.mli,
+ * ocaml_specific.ml,
+ * ocaml_specific.mli,
+ * pathname.ml,
+ * resource.ml,
+ * rule.ml,
+ * rule.mli,
+ * solver.ml,
+ * solver.mli: The previous version was somwhat unstable.
+
+2006-10-24 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Many things...
+
+ * ocamlbuild.ml,
+ * command.ml,
+ * command.mli,
+ * ocaml_specific.ml,
+ * ocaml_specific.mli,
+ * options.ml,
+ * options.mli,
+ * resource.ml,
+ * resource.mli,
+ * rule.ml,
+ * rule.mli,
+ * solver.ml,
+ * solver.mli:
+ Simplify the whole solver by removing the value type.
+ Rule code now returns a resource set, that is injected as dependencies.
+ So rule code always returns unit. But can raise exceptions.
+ Add -ignore, and -ignore-auto options to workaround ocamldep
+ approximations without igonring errors.
+ * Makefile: Add backup and restore targets.
+
+2006-10-23 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Compute digests of dependencies recursively.
+
+ * ocamlbuild.ml,
+ * ocaml_specific.ml,
+ * options.ml,
+ * options.mli,
+ * resource.ml,
+ * resource.mli,
+ * rule.ml: Ditto.
+
+2006-10-23 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ One step toward a parallelisable system.
+
+ * boot,
+ * command.ml,
+ * ocaml_specific.ml,
+ * ocaml_specific.mli,
+ * options.ml,
+ * options.mli,
+ * rule.ml,
+ * rule.mli,
+ * solver.ml: Update.
+ * value.ml: Remove.
+ * value.mli: Remove.
+
+2006-10-20 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add vcs config file to setup a good default setup.
+
+ * .vcs: New.
+
+2006-10-20 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Simplify the bootstrap by introducing a shell script.
+
+ * boot/ocamlbuild.byte: Remove. Useless in distribution mode
+ but will be created, the first time. So the devel is not
+ disturbed.
+ * start.sh: New.
+ * Makefile: Remove the old one to use start.sh.
+
+2006-10-20 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Take command line in account for the digest computation.
+
+ * command.ml,
+ * command.mli,
+ * debug.ml,
+ * ocaml_specific.ml,
+ * ocaml_specific.mli,
+ * resource.ml,
+ * resource.mli,
+ * rule.ml,
+ * rule.mli,
+ * solver.ml,
+ * value.ml,
+ * value.mli: Update.
+
+2006-10-19 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ New pathname representation.
+
+ * pathname.ml, pathname.mli: This new representation should
+ avoids "fix" problems.
+
+2006-10-17 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Change the cache implem -> now really fast at link time.
+
+ * ocamlbuild.ml,
+ * boot/ocamlbuild.byte,
+ * my_std.ml,
+ * ocaml_specific.ml,
+ * pathname.ml,
+ * resource.ml,
+ * resource.mli,
+ * solver.ml: By replacing various sets by a map of records and
+ remember that something has not changed, or cannot be built;
+ there is a real speedup. In particular to detect that the link is
+ not necessary to do.
+
+2006-10-17 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add a basic support for a digest based cache verification.
+
+ * resource.ml, resource.mli: Add have_digest and store_digest.
+ * rule.ml: Use these digests but don't include the command for
+ now.
+ * test/test2/vivi.ml, test/test2/tata.mli: Dummy updates.
+
+2006-10-16 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Split in many files.
+
+ * ocamlbuild.ml: Splitted.
+ * boot/ocamlbuild.byte: Updated.
+ * configuration.ml: New.
+ * configuration.mli: New.
+ * command.ml: New.
+ * command.mli: New.
+ * debug.ml: New.
+ * debug.mli: New.
+ * flags.ml: New.
+ * flags.mli: New.
+ * my_std.ml: New.
+ * my_std.mli: New.
+ * ocaml_specific.ml: New.
+ * ocaml_specific.mli: New.
+ * options.ml: New.
+ * options.mli: New.
+ * pathname.ml: New.
+ * pathname.mli: New.
+ * re.ml: New.
+ * re.mli: New.
+ * resource.ml: New.
+ * resource.mli: New.
+ * rule.ml: New.
+ * rule.mli: New.
+ * solver.ml: New.
+ * solver.mli: New.
+ * test/test5/d.ml: New.
+ * tags.ml: New.
+ * test/test5/b.ml: New.
+ * test/test5/a.ml: New.
+ * tags.mli: New.
+ * test/test5/a.mli: New.
+ * test/test5/c.mlpack: New.
+ * test/test5/_tags: New.
+ * test/test5: New.
+ * value.ml: New.
+ * value.mli: New.
+ * Makefile: .
+
+2006-10-16 Berke Durak <berke.durak@inria.fr>
+
+ Various useful changes.
+
+ * ocamlbuild.ml: Hygiene to true.
+ * slurp.ml: Remove debugging
+ * Makefile: Clean annot and object files.
+
+2006-10-15 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Bootstrap it ;).
+
+ * ocamlbuild.ml: Add support for -g, -dtypes, and -rectypes in
+ four lines.
+ * _tags: New. Specify how to build ocamlbuild itself.
+ * boot: New.
+ * boot/ocamlbuild.byte: New. A bytecode version needed to
+ bootstrap
+ * Makefile: By default make it a wrapper over ocamlbuild in boot.
+
+2006-10-15 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Little fix...
+
+ * ocamlbuild.ml: Don't assoc over pathnames since the default
+ compare is wrong and slow use the string repr.
+
+2006-10-15 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Allow to control flags, and libraries by tags.
+
+ * ocamlbuild.ml: In the _tags file you can add or remove flags
+ using a colon flag_name:flag_value.
+ * test/test2/vivi.ml,
+ * test/test3/f.ml,
+ * test/test4/b/bb.ml: Dummy updates.
+ * test/test3/_tags: New.
+ * test/test4/_tags: New.
+
+2006-10-15 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add a tag based flag system.
+
+ * test/test2/vivi.ml: An example.
+ * test/test2/_tags: New.
+ * ocamlbuild.ml: Now a command can request for flags by giving a
+ set of tags these tags include file specific tags this allow to
+ tweak flags by just providing a _tags file.
+
+2006-10-15 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add -lib,-libs options remove -P.
+
+ * ocamlbuild.ml: -P Is useless due to the fact that we now
+ have the same directory structure in the _build directory.
+ Add -lib,-libs that allows one to specify -lib unix without
+ its extension in order to request for native and byte
+ compilations.
+
+2006-10-15 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Multi directories now works ;).
+
+ * ocamlbuild.ml: Solve the whole problem by improving the
+ Pathname module. Pathnames are now symbolic values that
+ can include variable names. These variable names represent
+ still ambiguous pathnames /a/b/(c|d as x1)/e.ml but variables
+ can be shared, so discovering that /a/b/(c|d as x1)/e.ml is in
+ fact /a/b/c/e.ml will make /a/b/(c|d as x1)/e.cmo automatically
+ take this value /a/b/c/e.cmo cause it shares the x1 variable.
+
+2006-10-13 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ I prefer capitalized names.
+
+ * AUTHORS
+
+2006-10-13 Berke Durak <berke.durak@inria.fr>
+
+ Added an AUTHORS file.
+
+ * AUTHORS: New.
+
+2006-10-13 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add the vcs dir.
+
+ * vcs: New.
+ * vcs/ocamlbuild.rb: New.
+
+2006-10-13 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ * ocamlbuild.ml: Restore dependencies.
+
+2006-10-13 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix the makefile.
+
+ * Makefile, discard_printf.ml: Ditto.
+
+2006-10-13 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Improve the directory handling.
+
+ * ocamlbuild.ml: Ditto, but there is still a problem with native.
+ * Makefile: Update.
+
+2006-10-11 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix native dependencies.
+
+ * ocamlbuild.ml: By default due to inlining the cmx dependencies
+ are needed to build a cmx.
+ * Makefile: Add native support.
+
+2006-10-11 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Use phony for linkdeps.
+
+ * ocamlbuild.ml: Ditto.
+
+2006-10-11 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix exit on multiple targets.
+
+ * ocamlbuild.ml: Ditto.
+
+2006-10-11 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ More flags -lflags,-lflag...
+
+ * ocamlbuild.ml: Add plrual form options for those that use
+ comma separated lists.
+
+2006-10-11 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Use phony resources for .cmo.linkdeps.
+
+ * ocamlbuild.ml: Also restore the command running if "--"
+ is specified
+
+2006-10-11 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Remove Include_string_list resources, add Phony resources.
+
+ * ocamlbuild.ml: Also fix some rules.
+
+2006-10-11 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Shift debug levels.
+
+ * ocamlbuild.ml: Add -quiet.
+
+2006-10-11 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Use str more intensively.
+
+ * ocamlbuild.ml: Also clean up useless functions.
+
+2006-10-11 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Fix link dependencies.
+
+ * ocamlbuild.ml: Force to consider recursivly Include_ tagged
+ resources for their full contents. Alas it takes more time to
+ know if we need to recompute the link.
+ * test/test2/vivi.ml: Update.
+
+2006-10-10 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Support multiple directories, it can compile the OCaml compiler :).
+
+ * ocamlbuild.ml: Add directory handling but also start
+ the tags config files handling.
+ * Makefile: Use str.cma.
+
+2006-10-08 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ Add library support.
+
+ * ocamlbuild.ml: Deduce basic set of tags form the target
+ extension.
+
+2006-10-08 Nicolas Pouillard <nicolas.pouillard@gmail.com>
+
+ More customisable flags, and cycle detection.
+
+ * ocamlbuild.ml: Add some flags -lflag, -ppflag, -cflag, --.
+ Also add a detection mechanism for dependencies.
+ * discard_printf.ml, Makefile: Update.
+
diff --git a/ocamlbuild/Makefile b/ocamlbuild/Makefile
new file mode 100644
index 0000000000..34bd5dc95e
--- /dev/null
+++ b/ocamlbuild/Makefile
@@ -0,0 +1,95 @@
+.PHONY: all byte native profile debug ppcache doc
+
+ifndef INSTALL_PREFIX
+INSTALL_PREFIX := /usr/local
+endif
+
+ifndef INSTALL_LIB
+INSTALL_LIB := $(INSTALL_PREFIX)/lib/ocamlbuild
+endif
+
+ifndef INSTALL_BIN
+INSTALL_BIN := $(INSTALL_PREFIX)/bin
+endif
+
+ifndef BUILDDIR
+BUILDDIR := "_build"
+endif
+
+ifndef OCAMLBUILDCMD
+OCAMLBUILDCMD := ./boot/ocamlbuild
+endif
+
+ifdef O
+OCAMLBUILD_OPTIONS := $(OCAMLBUILD_OPTIONS) $(O)
+endif
+
+ifeq ($(wildcard ./boot/oc*build),./boot/ocamlbuild)
+OCAMLBUILD=INSTALL_LIB=$(INSTALL_LIB) $(OCAMLBUILDCMD) -build-dir $(BUILDDIR) -no-links $(OCAMLBUILD_OPTIONS)
+LIBS=ocamlbuildlib ocamlbuildlightlib
+PROGRAMS=ocamlbuild ocamlbuildlight
+BYTE=$(LIBS:=.cma) $(PROGRAMS:=.byte)
+NATIVE=$(LIBS:=.cmxa) $(PROGRAMS:=.native)
+
+all:
+ $(OCAMLBUILD) $(BYTE) $(NATIVE)
+byte:
+ $(OCAMLBUILD) $(BYTE)
+profile:
+ $(OCAMLBUILD) $(LIBS:=.p.cmxa) $(PROGRAMS:=.p.native)
+debug:
+ $(OCAMLBUILD) $(LIBS:=.d.cma) $(PROGRAMS:=.d.byte)
+ppcache:
+ $(OCAMLBUILD) ppcache.byte ppcache.native
+doc:
+ $(OCAMLBUILD) ocamlbuild.docdir/index.html
+ ln -sf $(BUILDDIR)/ocamlbuild.docdir doc
+else
+all byte native: ocamlbuild.byte.start
+ cp ocamlbuild.byte.start boot/ocamlbuild
+ $(MAKE) $(MFLAGS) $(MAKECMDGOALS)
+ cp $(BUILDDIR)/ocamlbuild.native boot/ocamlbuild
+ $(MAKE) $(MFLAGS) $(MAKECMDGOALS) OCAMLBUILD_OPTIONS="-nothing-should-be-rebuilt -debug -1"
+endif
+
+ocamlbuild.byte.start:
+ ./start.sh
+
+promote:
+ cp $(BUILDDIR)/ocamlbuild.native boot/ocamlbuild
+
+clean:
+ rm -rf $(BUILDDIR)
+
+distclean: clean
+ rm -rf _start ocamlbuild.byte.start boot/ocamlbuild
+
+install: all
+ mkdir -p $(INSTALL_BIN)
+ mkdir -p $(INSTALL_LIB)
+ install $(BUILDDIR)/ocamlbuild.byte \
+ $(BUILDDIR)/ocamlbuild.native \
+ $(BUILDDIR)/ocamlbuildlight.byte \
+ $(BUILDDIR)/ocamlbuildlight.native \
+ $(INSTALL_BIN)
+ install $(BUILDDIR)/ocamlbuild.native $(INSTALL_BIN)/ocamlbuild
+ install $(BUILDDIR)/ocamlbuildlight.byte $(INSTALL_BIN)/ocamlbuildlight
+ install -m 644 \
+ $(BUILDDIR)/ocamlbuildlib.cmxa \
+ $(BUILDDIR)/ocamlbuildlib.a \
+ $(BUILDDIR)/ocamlbuildlib.cma \
+ $(BUILDDIR)/ocamlbuildlightlib.cmxa \
+ $(BUILDDIR)/ocamlbuildlightlib.a \
+ $(BUILDDIR)/ocamlbuildlightlib.cma \
+ $(BUILDDIR)/ocamlbuild_pack.cmi \
+ $(BUILDDIR)/ocamlbuild_pack.cmx \
+ $(BUILDDIR)/ocamlbuild.cmi \
+ $(BUILDDIR)/ocamlbuild_plugin.cmi \
+ $(BUILDDIR)/ocamlbuild.cmx \
+ $(BUILDDIR)/ocamlbuild.o \
+ $(BUILDDIR)/ocamlbuild.cmo \
+ $(BUILDDIR)/ocamlbuildlight.cmx \
+ $(BUILDDIR)/ocamlbuildlight.o \
+ $(BUILDDIR)/ocamlbuildlight.cmo $(INSTALL_LIB)
+ ranlib $(INSTALL_LIB)/ocamlbuildlib.a
+ ranlib $(INSTALL_LIB)/ocamlbuildlightlib.a
diff --git a/ocamlbuild/TODO b/ocamlbuild/TODO
new file mode 100644
index 0000000000..f48333c002
--- /dev/null
+++ b/ocamlbuild/TODO
@@ -0,0 +1,30 @@
+To do:
+* Ensure that _build and _log are not created if not needed (with -help for
+ instance)
+* Fix report
+* Design a nice, friendly, future-proof plugin (myocamlbuild) API
+* Display: should display nothing (even when finish is called) when no real
+ event as occured.
+
+Being done:
+* Write doc
+
+Almost done:
+* Fine control for hygiene using a glob pattern (command line option + tag)
+ => the command line option is todo.
+ -tag "<glob1> or <glob2> ..." "tag1, -tag2, ..."
+
+Won't fix:
+* Config file for options => no since myocamlbuild is sufficent
+* Optimize MD5 (Daemon ? Dnotify ?) : too much hassle for little gain
+
+Done:
+* Fix uncaught exception handler to play well with the Display module
+* Finish display before executing target
+* Slurp: in a directory read files, before subdirs (to have _tags before foo/_tags)
+* Add a -clean option
+* Add ocamldoc rules (use .odoc extension)
+* Add .inferred.mli target rules
+* -- with no args does not call the executable
+* Complain when used with -- and no target
+* dep ["ocaml"; "link"; "use_foo"] ["foo/foo.o"] tags for adding targets
diff --git a/ocamlbuild/_tags b/ocamlbuild/_tags
new file mode 100644
index 0000000000..8a42d27ecb
--- /dev/null
+++ b/ocamlbuild/_tags
@@ -0,0 +1,12 @@
+# OCamlbuild tags file
+<*.ml> or <*.mli>: warn_A, warn_error_A, dtypes
+"discard_printf.ml": rectypes
+"ocamlbuildlib.cma" or "ocamlbuildlightlib.cma": linkall
+<*.byte> or <*.native>: use_unix
+"ocamlbuildlight.byte": -use_unix
+<*.cmx>: for-pack(Ocamlbuild_pack)
+<{ocamlbuild_{pack,plugin},my_unix_with_unix,ppcache,executor}{,.p}.cmx>: -for-pack(Ocamlbuild_pack)
+"lexers.ml" or "glob_lexer.ml": -warn_A, -warn_error_A
+"glob.ml": -warn_E, -warn_error_E, -warn_A, -warn_error_A
+"doc": not_hygienic
+"resource.ml": warn_error_e
diff --git a/ocamlbuild/bool.ml b/ocamlbuild/bool.ml
new file mode 100644
index 0000000000..4fa734e921
--- /dev/null
+++ b/ocamlbuild/bool.ml
@@ -0,0 +1,38 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Bool *)
+
+type 'a boolean = And of 'a boolean list | Or of 'a boolean list | Not of 'a boolean | Atom of 'a | True | False;;
+
+let rec eval f = function
+ | And l -> List.for_all (eval f) l
+ | Or l -> List.exists (eval f) l
+ | Not x -> not (eval f x)
+ | Atom a -> f a
+ | True -> true
+ | False -> false
+;;
+let rec iter f = function
+ | (And l|Or l) -> List.iter (iter f) l
+ | Not x -> iter f x
+ | Atom a -> f a
+ | True|False -> ()
+;;
+let rec map f = function
+ | And l -> And(List.map (map f) l)
+ | Or l -> Or(List.map (map f) l)
+ | Not x -> Not(map f x)
+ | Atom a -> Atom(f a)
+ | (True|False) as b -> b
+;;
diff --git a/ocamlbuild/bool.mli b/ocamlbuild/bool.mli
new file mode 100644
index 0000000000..4b3ea3f669
--- /dev/null
+++ b/ocamlbuild/bool.mli
@@ -0,0 +1,34 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Bool *)
+
+(** Provides a datatype for representing boolean formulas and evaluation,
+ iteration and map functions. *)
+
+(** Public type for generic boolean formulas. An empty conjunction [And[]] is true and
+ an empty disjunction [Or[]] is false. *)
+type 'a boolean =
+ And of 'a boolean list
+ | Or of 'a boolean list
+ | Not of 'a boolean
+ | Atom of 'a
+ | True
+ | False
+
+val eval : ('a -> bool) -> 'a boolean -> bool
+(** [eval g f] evaluates the boolean formula [f] using the values returned by [g] for the atoms. *)
+val iter : ('a -> unit) -> 'a boolean -> unit
+(** [iter g f] calls [g] over every atom of [f]. *)
+val map : ('a -> 'b) -> 'a boolean -> 'b boolean
+(** [map g f] replaces every atom of [f] by its image by [g]. *)
diff --git a/ocamlbuild/command.ml b/ocamlbuild/command.ml
new file mode 100644
index 0000000000..593b1f8d08
--- /dev/null
+++ b/ocamlbuild/command.ml
@@ -0,0 +1,295 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* Command *)
+
+open My_std
+open Log
+
+type tags = Tags.t
+
+let jobs = ref 1
+
+type t =
+| Seq of t list
+| Cmd of spec
+| Nop
+and spec =
+| N (* nop or nil *)
+| S of spec list
+| A of string
+| P of string (* Pathname.t *)
+| Px of string (* Pathname.t *)
+| Sh of string
+| T of Tags.t
+| V of string
+| Quote of spec
+
+(*type v = [ `Seq of v list | `Cmd of vspec | `Nop ]
+and vspec =
+ [ `N
+ | `S of vspec list
+ | `A of string
+ | `P of string (* Pathname.t *)
+ | `Px of string (* Pathname.t *)
+ | `Sh of string
+ | `Quote of vspec ]
+
+let rec spec_of_vspec =
+ function
+ | `N -> N
+ | `S vspecs -> S (List.map spec_of_vspec vspecs)
+ | `A s -> A s
+ | `P s -> P s
+ | `Px s -> Px s
+ | `Sh s -> Sh s
+ | `Quote vspec -> Quote (spec_of_vspec vspec)
+
+let rec vspec_of_spec =
+ function
+ | N -> `N
+ | S specs -> `S (List.map vspec_of_spec specs)
+ | A s -> `A s
+ | P s -> `P s
+ | Px s -> `Px s
+ | Sh s -> `Sh s
+ | T _ -> invalid_arg "vspec_of_spec: T not supported"
+ | Quote spec -> `Quote (vspec_of_spec spec)
+
+let rec t_of_v =
+ function
+ | `Nop -> Nop
+ | `Cmd vspec -> Cmd (spec_of_vspec vspec)
+ | `Seq cmds -> Seq (List.map t_of_v cmds)
+
+let rec v_of_t =
+ function
+ | Nop -> `Nop
+ | Cmd spec -> `Cmd (vspec_of_spec spec)
+ | Seq cmds -> `Seq (List.map v_of_t cmds)*)
+
+let no_tag_handler _ = failwith "no_tag_handler"
+
+let tag_handler = ref no_tag_handler
+
+(*** atomize *)
+let atomize l = S(List.map (fun x -> A x) l)
+let atomize_paths l = S(List.map (fun x -> P x) l)
+(* ***)
+
+let env_path = lazy begin
+ let path_var = Sys.getenv "PATH" in
+ Lexers.colon_sep_strings (Lexing.from_string path_var)
+end
+
+let virtual_solvers = Hashtbl.create 32
+let setup_virtual_command_solver virtual_command solver =
+ Hashtbl.replace virtual_solvers virtual_command solver
+let virtual_solver virtual_command =
+ let solver =
+ try
+ Hashtbl.find virtual_solvers virtual_command
+ with Not_found ->
+ failwith (sbprintf "no solver for the virtual command %S \
+ (setup one with Command.setup_virtual_command_solver)"
+ virtual_command)
+ in
+ try solver ()
+ with Not_found ->
+ failwith (Printf.sprintf "the solver for the virtual command %S \
+ has failed finding a valid command" virtual_command)
+
+
+(* FIXME windows *)
+let search_in_path cmd =
+ if Filename.is_implicit cmd then
+ let path = List.find begin fun path ->
+ if path = Filename.current_dir_name then sys_file_exists cmd
+ else sys_file_exists (filename_concat path cmd)
+ end !*env_path in
+ filename_concat path cmd
+ else cmd
+
+(*** string_of_command_spec{,_with_calls *)
+let rec string_of_command_spec_with_calls call_with_tags call_with_target resolve_virtuals spec =
+ let self = string_of_command_spec_with_calls call_with_tags call_with_target resolve_virtuals in
+ let b = Buffer.create 256 in
+ let first = ref true in
+ let put_space () =
+ if !first then
+ first := false
+ else
+ Buffer.add_char b ' '
+ in
+ let put_filename p =
+ Buffer.add_string b (Shell.quote_filename_if_needed p)
+ in
+ let rec do_spec = function
+ | N -> ()
+ | A u -> put_space (); put_filename u
+ | Sh u -> put_space (); Buffer.add_string b u
+ | P p -> put_space (); put_filename p
+ | Px u -> put_space (); put_filename u; call_with_target u
+ | V v -> if resolve_virtuals then do_spec (virtual_solver v)
+ else (put_space (); Printf.bprintf b "<virtual %s>" (Shell.quote_filename_if_needed v))
+ | S l -> List.iter do_spec l
+ | T tags -> call_with_tags tags; do_spec (!tag_handler tags)
+ | Quote s -> put_space (); put_filename (self s)
+ in
+ do_spec spec;
+ Buffer.contents b
+
+let string_of_command_spec x = string_of_command_spec_with_calls ignore ignore false x
+
+let string_print_of_command_spec spec =
+ let rtags = ref Tags.empty in
+ let rtarget = ref "" in
+ let s = string_of_command_spec_with_calls ((:=) rtags) ((:=) rtarget) true spec in
+ let target = if !rtarget = "" then s else !rtarget in
+ (s, (fun quiet pretend () -> if not quiet then Log.event ~pretend s target !rtags))
+(* ***)
+
+let rec print f =
+ function
+ | Cmd spec -> Format.pp_print_string f (string_of_command_spec spec)
+ | Seq seq -> List.print print f seq
+ | Nop -> Format.pp_print_string f "nop"
+
+let to_string x = sbprintf "%a" print x
+
+let rec list_rev_iter f =
+ function
+ | [] -> ()
+ | x :: xs -> list_rev_iter f xs; f x
+
+let spec_list_of_cmd cmd =
+ let rec loop acc =
+ function
+ | [] -> acc
+ | Nop :: xs -> loop acc xs
+ | Cmd spec :: xs -> loop (string_print_of_command_spec spec :: acc) xs
+ | Seq l :: xs -> loop (loop acc l) xs
+ in List.rev (loop [] [cmd])
+
+let execute_many ?(quiet=false) ?(pretend=false) cmds =
+ let degraded = !*My_unix.is_degraded || Sys.os_type = "Win32" in
+ let jobs = !jobs in
+ if jobs < 0 then invalid_arg "jobs < 0";
+ let max_jobs = if jobs = 0 then None else Some jobs in
+
+ let ticker = Log.update in
+ let display = Log.display in
+
+ if cmds = [] then
+ None
+ else
+ begin
+ let konts =
+ List.map
+ begin fun cmd ->
+ let specs = spec_list_of_cmd cmd in
+ List.map
+ begin fun (cmd, print) ->
+ (cmd, (print quiet pretend))
+ end
+ specs
+ end
+ cmds
+ in
+ if pretend then
+ begin
+ List.iter
+ begin fun l ->
+ List.iter
+ begin fun (_, f) -> f () end
+ l
+ end
+ konts;
+ None
+ end
+ else
+ begin
+ reset_filesys_cache ();
+ if degraded then
+ let res, opt_exn =
+ List.fold_left begin fun (acc_res, acc_exn) cmds ->
+ match acc_exn with
+ | None ->
+ begin try
+ List.iter begin fun (cmd, print) ->
+ print ();
+ let rc = sys_command cmd in
+ if rc <> 0 then begin
+ if not quiet then
+ eprintf "Exit code %d while executing this \
+ command:@\n%s" rc cmd;
+ raise (Exit_with_code rc)
+ end
+ end cmds;
+ true :: acc_res, None
+ with e -> false :: acc_res, Some e
+ end
+ | Some _ -> false :: acc_res, acc_exn
+ end ([], None) konts
+ in match opt_exn with
+ | Some(exn) -> Some(res, exn)
+ | None -> None
+ else
+ My_unix.execute_many ~ticker ?max_jobs ~display konts
+ end
+ end
+;;
+
+let execute ?quiet ?pretend cmd =
+ match execute_many ?quiet ?pretend [cmd] with
+ | Some(_, exn) -> raise exn
+ | _ -> ()
+
+let rec reduce x =
+ let rec self x acc =
+ match x with
+ | N -> acc
+ | A _ | Sh _ | P _ | Px _ | V _ -> x :: acc
+ | S l -> List.fold_right self l acc
+ | T tags -> self (!tag_handler tags) acc
+ | Quote s -> Quote (reduce s) :: acc in
+ match self x [] with
+ | [] -> N
+ | [x] -> x
+ | xs -> S xs
+
+let to_string_for_digest = to_string
+(*
+let to_string_for_digest x =
+ let rec cmd_of_spec =
+ function
+ | [] -> None
+ | N :: xs -> cmd_of_spec xs
+ | (A x | P x | P x) :: _ -> Some x
+ | Sh x :: _ ->
+ if Shell.is_simple_filename x then Some x
+ else None (* Sh"ocamlfind ocamlc" for example will not be digested. *)
+ | S specs1 :: specs2 -> cmd_of_spec (specs1 @ specs2)
+ | (T _ | Quote _) :: _ -> assert false in
+ let rec cmd_of_cmds =
+ function
+ | Nop | Seq [] -> None
+ | Cmd spec -> cmd_of_spec [spec]
+ | Seq (cmd :: _) -> cmd_of_cmds cmd in
+ let s = to_string x in
+ match cmd_of_cmds x with
+ | Some x ->
+ if sys_file_exists x then sprintf "(%S,%S)" s (Digest.file x)
+ else s
+ | None -> s
+*)
diff --git a/ocamlbuild/command.mli b/ocamlbuild/command.mli
new file mode 100644
index 0000000000..5ad5302dd4
--- /dev/null
+++ b/ocamlbuild/command.mli
@@ -0,0 +1,30 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* Command *)
+
+(** Provides an abstract type for easily building complex shell commands without making
+ quotation mistakes. *)
+include Signatures.COMMAND with type tags = Tags.t
+
+(** {6 For system use only, not for the casual user} *)
+
+(** Same as [to_string]. *)
+val to_string_for_digest : t -> string
+
+(** Maximum number of parallel jobs. *)
+val jobs : int ref
+
+(** Hook here the function that maps a set of tags to appropriate command
+ options. It also build the dependencies that matches the tags. *)
+val tag_handler : (Tags.t -> spec) ref
diff --git a/ocamlbuild/configuration.ml b/ocamlbuild/configuration.ml
new file mode 100644
index 0000000000..6f1a7f3a5c
--- /dev/null
+++ b/ocamlbuild/configuration.ml
@@ -0,0 +1,63 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Log
+open Lexers
+
+type flag_list = (string * string) list
+
+type t = Lexers.conf
+
+let cache = Hashtbl.create 107
+let (configs, add_config) =
+ let configs = ref [] in
+ (fun () -> !configs),
+ (fun config -> configs := config :: !configs; Hashtbl.clear cache)
+
+let parse_string s =
+ let conf = Lexers.conf_lines None 1 (Printf.sprintf "string: %S" s) (Lexing.from_string s) in
+ add_config conf
+
+let parse_file ?dir file =
+ with_input_file file begin fun ic ->
+ let conf = Lexers.conf_lines dir 1 (Printf.sprintf "file: %S" file) (Lexing.from_channel ic) in
+ add_config conf
+ end
+
+let key_match = Glob.eval
+
+let apply_config s (config : t) init =
+ List.fold_left begin fun (tags, flags as acc) (key, v) ->
+ if key_match key s then
+ (List.fold_right Tags.add v.plus_tags (List.fold_right Tags.remove v.minus_tags tags),
+ List.fold_right Flags.add v.plus_flags (List.fold_right Flags.remove v.minus_flags flags))
+ else acc
+ end init config
+
+let apply_configs s =
+ let (tags, flags) =
+ List.fold_right (apply_config s) (configs ()) (Tags.empty, [])
+ in (tags, Flags.to_spec flags)
+
+let tags_and_flags_of_filename s =
+ try Hashtbl.find cache s
+ with Not_found ->
+ let res = apply_configs s in
+ let () = Hashtbl.replace cache s res in
+ res
+
+let tags_of_filename x = fst (tags_and_flags_of_filename x)
+let flags_of_filename x = snd (tags_and_flags_of_filename x)
+
+let has_tag tag = Tags.mem tag (tags_of_filename "")
diff --git a/ocamlbuild/configuration.mli b/ocamlbuild/configuration.mli
new file mode 100644
index 0000000000..a8578bf768
--- /dev/null
+++ b/ocamlbuild/configuration.mli
@@ -0,0 +1,34 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* Configuration *)
+
+(** Handles the "_tags" file mechanism. *)
+
+type flag_list = (string * string) list
+
+(** Incorporate a newline-separated configuration string into the current configuration.
+ Will usually raising an [Invalid_arg] with an appropriately explicit message in case of error. *)
+val parse_string : string -> unit
+
+(** [parse_file ?dir fn] incorporates the configuration file named [fn], prefixing its glob patterns
+ with [dir] if given. *)
+val parse_file : ?dir:string -> string -> unit
+
+(** Return the set of tags that apply to a given filename under the current configuration. *)
+val tags_of_filename : string -> Tags.t
+
+(** Return the set of flags that apply to a given filename under the current configuration. *)
+val flags_of_filename : string -> Command.spec
+
+val has_tag : string -> bool
diff --git a/ocamlbuild/discard_printf.ml b/ocamlbuild/discard_printf.ml
new file mode 100644
index 0000000000..d77ecd3ddb
--- /dev/null
+++ b/ocamlbuild/discard_printf.ml
@@ -0,0 +1,16 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+let rec greedy _ = greedy
+
+let discard_printf _fmt = Obj.magic greedy
diff --git a/ocamlbuild/discard_printf.mli b/ocamlbuild/discard_printf.mli
new file mode 100644
index 0000000000..363e33d773
--- /dev/null
+++ b/ocamlbuild/discard_printf.mli
@@ -0,0 +1,19 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* Discard_printf *)
+
+(** This module compiled with [-rectypes] allows one to write functions
+ taking formatters as arguments. *)
+open Format
+val discard_printf: ('a, formatter, unit) format -> 'a
diff --git a/ocamlbuild/display.ml b/ocamlbuild/display.ml
new file mode 100644
index 0000000000..b1f13ee393
--- /dev/null
+++ b/ocamlbuild/display.ml
@@ -0,0 +1,385 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Display *)
+open My_std;;
+
+open My_unix;;
+
+let fp = Printf.fprintf;;
+
+(*** ANSI *)
+module ANSI =
+ struct
+ let up oc n = fp oc "\027[%dA" n;;
+ let clear_to_eol oc () = fp oc "\027[K";;
+ let bol oc () = fp oc "\r";;
+ let get_columns () =
+ try
+ int_of_string (String.chomp (My_unix.run_and_read "tput cols"))
+ with
+ | Failure _ -> 80
+ end
+;;
+(* ***)
+(*** tagline_description *)
+type tagline_description = (string * char) list;;
+(* ***)
+(*** sophisticated_display *)
+type sophisticated_display = {
+ ds_channel : out_channel; (** Channel for writing *)
+ ds_start_time : float; (** When was compilation started *)
+ mutable ds_last_update : float; (** When was the display last updated *)
+ mutable ds_last_target : string; (** Last target built *)
+ mutable ds_last_cached : bool; (** Was the last target cached or really built ? *)
+ mutable ds_last_tags : Tags.t; (** Tags of the last command *)
+ mutable ds_changed : bool; (** Does the tag line need recomputing ? *)
+ ds_update_interval : float; (** Minimum interval between updates *)
+ ds_columns : int; (** Number of columns in dssplay *)
+ mutable ds_jobs : int; (** Number of jobs launched or cached *)
+ mutable ds_jobs_cached : int; (** Number of jobs cached *)
+ ds_tagline : string; (** Current tagline *)
+ mutable ds_seen_tags : Tags.t; (** Tags that we have encountered *)
+ ds_pathname_length : int; (** How much space for displaying pathnames ? *)
+ ds_tld : tagline_description; (** Description for the tagline *)
+};;
+(* ***)
+(*** display_line, display *)
+type display_line =
+| Classic
+| Sophisticated of sophisticated_display
+
+type display = {
+ di_log_level : int;
+ di_log_channel : (Format.formatter * out_channel) option;
+ di_channel : out_channel;
+ di_formatter : Format.formatter;
+ di_display_line : display_line;
+ mutable di_finished : bool;
+}
+;;
+(* ***)
+(*** various defaults *)
+let default_update_interval = 0.05;;
+let default_tagline_description = [
+ "ocaml", 'O';
+ "native", 'N';
+ "byte", 'B';
+ "program", 'P';
+ "pp", 'R';
+ "debug", 'D';
+ "interf", 'I';
+ "link", 'L';
+];;
+
+(* NOT including spaces *)
+let countdown_chars = 8;;
+let jobs_chars = 3;;
+let jobs_cached_chars = 5;;
+let dots = "...";;
+let start_target = "STARTING";;
+let finish_target = "FINISHED";;
+let ticker_chars = 3;;
+let ticker_period = 0.25;;
+let ticker_animation = [|
+ "\\";
+ "|";
+ "/";
+ "-";
+|];;
+let cached = "*";;
+let uncached = " ";;
+let cache_chars = 1;;
+(* ***)
+(*** create_tagline *)
+let create_tagline description = String.make (List.length description) '-';;
+(* ***)
+(*** create *)
+let create
+ ?(channel=stdout)
+ ?(mode:[`Classic|`Sophisticated] = `Sophisticated)
+ ?columns:(_columns=75)
+ ?(description = default_tagline_description)
+ ?log_file
+ ?(log_level=1)
+ ()
+ =
+ let log_channel =
+ match log_file with
+ | None -> None
+ | Some fn ->
+ let oc = open_out_gen [Open_text; Open_wronly; Open_creat; Open_trunc] 0o644 fn in
+ let f = Format.formatter_of_out_channel oc in
+ Format.fprintf f "*** Starting build.\n";
+ Some (f, oc)
+ in
+
+ let display_line =
+ match mode with
+ | `Classic -> Classic
+ | `Sophisticated ->
+ (* We assume Unix is not degraded. *)
+ let n = ANSI.get_columns () in
+ let tag_chars = List.length description in
+ Sophisticated
+ { ds_channel = stdout;
+ ds_start_time = gettimeofday ();
+ ds_last_update = 0.0;
+ ds_last_target = start_target;
+ ds_last_tags = Tags.empty;
+ ds_last_cached = false;
+ ds_changed = false;
+ ds_update_interval = default_update_interval;
+ ds_columns = n;
+ ds_jobs = 0;
+ ds_jobs_cached = 0;
+ ds_tagline = create_tagline description;
+ ds_seen_tags = Tags.empty;
+ ds_pathname_length = n -
+ (countdown_chars + 1 + jobs_chars + 1 + jobs_cached_chars + 1 +
+ cache_chars + 1 + tag_chars + 1 + ticker_chars + 2);
+ ds_tld = description }
+ in
+ { di_log_level = log_level;
+ di_log_channel = log_channel;
+ di_channel = channel;
+ di_formatter = Format.formatter_of_out_channel channel;
+ di_display_line = display_line;
+ di_finished = false }
+;;
+(* ***)
+(*** print_time *)
+let print_time oc t =
+ let t = int_of_float t in
+ let s = t mod 60 in
+ let m = (t / 60) mod 60 in
+ let h = t / 3600 in
+ fp oc "%02d:%02d:%02d" h m s
+;;
+(* ***)
+(*** print_shortened_pathname *)
+let print_shortened_pathname length oc u =
+ assert(length >= 3);
+ let m = String.length u in
+ if m <= length then
+ begin
+ output_string oc u;
+ fp oc "%*s" (length - m) ""
+ end
+ else
+ begin
+ let n = String.length dots in
+ let k = length - n in
+ output_string oc dots;
+ output oc u (m - k) k;
+ end
+(* ***)
+(*** Layout
+
+00000000001111111111222222222233333333334444444444555555555566666666667777777777
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+HH MM SS XXXX PATHNAME
+00:12:31 32 ( 26) ...lp4Filters/Camlp4LocationStripper.cmo * OBn-------------
+| | | | | \ tags
+| | | \ last target built \ cached ?
+| | |
+| | \ number of jobs cached
+| \ number of jobs
+\ elapsed time
+cmo mllib
+***)
+(*** redraw_sophisticated *)
+let redraw_sophisticated ds =
+ let t = gettimeofday () in
+ let oc = ds.ds_channel in
+ let dt = t -. ds.ds_start_time in
+ ds.ds_last_update <- t;
+ fp oc "%a" ANSI.bol ();
+ let ticker_phase = (abs (int_of_float (ceil (dt /. ticker_period)))) mod (Array.length ticker_animation) in
+ let ticker = ticker_animation.(ticker_phase) in
+ fp oc "%a %-4d (%-4d) %a %s %s %s"
+ print_time dt
+ ds.ds_jobs
+ ds.ds_jobs_cached
+ (print_shortened_pathname ds.ds_pathname_length) ds.ds_last_target
+ (if ds.ds_last_cached then cached else uncached)
+ ds.ds_tagline
+ ticker;
+ fp oc "%a%!" ANSI.clear_to_eol ()
+;;
+(* ***)
+(*** redraw *)
+let redraw = function
+ | Classic -> ()
+ | Sophisticated ds -> redraw_sophisticated ds
+;;
+(* ***)
+(*** finish_sophisticated *)
+let finish_sophisticated ?(how=`Success) ds =
+ let t = gettimeofday () in
+ let oc = ds.ds_channel in
+ let dt = t -. ds.ds_start_time in
+ match how with
+ | `Success|`Error ->
+ fp oc "%a" ANSI.bol ();
+ fp oc "%s %d target%s (%d cached) in %a."
+ (if how = `Error then
+ "Compilation unsuccessful after building"
+ else
+ "Finished,")
+ ds.ds_jobs
+ (if ds.ds_jobs = 1 then "" else "s")
+ ds.ds_jobs_cached
+ print_time dt;
+ fp oc "%a\n%!" ANSI.clear_to_eol ()
+ | `Quiet ->
+ fp oc "%a%a%!" ANSI.bol () ANSI.clear_to_eol ();
+;;
+(* ***)
+(*** sophisticated_display *)
+let sophisticated_display ds f =
+ fp ds.ds_channel "%a%a%!" ANSI.bol () ANSI.clear_to_eol ();
+ f ds.ds_channel
+;;
+(* ***)
+(*** call_if *)
+let call_if log_channel f =
+ match log_channel with
+ | None -> ()
+ | Some x -> f x
+;;
+(* ***)
+(*** display *)
+let display di f =
+ call_if di.di_log_channel (fun (_, oc) -> f oc);
+ match di.di_display_line with
+ | Classic -> f di.di_channel
+ | Sophisticated ds -> sophisticated_display ds f
+;;
+(* ***)
+(*** finish *)
+let finish ?(how=`Success) di =
+ if not di.di_finished then begin
+ di.di_finished <- true;
+ call_if di.di_log_channel
+ begin fun (fmt, oc) ->
+ Format.fprintf fmt "# Compilation %ssuccessful.@." (if how = `Error then "un" else "");
+ close_out oc
+ end;
+ match di.di_display_line with
+ | Classic -> ()
+ | Sophisticated ds -> finish_sophisticated ~how ds
+ end
+;;
+(* ***)
+(*** update_tagline_from_tags *)
+let update_tagline_from_tags ds =
+ let tagline = ds.ds_tagline in
+ let tags = ds.ds_last_tags in
+ let rec loop i = function
+ | [] ->
+ for j = i to String.length tagline - 1 do
+ tagline.[j] <- '-'
+ done
+ | (tag, c) :: rest ->
+ if Tags.mem tag tags then
+ tagline.[i] <- Char.uppercase c
+ else
+ if Tags.mem tag ds.ds_seen_tags then
+ tagline.[i] <- Char.lowercase c
+ else
+ tagline.[i] <- '-';
+ loop (i + 1) rest
+ in
+ loop 0 ds.ds_tld;
+;;
+(* ***)
+(*** update_sophisticated *)
+let update_sophisticated ds =
+ let t = gettimeofday () in
+ let dt = t -. ds.ds_last_update in
+ if dt > ds.ds_update_interval then
+ begin
+ if ds.ds_changed then
+ begin
+ update_tagline_from_tags ds;
+ ds.ds_changed <- false
+ end;
+ redraw_sophisticated ds
+ end
+ else
+ ()
+;;
+(* ***)
+(*** set_target_sophisticated *)
+let set_target_sophisticated ds target tags cached =
+ ds.ds_changed <- true;
+ ds.ds_last_target <- target;
+ ds.ds_last_tags <- tags;
+ ds.ds_jobs <- 1 + ds.ds_jobs;
+ if cached then ds.ds_jobs_cached <- 1 + ds.ds_jobs_cached;
+ ds.ds_last_cached <- cached;
+ ds.ds_seen_tags <- Tags.union ds.ds_seen_tags ds.ds_last_tags;
+ update_sophisticated ds
+;;
+
+let print_tags f tags =
+ let first = ref true in
+ Tags.iter begin fun tag ->
+ if !first then begin
+ first := false;
+ Format.fprintf f "%s" tag
+ end else Format.fprintf f ", %s" tag
+ end tags
+;;
+(* ***)
+(*** update *)
+let update di =
+ match di.di_display_line with
+ | Classic -> ()
+ | Sophisticated ds -> update_sophisticated ds
+;;
+(* ***)
+(*** event *)
+let event di ?(pretend=false) command target tags =
+ call_if di.di_log_channel
+ (fun (fmt, _) ->
+ Format.fprintf fmt "# Target: %s, tags: { %a }\n" target print_tags tags;
+ Format.fprintf fmt "%s%s@." command (if pretend then " # cached" else ""));
+ match di.di_display_line with
+ | Classic ->
+ if pretend then
+ (if di.di_log_level >= 2 then Format.fprintf di.di_formatter "[cache hit] %s\n%!" command)
+ else
+ (if di.di_log_level >= 1 then Format.fprintf di.di_formatter "%s\n%!" command)
+ | Sophisticated ds ->
+ set_target_sophisticated ds target tags pretend;
+ update_sophisticated ds
+;;
+(* ***)
+(*** dprintf *)
+let dprintf ?(log_level=1) di fmt =
+ if log_level > di.di_log_level then Discard_printf.discard_printf fmt else
+ match di.di_display_line with
+ | Classic -> Format.fprintf di.di_formatter fmt
+ | Sophisticated _ ->
+ if log_level < 0 then
+ begin
+ display di ignore;
+ Format.fprintf di.di_formatter fmt
+ end
+ else
+ match di.di_log_channel with
+ | Some (f, _) -> Format.fprintf f fmt
+ | None -> Discard_printf.discard_printf fmt
+(* ***)
diff --git a/ocamlbuild/display.mli b/ocamlbuild/display.mli
new file mode 100644
index 0000000000..d184774b7a
--- /dev/null
+++ b/ocamlbuild/display.mli
@@ -0,0 +1,33 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Display *)
+
+type display
+type tagline_description = (string * char) list
+
+val create :
+ ?channel:out_channel ->
+ ?mode:[ `Classic | `Sophisticated ] ->
+ ?columns:int ->
+ ?description:tagline_description ->
+ ?log_file:string ->
+ ?log_level:int ->
+ unit ->
+ display
+
+val finish : ?how:[`Success|`Error|`Quiet] -> display -> unit
+val event : display -> ?pretend:bool -> string -> string -> Tags.t -> unit
+val display : display -> (out_channel -> unit) -> unit
+val update : display -> unit
+val dprintf : ?log_level:int -> display -> ('a, Format.formatter, unit) format -> 'a
diff --git a/ocamlbuild/examples/example1/hello.ml b/ocamlbuild/examples/example1/hello.ml
new file mode 100644
index 0000000000..c85cb66b87
--- /dev/null
+++ b/ocamlbuild/examples/example1/hello.ml
@@ -0,0 +1,5 @@
+let _ =
+ Printf.printf "Hello, %s ! My name is %s\n"
+ (if Array.length Sys.argv > 1 then Sys.argv.(1) else "stranger")
+ Sys.argv.(0)
+;;
diff --git a/ocamlbuild/examples/example2/greet.ml b/ocamlbuild/examples/example2/greet.ml
new file mode 100644
index 0000000000..ec8088916e
--- /dev/null
+++ b/ocamlbuild/examples/example2/greet.ml
@@ -0,0 +1,6 @@
+type how = Nicely | Badly;;
+
+let greet how who =
+ match how with Nicely -> Printf.printf "Hello, %s !\n" who
+ | Badly -> Printf.printf "Oh, here is that %s again.\n" who
+;;
diff --git a/ocamlbuild/examples/example2/hello.ml b/ocamlbuild/examples/example2/hello.ml
new file mode 100644
index 0000000000..b48806a3db
--- /dev/null
+++ b/ocamlbuild/examples/example2/hello.ml
@@ -0,0 +1,14 @@
+open Greet
+
+let _ =
+ let name =
+ if Array.length Sys.argv > 1 then
+ Sys.argv.(1)
+ else
+ "stranger"
+ in
+ greet
+ (if name = "Caesar" then Nicely else Badly)
+ name;
+ Printf.printf "My name is %s\n" Sys.argv.(0)
+;;
diff --git a/ocamlbuild/examples/example3/epoch.ml b/ocamlbuild/examples/example3/epoch.ml
new file mode 100644
index 0000000000..ad95a0394f
--- /dev/null
+++ b/ocamlbuild/examples/example3/epoch.ml
@@ -0,0 +1,6 @@
+let _ =
+ let s = Num.num_of_string (Printf.sprintf "%.0f" (Unix.gettimeofday ())) in
+ let ps = Num.mult_num (Num.num_of_string "1000000000000") s in
+ Printf.printf "%s picoseconds have passed since January 1st, 1970.\n"
+ (Num.string_of_num ps)
+;;
diff --git a/ocamlbuild/examples/example3/make.sh b/ocamlbuild/examples/example3/make.sh
new file mode 100755
index 0000000000..3588a713fc
--- /dev/null
+++ b/ocamlbuild/examples/example3/make.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+set -e
+
+TARGET=epoch
+FLAGS="-libs unix,nums"
+OCAMLBUILD=ocamlbuild
+
+ocb()
+{
+ $OCAMLBUILD $FLAGS $*
+}
+
+rule() {
+ case $1 in
+ clean) ocb -clean;;
+ native) ocb $TARGET.native;;
+ byte) ocb $TARGET.byte;;
+ all) ocb $TARGET.native $TARGET.byte;;
+ depend) echo "Not needed.";;
+ *) echo "Unknown action $1";;
+ esac;
+}
+
+if [ $# -eq 0 ]; then
+ rule all
+else
+ while [ $# -gt 0 ]; do
+ rule $1;
+ shift
+ done
+fi
diff --git a/ocamlbuild/executor.ml b/ocamlbuild/executor.ml
new file mode 100644
index 0000000000..2a05ca96b8
--- /dev/null
+++ b/ocamlbuild/executor.ml
@@ -0,0 +1,315 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Executor *)
+
+open Unix;;
+
+module Exit_codes = struct
+ let rc_subcommand_failed = 10
+ let rc_subcommand_got_signal = 11
+ let rc_io_error = 12
+ let rc_exceptional_condition = 13
+end;;
+
+type task = (string * (unit -> unit));;
+
+type job = {
+ job_id : int * int;
+ job_command : string;
+ job_next : (string * (unit -> unit)) list;
+ job_result : bool ref; (* Result of this sequence group *)
+ job_stdout : in_channel;
+ job_stdin : out_channel;
+ job_stderr : in_channel;
+ job_buffer : Buffer.t;
+ mutable job_dying : bool;
+};;
+
+module JS = Set.Make(struct type t = job let compare = compare end);;
+module FDM = Map.Make(struct type t = file_descr let compare = compare end);;
+
+let sf = Printf.sprintf;;
+let fp = Printf.fprintf;;
+
+(*** print_unix_status *)
+(* FIXME never called *)
+let print_unix_status oc = function
+ | WEXITED x -> fp oc "exit %d" x
+ | WSIGNALED i -> fp oc "signal %d" i
+ | WSTOPPED i -> fp oc "stop %d" i
+;;
+(* ***)
+(*** print_job_id *)
+let print_job_id oc (x,y) = fp oc "%d.%d" x y;;
+(* ***)
+(*** output_lines *)
+let output_lines prefix oc buffer =
+ let u = Buffer.contents buffer in
+ let m = String.length u in
+ let output_line i j =
+ output_string oc prefix;
+ output oc u i (j - i);
+ output_char oc '\n'
+ in
+ let rec loop i =
+ if i = m then
+ ()
+ else
+ begin
+ try
+ let j = String.index_from u i '\n' in
+ output_line i j;
+ loop (j + 1)
+ with
+ | Not_found ->
+ output_line i m
+ end
+ in
+ loop 0
+;;
+(* ***)
+(*** execute *)
+(* XXX: Add test for non reentrancy *)
+let execute
+ ?(max_jobs=max_int)
+ ?(ticker=ignore)
+ ?(period=0.1)
+ ?(display=(fun f -> f Pervasives.stdout))
+ (commands : task list list)
+ =
+ let batch_id = ref 0 in
+ let env = environment () in
+ let jobs = ref JS.empty in
+ let jobs_active = ref 0 in
+ let jobs_to_terminate = Queue.create () in
+ let commands_to_execute = Queue.create () in
+ let all_ok = ref true in
+ let results =
+ List.map (fun tasks ->
+ let result = ref false in
+ Queue.add (tasks, result) commands_to_execute;
+ result)
+ commands
+ in
+ let outputs = ref FDM.empty in
+ let doi = descr_of_in_channel in
+ let doo = descr_of_out_channel in
+ (*** compute_fds *)
+ let compute_fds =
+ let fds = ref ([], [], []) in
+ let prev_jobs = ref JS.empty in
+ fun () ->
+ if not (!prev_jobs == !jobs) then
+ begin
+ prev_jobs := !jobs;
+ fds :=
+ JS.fold
+ begin fun job (rfds, wfds, xfds) ->
+ let ofd = doi job.job_stdout
+ and ifd = doo job.job_stdin
+ and efd = doi job.job_stderr
+ in
+ (ofd :: efd :: rfds, wfds, ofd :: ifd :: efd :: xfds)
+ end
+ !jobs
+ ([], [], [])
+ end;
+ !fds
+ in
+ (* ***)
+ (*** add_job *)
+ let add_job (cmd, action) rest result id =
+ (*display begin fun oc -> fp oc "Job %a is %s\n%!" print_job_id id cmd; end;*)
+ action ();
+ let (stdout', stdin', stderr') = open_process_full cmd env in
+ incr jobs_active;
+ set_nonblock (doi stdout');
+ set_nonblock (doi stderr');
+ let job =
+ { job_id = id;
+ job_command = cmd;
+ job_next = rest;
+ job_result = result;
+ job_stdout = stdout';
+ job_stdin = stdin';
+ job_stderr = stderr';
+ job_buffer = Buffer.create 1024;
+ job_dying = false }
+ in
+ outputs := FDM.add (doi stdout') job (FDM.add (doi stderr') job !outputs);
+ jobs := JS.add job !jobs;
+ in
+ (* ***)
+ (*** add_some_jobs *)
+ let add_some_jobs () =
+ let (tasks, result) = Queue.take commands_to_execute in
+ match tasks with
+ | [] -> result := false
+ | task :: rest ->
+ let b_id = !batch_id in
+ incr batch_id;
+ add_job task rest result (b_id, 0)
+ in
+ (* ***)
+ (*** terminate *)
+ let terminate ?(continue=true) job =
+ if not job.job_dying then
+ begin
+ job.job_dying <- true;
+ Queue.add (job, continue) jobs_to_terminate
+ end
+ else
+ ()
+ in
+ (* ***)
+ (*** add_more_jobs_if_possible *)
+ let add_more_jobs_if_possible () =
+ while !jobs_active < max_jobs && not (Queue.is_empty commands_to_execute) do
+ add_some_jobs ()
+ done
+ in
+ (* ***)
+ (*** process_jobs_to_terminate *)
+ let process_jobs_to_terminate () =
+ while not (Queue.is_empty jobs_to_terminate) do
+ ticker ();
+ let (job, continue) = Queue.take jobs_to_terminate in
+
+ (*display begin fun oc -> fp oc "Terminating job %a\n%!" print_job_id job.job_id; end;*)
+
+ decr jobs_active;
+ outputs := FDM.remove (doi job.job_stdout) (FDM.remove (doi job.job_stderr) !outputs);
+ jobs := JS.remove job !jobs;
+ let status = close_process_full (job.job_stdout, job.job_stdin, job.job_stderr) in
+
+ let shown = ref false in
+
+ let show_command () =
+ if !shown then
+ ()
+ else
+ display
+ begin fun oc ->
+ shown := true;
+ fp oc "+ %s\n" job.job_command;
+ output_lines "" oc job.job_buffer
+ end
+ in
+ if Buffer.length job.job_buffer > 0 then show_command ();
+ begin
+ match status with
+ | Unix.WEXITED 0 ->
+ begin
+ if continue then
+ begin
+ match job.job_next with
+ | [] -> job.job_result := true
+ | task :: rest ->
+ let (b_id, s_id) = job.job_id in
+ add_job task rest job.job_result (b_id, s_id + 1)
+ end
+ else
+ all_ok := false;
+ end
+ | Unix.WEXITED rc ->
+ show_command ();
+ display (fun oc -> fp oc "Command exited with code %d.\n" rc);
+ all_ok := false;
+ exit Exit_codes.rc_subcommand_failed
+ | Unix.WSTOPPED s | Unix.WSIGNALED s ->
+ show_command ();
+ all_ok := false;
+ display (fun oc -> fp oc "Command got signal %d.\n" s);
+ exit Exit_codes.rc_subcommand_got_signal
+ end
+ done
+ in
+ (* ***)
+ (*** do_read *)
+ let do_read =
+ let u = String.create 4096 in
+ fun fd job ->
+ if job.job_dying then
+ ()
+ else
+ try
+ let m = read fd u 0 (String.length u) in
+ if m = 0 then
+ terminate job
+ else
+ begin
+ Buffer.add_substring job.job_buffer u 0 m
+ end
+ with
+ | x ->
+ display
+ begin fun oc ->
+ fp oc "Exception %s while reading output of command %S\n%!" job.job_command
+ (Printexc.to_string x);
+ end;
+ exit Exit_codes.rc_io_error
+ in
+ (* ***)
+ (*** terminate_all_jobs *)
+ let terminate_all_jobs () =
+ JS.iter (terminate ~continue:false) !jobs
+ in
+ (* ***)
+ (*** loop *)
+ let rec loop () =
+ (*display (fun oc -> fp oc "Total %d jobs\n" !jobs_active);*)
+ process_jobs_to_terminate ();
+ add_more_jobs_if_possible ();
+ if JS.is_empty !jobs then
+ ()
+ else
+ begin
+ let (rfds, wfds, xfds) = compute_fds () in
+ ticker ();
+ let (chrfds, chwfds, chxfds) = select rfds wfds xfds period in
+ List.iter
+ begin fun (fdlist, hook) ->
+ List.iter
+ begin fun fd ->
+ let job = FDM.find fd !outputs in
+ ticker ();
+ hook fd job
+ end
+ fdlist
+ end
+ [chrfds, do_read;
+ chwfds, (fun _ _ -> ());
+ chxfds,
+ begin fun _ job ->
+ display (fun oc -> fp oc "Exceptional condition on command %S\n%!" job.job_command);
+ exit Exit_codes.rc_exceptional_condition
+ end];
+ loop ()
+ end
+ in
+ try
+ loop ();
+ None
+ with
+ | x ->
+ begin
+ try
+ terminate_all_jobs ()
+ with
+ | x' ->
+ display (fun oc -> fp oc "Extra exception %s\n%!" (Printexc.to_string x'))
+ end;
+ Some(List.map (!) results, x)
+;;
+(* ***)
diff --git a/ocamlbuild/executor.mli b/ocamlbuild/executor.mli
new file mode 100644
index 0000000000..76fc6879fd
--- /dev/null
+++ b/ocamlbuild/executor.mli
@@ -0,0 +1,35 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Executor *)
+
+(** UNIX-specific module for running tasks in parallel and properly multiplexing their outputs. *)
+
+(** [execute ~ticker ~period ~display commands] will execute the commands in [commands]
+ in parallel, correctly multiplexing their outputs. A command is a pair [(cmd, action)]
+ where [cmd] is a shell command string, and [action] is a thunk that is to be called just
+ before [cmd] is about to be executed. If specified, it will call [ticker] at least every [period]
+ seconds. If specified, it will call [display f] when it wishes to print something;
+ [display] should then call [f] with then channel on which [f] should print.
+ Note that [f] must be idempotent as it may well be called twice, once for the log file,
+ once for the actual output.
+ If one of the commands fails, it will exit with an appropriate error code,
+ calling [cleanup] before.
+*)
+val execute :
+ ?max_jobs:int ->
+ ?ticker:(unit -> unit) ->
+ ?period:float ->
+ ?display:((out_channel -> unit) -> unit) ->
+ ((string * (unit -> unit)) list list) ->
+ (bool list * exn) option
diff --git a/ocamlbuild/fda.ml b/ocamlbuild/fda.ml
new file mode 100644
index 0000000000..2a2ce85449
--- /dev/null
+++ b/ocamlbuild/fda.ml
@@ -0,0 +1,76 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* FDA *)
+
+open Log
+open Hygiene
+;;
+
+exception Exit_hygiene_failed
+;;
+
+let laws =
+ [
+ { law_name = "Leftover Ocaml compilation files";
+ law_rules = [Not ".cmo"; Not ".cmi"; Not ".cmx"; Not ".cma"; Not ".cmxa"];
+ law_penalty = Fail };
+ { law_name = "Leftover Ocaml type annotation files";
+ law_rules = [Not ".annot"];
+ law_penalty = Warn };
+ { law_name = "Leftover object files";
+ law_rules = [Not ".o"; Not ".a"; Not ".so"; Not ".obj"; Not ".lib"; Not ".dll"];
+ law_penalty = Fail };
+ { law_name = "Leftover ocamlyacc-generated files";
+ law_rules = [Implies_not(".mly",".ml"); Implies_not(".mly",".mli")];
+ law_penalty = Fail };
+ { law_name = "Leftover ocamllex-generated files";
+ law_rules = [Implies_not(".mll",".ml")];
+ law_penalty = Fail };
+ { law_name = "Leftover dependency files";
+ law_rules = [Not ".ml.depends"; Not ".mli.depends"];
+ law_penalty = Fail }
+ ]
+
+let inspect entry =
+ dprintf 5 "Doing sanity checks";
+ let evil = ref false in
+ match Hygiene.check ~sterilize:!Options.sterilize laws entry with
+ | (entry, []) -> entry
+ | (entry, stuff) ->
+ List.iter
+ begin fun (law, msgs) ->
+ Printf.printf "%s: %s:\n"
+ (match law.law_penalty with
+ | Warn -> "Warning"
+ | Fail ->
+ if not !evil then
+ begin
+ Printf.printf "IMPORTANT:\n\
+ \ I cannot work with leftover compiled files: Please remove them.\n\
+ \ The directory should contain only source files.\n\
+ \ By default I compile in the %s/ directory.\n%!" !Options.build_dir;
+ evil := true
+ end;
+ "ERROR")
+ law.law_name;
+ List.iter
+ begin fun msg ->
+ Printf.printf " %s\n" msg
+ end
+ msgs
+ end
+ stuff;
+ if !evil then raise Exit_hygiene_failed;
+ entry
+;;
diff --git a/ocamlbuild/fda.mli b/ocamlbuild/fda.mli
new file mode 100644
index 0000000000..ac1c824812
--- /dev/null
+++ b/ocamlbuild/fda.mli
@@ -0,0 +1,18 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Fda *)
+
+exception Exit_hygiene_failed
+
+val inspect : bool Slurp.entry -> bool Slurp.entry
diff --git a/ocamlbuild/flags.ml b/ocamlbuild/flags.ml
new file mode 100644
index 0000000000..ddecba5646
--- /dev/null
+++ b/ocamlbuild/flags.ml
@@ -0,0 +1,43 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open Command
+open Bool (* FIXME remove me *)
+open Tags.Operators
+let all_flags = ref []
+
+let of_tags tags =
+ S begin
+ List.fold_left begin fun acc (xtags, xflags) ->
+ if Tags.does_match tags xtags then xflags :: acc
+ else acc
+ end [] !all_flags
+ end
+
+let () = Command.tag_handler := of_tags
+
+let of_tag_list x = of_tags (Tags.of_list x)
+
+let set_flags tags flags =
+ all_flags := (tags, flags) :: !all_flags
+
+let flag tags flags = set_flags (Tags.of_list tags) flags
+
+let add x xs = x :: xs
+let remove me = List.filter (fun x -> me <> x)
+let to_spec l =
+ S begin
+ List.fold_right begin fun (x, y) acc ->
+ A ("-"^x) :: A y :: acc
+ end l []
+ end
diff --git a/ocamlbuild/flags.mli b/ocamlbuild/flags.mli
new file mode 100644
index 0000000000..d0e8c98caf
--- /dev/null
+++ b/ocamlbuild/flags.mli
@@ -0,0 +1,19 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+val of_tags : Tags.t -> Command.spec
+val of_tag_list : Tags.elt list -> Command.spec
+val flag : Tags.elt list -> Command.spec -> unit
+val add : 'a -> 'a list -> 'a list
+val remove : 'a -> 'a list -> 'a list
+val to_spec : (string * string) list -> Command.spec
diff --git a/ocamlbuild/glob.ml b/ocamlbuild/glob.ml
new file mode 100644
index 0000000000..8003dbbb8f
--- /dev/null
+++ b/ocamlbuild/glob.ml
@@ -0,0 +1,398 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Glob *)
+open My_std;;
+open Bool;;
+include Glob_ast;;
+open Glob_lexer;;
+
+let sf = Printf.sprintf;;
+
+let brute_limit = 10;;
+
+(*** string_of_token *)
+let string_of_token = function
+| ATOM _ -> "ATOM"
+| AND -> "AND"
+| OR -> "OR"
+| NOT -> "NOT"
+| LPAR -> "LPAR"
+| RPAR -> "RPAR"
+| TRUE -> "TRUE"
+| FALSE -> "FALSE"
+| EOF -> "EOF"
+;;
+(* ***)
+(*** match_character_class *)
+let match_character_class cl c =
+ Bool.eval
+ begin function (c1,c2) ->
+ c1 <= c && c <= c2
+ end
+ cl
+;;
+(* ***)
+(*** NFA *)
+module NFA =
+ struct
+ type transition =
+ | QCLASS of character_class
+ | QEPSILON
+ ;;
+
+ module IS = Set.Make(struct type t = int let compare = compare let print = Format.pp_print_int end);;
+ module ISM = Map.Make(struct type t = IS.t let compare = IS.compare let print = IS.print end);;
+
+ type machine = {
+ mc_qi : IS.t;
+ mc_table : (character_class * IS.t) list array;
+ mc_qf : int;
+ mc_power_table : (char, IS.t ISM.t) Hashtbl.t
+ }
+
+ (*** build' *)
+ let build' p =
+ let count = ref 0 in
+ let transitions = ref [] in
+ let epsilons : (int * int) list ref = ref [] in
+ let state () = let id = !count in incr count; id in
+ let ( --> ) q1 t q2 =
+ match t with
+ | QEPSILON -> epsilons := (q1,q2) :: !epsilons; q1
+ | QCLASS cl -> transitions := (q1,cl,q2) :: !transitions; q1
+ in
+ (* Construit les transitions correspondant au motif donné et arrivant
+ * sur l'état qf. Retourne l'état d'origine. *)
+ let rec loop qf = function
+ | Epsilon -> qf
+ | Word u ->
+ let m = String.length u in
+ let q0 = state () in
+ let rec loop q i =
+ if i = m then
+ q0
+ else
+ begin
+ let q' =
+ if i = m - 1 then
+ qf
+ else
+ state ()
+ in
+ let _ = (q --> QCLASS(Atom(u.[i], u.[i]))) q' in
+ loop q' (i + 1)
+ end
+ in
+ loop q0 0
+ | Class cl ->
+ let q1 = state () in
+ (q1 --> QCLASS cl) qf
+ | Star p ->
+ (* The fucking Kleene star *)
+ let q2 = state () in
+ let q1 = loop q2 p in (* q1 -{p}-> q2 *)
+ let _ = (q1 --> QEPSILON) qf in
+ let _ = (q2 --> QEPSILON) q1 in
+ let _ = (q2 --> QEPSILON) q1 in
+ q1
+ | Concat(p1,p2) ->
+ let q12 = state () in
+ let q1 = loop q12 p1 in (* q1 -{p1}-> q12 *)
+ let q2 = loop qf p2 in (* q2 -{p2}-> qf *)
+ let _ = (q12 --> QEPSILON) q2 in
+ q1
+ | Union pl ->
+ let qi = state () in
+ List.iter
+ begin fun p ->
+ let q = loop qf p in (* q -{p2}-> qf *)
+ let _ = (qi --> QEPSILON) q in (* qi -{}---> q *)
+ ()
+ end
+ pl;
+ qi
+ in
+ let qf = state () in
+ let qi = loop qf p in
+ let m = !count in
+
+ (* Compute epsilon closure *)
+ let graph = Array.make m IS.empty in
+ List.iter
+ begin fun (q,q') ->
+ graph.(q) <- IS.add q' graph.(q)
+ end
+ !epsilons;
+
+ let closure = Array.make m IS.empty in
+ let rec transitive past = function
+ | [] -> past
+ | q :: future ->
+ let past' = IS.add q past in
+ let future' =
+ IS.fold
+ begin fun q' future' ->
+ (* q -{}--> q' *)
+ if IS.mem q' past' then
+ future'
+ else
+ q' :: future'
+ end
+ graph.(q)
+ future
+ in
+ transitive past' future'
+ in
+ for i = 0 to m - 1 do
+ closure.(i) <- transitive IS.empty [i] (* O(n^2), I know *)
+ done;
+
+ (* Finally, build the table *)
+ let table = Array.make m [] in
+ List.iter
+ begin fun (q,t,q') ->
+ table.(q) <- (t, closure.(q')) :: table.(q)
+ end
+ !transitions;
+
+ (graph, closure,
+ { mc_qi = closure.(qi);
+ mc_table = table;
+ mc_qf = qf;
+ mc_power_table = Hashtbl.create 37 })
+ ;;
+ let build x = let (_,_, machine) = build' x in machine;;
+ (* ***)
+ (*** run *)
+ let run ?(trace=false) machine u =
+ let m = String.length u in
+ let apply qs c =
+ try
+ let t = Hashtbl.find machine.mc_power_table c in
+ ISM.find qs t
+ with
+ | Not_found ->
+ let qs' =
+ IS.fold
+ begin fun q qs' ->
+ List.fold_left
+ begin fun qs' (cl,qs'') ->
+ if match_character_class cl c then
+ IS.union qs' qs''
+ else
+ qs'
+ end
+ qs'
+ machine.mc_table.(q)
+ end
+ qs
+ IS.empty
+ in
+ let t =
+ try
+ Hashtbl.find machine.mc_power_table c
+ with
+ | Not_found -> ISM.empty
+ in
+ Hashtbl.replace machine.mc_power_table c (ISM.add qs qs' t);
+ qs'
+ in
+ let rec loop qs i =
+ if IS.is_empty qs then
+ false
+ else
+ begin
+ if i = m then
+ IS.mem machine.mc_qf qs
+ else
+ begin
+ let c = u.[i] in
+ if trace then
+ begin
+ Printf.printf "%d %C {" i c;
+ IS.iter (fun q -> Printf.printf " %d" q) qs;
+ Printf.printf " }\n%!"
+ end;
+ let qs' = apply qs c in
+ loop qs' (i + 1)
+ end
+ end
+ in
+ loop machine.mc_qi 0
+ ;;
+ (* ***)
+ end
+;;
+(* ***)
+(*** Brute *)
+module Brute =
+ struct
+ exception Succeed;;
+ exception Fail;;
+ exception Too_hard;;
+
+ (*** match_pattern *)
+ let match_pattern counter p u =
+ let m = String.length u in
+ (** [loop i n p] returns [true] iff the word [u.(i .. i + n - 1)] is in the
+ ** language generated by the pattern [p].
+ ** We must have 0 <= i and i + n <= m *)
+ let rec loop (i,n,p) =
+ assert (0 <= i && 0 <= n && i + n <= m);
+ incr counter;
+ if !counter >= brute_limit then raise Too_hard;
+ match p with
+ | Word v ->
+ String.length v = n &&
+ begin
+ let rec check j = j = n or (v.[j] = u.[i + j] && check (j + 1))
+ in
+ check 0
+ end
+ | Epsilon -> n = 0
+ | Star(Class True) -> true
+ | Star(Class cl) ->
+ let rec check k =
+ if k = n then
+ true
+ else
+ (match_character_class cl u.[i + k]) && check (k + 1)
+ in
+ check 0
+ | Star p -> raise Too_hard
+ | Class cl -> n = 1 && match_character_class cl u.[i]
+ | Concat(p1,p2) ->
+ let rec scan j =
+ j <= n && ((loop (i,j,p1) && loop (i+j, n - j,p2)) || scan (j + 1))
+ in
+ scan 0
+ | Union pl -> List.exists (fun p' -> loop (i,n,p')) pl
+ in
+ loop (0,m,p)
+ ;;
+ (* ***)
+end
+;;
+(* ***)
+(*** fast_pattern, globber *)
+type fast_pattern =
+| Brute of int ref * pattern
+| Machine of NFA.machine
+;;
+
+type globber = fast_pattern ref atom Bool.boolean;;
+(* ***)
+(*** add_dir *)
+let add_dir dir x =
+ match dir with
+ | None -> x
+ | Some(dir) ->
+ match x with
+ | Constant(s) ->
+ Constant(My_std.filename_concat dir s)
+ | Pattern(p) ->
+ Pattern(Concat(Word(My_std.filename_concat dir ""), p))
+;;
+(* ***)
+(*** parse *)
+let parse ?dir u =
+ let l = Lexing.from_string u in
+ let tok = ref None in
+ let f =
+ fun () ->
+ match !tok with
+ | None -> token l
+ | Some x ->
+ tok := None;
+ x
+ in
+ let g t =
+ match !tok with
+ | None -> tok := Some t
+ | Some t' ->
+ raise (Parse_error(sf "Trying to unput token %s while %s is active" (string_of_token t) (string_of_token t')))
+ in
+ let read x =
+ let y = f () in
+ if x = y then
+ ()
+ else
+ raise (Parse_error(sf "Unexpected token, expecting %s, got %s" (string_of_token x) (string_of_token y)))
+ in
+ let rec atomizer continuation = match f () with
+ | NOT -> atomizer (fun x -> continuation (Not x))
+ | ATOM x ->
+ begin
+ let a =
+ match add_dir dir x with
+ | Constant u -> Constant u
+ | Pattern p -> Pattern(ref (Brute(ref 0, p)))
+ in
+ continuation (Atom a)
+ end
+ | TRUE -> continuation True
+ | FALSE -> continuation False
+ | LPAR ->
+ let y = parse_s () in
+ read RPAR;
+ continuation y
+ | t -> raise (Parse_error(sf "Unexpected token %s in atomizer" (string_of_token t)))
+ and parse_s1 x = match f () with
+ | OR -> let y = parse_s () in Or[x; y]
+ | AND -> parse_t x
+ | t -> g t; x
+ and parse_t1 x y = match f () with
+ | OR -> let z = parse_s () in Or[And[x;y]; z]
+ | AND -> parse_t (And[x;y])
+ | t -> g t; And[x;y]
+ and parse_s () = atomizer parse_s1
+ and parse_t x = atomizer (parse_t1 x)
+ in
+ let x = parse_s () in
+ read EOF;
+ x
+;;
+(* ***)
+(*** eval *)
+let eval g u =
+ Bool.eval
+ begin function
+ | Constant v -> u = v
+ | Pattern kind ->
+ match !kind with
+ | Brute(count, p) ->
+ begin
+ let do_nfa () =
+ let m = NFA.build p in
+ kind := Machine m;
+ NFA.run m u
+ in
+ if !count >= brute_limit then
+ do_nfa ()
+ else
+ try
+ Brute.match_pattern count p u
+ with
+ | Brute.Too_hard -> do_nfa ()
+ end
+ | Machine m -> NFA.run m u
+ end
+ g
+(* ***)
+(*** Debug *)
+(*let (Atom(Pattern x)) = parse "<{a,b}>";;
+#install_printer IS.print;;
+#install_printer ISM.print;;
+let (graph, closure, machine) = build' x;;*)
+(* ***)
diff --git a/ocamlbuild/glob.mli b/ocamlbuild/glob.mli
new file mode 100644
index 0000000000..46dee1528d
--- /dev/null
+++ b/ocamlbuild/glob.mli
@@ -0,0 +1,18 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Glob *)
+
+(** A self-contained module implementing extended shell glob patterns who have an expressive power
+ equal to boolean combinations of regular expressions. *)
+include Signatures.GLOB
diff --git a/ocamlbuild/glob_ast.ml b/ocamlbuild/glob_ast.ml
new file mode 100644
index 0000000000..2173702ecb
--- /dev/null
+++ b/ocamlbuild/glob_ast.ml
@@ -0,0 +1,31 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Glob_ast *)
+
+exception Parse_error of string;;
+
+type pattern =
+| Epsilon
+| Star of pattern (* The fucking Kleene star *)
+| Class of character_class
+| Concat of pattern * pattern
+| Union of pattern list
+| Word of string
+and character_class = (char * char) Bool.boolean
+;;
+
+type 'pattern atom =
+| Constant of string
+| Pattern of 'pattern
+;;
diff --git a/ocamlbuild/glob_ast.mli b/ocamlbuild/glob_ast.mli
new file mode 100644
index 0000000000..a4c5a52dd8
--- /dev/null
+++ b/ocamlbuild/glob_ast.mli
@@ -0,0 +1,25 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Glob_ast *)
+
+exception Parse_error of string
+type pattern =
+| Epsilon
+| Star of pattern
+| Class of character_class
+| Concat of pattern * pattern
+| Union of pattern list
+| Word of string
+and character_class = (char * char) Bool.boolean
+type 'pattern atom = Constant of string | Pattern of 'pattern
diff --git a/ocamlbuild/glob_lexer.mli b/ocamlbuild/glob_lexer.mli
new file mode 100644
index 0000000000..aa818dda58
--- /dev/null
+++ b/ocamlbuild/glob_lexer.mli
@@ -0,0 +1,27 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+open Glob_ast
+
+type token =
+| ATOM of pattern atom
+| AND
+| OR
+| NOT
+| LPAR
+| RPAR
+| TRUE
+| FALSE
+| EOF
+
+val token : Lexing.lexbuf -> token
diff --git a/ocamlbuild/glob_lexer.mll b/ocamlbuild/glob_lexer.mll
new file mode 100644
index 0000000000..8bf49900da
--- /dev/null
+++ b/ocamlbuild/glob_lexer.mll
@@ -0,0 +1,114 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Glob *)
+{
+open Bool;;
+open Glob_ast;;
+
+type token =
+| ATOM of pattern atom
+| AND
+| OR
+| NOT
+| LPAR
+| RPAR
+| TRUE
+| FALSE
+| EOF
+;;
+
+let sf = Printf.sprintf;;
+
+let concat_patterns p1 p2 =
+ match (p1,p2) with
+ | (Epsilon,_) -> p2
+ | (_,Epsilon) -> p1
+ | (_,_) -> Concat(p1,p2)
+;;
+
+let slash = Class(Atom('/','/'));;
+let not_slash = Class(Not(Atom('/','/')));;
+let any = Class True;;
+}
+
+let pattern_chars = ['a'-'z']|['A'-'Z']|'_'|'-'|['0'-'9']|'.'
+let space_chars = [' ' '\t' '\n' '\r' '\012']
+
+rule token = parse
+| '<' { ATOM(Pattern(let (p,_) = parse_pattern ['>'] Epsilon lexbuf in p)) }
+| '"' { ATOM(Constant(parse_string (Buffer.create 32) lexbuf)) }
+| "and"|"AND"|"&" { AND }
+| "or"|"OR"|"|" { OR }
+| "not"|"NOT"|"~" { NOT }
+| "true"|"1" { TRUE }
+| "false"|"0" { FALSE }
+| "(" { LPAR }
+| ")" { RPAR }
+| space_chars+ { token lexbuf }
+| eof { EOF }
+
+and parse_pattern eof_chars p = parse
+| (pattern_chars+ as u) { parse_pattern eof_chars (concat_patterns p (Word u)) lexbuf }
+| '{'
+ {
+ let rec loop pl =
+ let (p',c) = parse_pattern ['}';','] Epsilon lexbuf in
+ let pl = p' :: pl in
+ if c = ',' then
+ loop pl
+ else
+ parse_pattern eof_chars (concat_patterns p (Union pl)) lexbuf
+ in
+ loop []
+ }
+| "[^"
+ {
+ let cl = Not(Or(parse_class [] lexbuf)) in
+ parse_pattern eof_chars (concat_patterns p (Class cl)) lexbuf
+ }
+| '['
+ {
+ let cl = Or(parse_class [] lexbuf) in
+ parse_pattern eof_chars (concat_patterns p (Class cl)) lexbuf
+ }
+| "/**/" (* / | /\Sigma^*/ *)
+ { let q = Union[slash; Concat(slash, Concat(Star any, slash)) ] in
+ parse_pattern eof_chars (concat_patterns p q) lexbuf }
+| "/**" (* \varepsilon | /\Sigma^* *)
+ { let q = Union[Epsilon; Concat(slash, Star any)] in
+ parse_pattern eof_chars (concat_patterns p q) lexbuf }
+| "**/" (* \varepsilon | \Sigma^*/ *)
+ { let q = Union[Epsilon; Concat(Star any, slash)] in
+ parse_pattern eof_chars (concat_patterns p q) lexbuf }
+| "**" { raise (Parse_error("Ambiguous ** pattern not allowed unless surrounded by one or more slashes")) }
+| '*' { parse_pattern eof_chars (concat_patterns p (Star not_slash)) lexbuf }
+| '/' { parse_pattern eof_chars (concat_patterns p slash) lexbuf }
+| '?' { parse_pattern eof_chars (concat_patterns p (Class True)) lexbuf }
+| _ as c
+ { if List.mem c eof_chars then
+ (p,c)
+ else
+ raise (Parse_error(sf "Unexpected character %C in glob pattern" c))
+ }
+
+and parse_string b = parse
+| "\"" { Buffer.contents b }
+| "\\\"" { Buffer.add_char b '"'; parse_string b lexbuf }
+| [^'"' '\\']+ as u { Buffer.add_string b u; parse_string b lexbuf }
+
+and parse_class cl = parse
+| ']' { cl }
+| "-]" { ((Atom('-','-'))::cl) }
+| (_ as c1) '-' (_ as c2) { parse_class ((Atom(c1,c2))::cl) lexbuf }
+| _ as c { parse_class ((Atom(c,c))::cl) lexbuf }
diff --git a/ocamlbuild/hooks.ml b/ocamlbuild/hooks.ml
new file mode 100644
index 0000000000..d1d36998e3
--- /dev/null
+++ b/ocamlbuild/hooks.ml
@@ -0,0 +1,26 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+type message =
+ | Before_hygiene
+ | After_hygiene
+ | Before_options
+ | After_options
+ | Before_rules
+ | After_rules
+
+let hooks = ref ignore
+
+let setup_hooks f = hooks := f
+
+let call_hook m = !hooks m
diff --git a/ocamlbuild/hooks.mli b/ocamlbuild/hooks.mli
new file mode 100644
index 0000000000..0c55e9f1a9
--- /dev/null
+++ b/ocamlbuild/hooks.mli
@@ -0,0 +1,23 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+type message =
+ | Before_hygiene
+ | After_hygiene
+ | Before_options
+ | After_options
+ | Before_rules
+ | After_rules
+
+val setup_hooks : (message -> unit) -> unit
+val call_hook : message -> unit
diff --git a/ocamlbuild/hygiene.ml b/ocamlbuild/hygiene.ml
new file mode 100644
index 0000000000..7b6a788fc9
--- /dev/null
+++ b/ocamlbuild/hygiene.ml
@@ -0,0 +1,171 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Hygiene *)
+open My_std
+open Slurp
+
+exception Exit_hygiene_violations
+
+type rule =
+| Implies_not of pattern * pattern
+| Not of pattern
+and pattern = suffix
+and suffix = string
+
+type penalty = Warn | Fail
+
+type law = {
+ law_name : string;
+ law_rules : rule list;
+ law_penalty : penalty
+}
+
+let list_collect f l =
+ let rec loop result = function
+ | [] -> List.rev result
+ | x :: rest ->
+ match f x with
+ | None -> loop result rest
+ | Some y -> loop (y :: result) rest
+ in
+ loop [] l
+
+let list_none_for_all f l =
+ let rec loop = function
+ | [] -> None
+ | x :: rest ->
+ match f x with
+ | None -> loop rest
+ | y -> y
+ in
+ loop l
+
+let sf = Printf.sprintf
+
+module SS = Set.Make(String);;
+
+let check ?(sterilize=false) laws entry =
+ let penalties = ref [] in
+ let microbes = ref SS.empty in
+ let remove path name =
+ if sterilize then
+ microbes := SS.add (filename_concat path name) !microbes
+ in
+ let check_rule = fun entries -> function
+ | Not suffix ->
+ list_collect
+ begin function
+ | File(path, name, _, true) ->
+ if Filename.check_suffix name suffix then
+ begin
+ remove path name;
+ Some(sf "File %s in %s has suffix %s" name path suffix)
+ end
+ else
+ None
+ | File _ | Dir _| Error _ | Nothing -> None
+ end
+ entries
+ | Implies_not(suffix1, suffix2) ->
+ list_collect
+ begin function
+ | File(path, name, _, true) ->
+ if Filename.check_suffix name suffix1 then
+ begin
+ let base = Filename.chop_suffix name suffix1 in
+ let name' = base ^ suffix2 in
+ if List.exists
+ begin function
+ | File(_, name'', _, true) -> name' = name''
+ | File _ | Dir _ | Error _ | Nothing -> false
+ end
+ entries
+ then
+ begin
+ remove path name';
+ Some(sf "Files %s and %s should not be together in %s" name name' path)
+ end
+ else
+ None
+ end
+ else
+ None
+ | File _ | Dir _ | Error _ | Nothing -> None
+ end
+ entries
+ in
+ let rec check_entry = function
+ | Dir(_,_,_,true,entries) ->
+ List.iter
+ begin fun law ->
+ match List.concat (List.map (check_rule !*entries) law.law_rules) with
+ | [] -> ()
+ | explanations ->
+ penalties := (law, explanations) :: !penalties
+ end
+ laws;
+ List.iter check_entry !*entries
+ | Dir _ | File _ | Error _ | Nothing -> ()
+ in
+ check_entry entry;
+ begin
+ let microbes = !microbes in
+ if SS.is_empty microbes then
+ (entry, !penalties)
+ else
+ begin
+ Printf.printf "STERILIZE: do you want me to remove the following files?\n ";
+ SS.iter
+ begin fun fn ->
+ Printf.printf " %s" fn
+ end
+ microbes;
+ Printf.printf "\n";
+ let rec answer () =
+ Printf.printf "Type YES (in uppercase) for removal, something else for no action: %!";
+ let u = input_line stdin in
+ if u <> "" then
+ u
+ else
+ answer ()
+ in
+ if answer () = "YES" then
+ begin
+ let success = ref true in
+ SS.iter
+ begin fun fn ->
+ try
+ Sys.remove fn
+ with
+ | x ->
+ success := false;
+ Printf.printf "ERROR removing %s: %s\n%!" fn (Printexc.to_string x)
+ end
+ microbes;
+ if !success then
+ let entry' =
+ Slurp.filter (fun path name _ -> not (SS.mem (My_std.filename_concat path name) microbes)) entry
+ in
+ (entry', []) (* XXX: No penalties, is this correct ? *)
+ else
+ raise Exit_hygiene_violations
+ end
+ else
+ begin
+ Printf.printf "I am taking your answer for a NO.\n";
+ (entry, !penalties)
+ end
+ end
+ end
+;;
diff --git a/ocamlbuild/hygiene.mli b/ocamlbuild/hygiene.mli
new file mode 100644
index 0000000000..6bed8a3c23
--- /dev/null
+++ b/ocamlbuild/hygiene.mli
@@ -0,0 +1,47 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Hygiene *)
+
+(** Module for checking that the source tree is not polluted by object files. *)
+
+(** Sanity rules to abide. Not to be confused with compilation rules. *)
+type rule =
+ Implies_not of pattern * pattern (** The rule [Implies_not(".mll",".ml")] is broken if there is a file [foo.mll]
+ together with a file [foo.ml] int the same directory. The second file can
+ get sterilized. *)
+| Not of pattern (* No files with suffix [pattern] will be tolerated. *)
+
+(** Suffix matching is enough for the purpose of this module. *)
+and pattern = suffix
+
+(** And a suffix is a string. *)
+and suffix = string
+
+(** A warning is simply displayed. A failures stops the compilation. *)
+type penalty = Warn | Fail
+
+(** This type is used to encode laws that will be checked by this module. *)
+type law = {
+ law_name : string; (** The name of the law that will be printed when it is violated. *)
+ law_rules : rule list; (** Breaking any of these rules is breaking this law. *)
+ law_penalty : penalty; (** Breaking the law gives you either a warning or a failure. *)
+}
+
+(** [check ~sterilize laws entry] will scan the directory tree [entry] for violation to the given [laws].
+ Any warnings or errors will be printed on the [stdout]. If [sterilize] is true, the user will be
+ given the option to delete the offending files by interaction on [stdin/stdout]. This function
+ will return a pair [(entry', penalties)] where [entry'] is the updated directory tree (if the user
+ has agreed to remove offending files, for instance) and [penalties] is a list of laws and messages
+ describing the offenses. *)
+val check : ?sterilize:bool -> law list -> bool Slurp.entry -> bool Slurp.entry * (law * string list) list
diff --git a/ocamlbuild/lexers.mli b/ocamlbuild/lexers.mli
new file mode 100644
index 0000000000..3d74cad93e
--- /dev/null
+++ b/ocamlbuild/lexers.mli
@@ -0,0 +1,30 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+exception Error of string
+
+type conf_values =
+ { plus_tags : string list;
+ minus_tags : string list;
+ plus_flags : (string * string) list;
+ minus_flags : (string * string) list }
+
+type conf = (Glob.globber * conf_values) list
+
+val ocamldep_output : Lexing.lexbuf -> (string * string list) list
+val space_sep_strings : Lexing.lexbuf -> string list
+val blank_sep_strings : Lexing.lexbuf -> string list
+val comma_sep_strings : Lexing.lexbuf -> string list
+val colon_sep_strings : Lexing.lexbuf -> string list
+val conf_lines : string option -> int -> string -> Lexing.lexbuf -> conf
+val meta_path : Lexing.lexbuf -> (string * bool) list
diff --git a/ocamlbuild/lexers.mll b/ocamlbuild/lexers.mll
new file mode 100644
index 0000000000..1d6ae65d5a
--- /dev/null
+++ b/ocamlbuild/lexers.mll
@@ -0,0 +1,116 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+{
+exception Error of string
+
+type conf_values =
+ { plus_tags : string list;
+ minus_tags : string list;
+ plus_flags : (string * string) list;
+ minus_flags : (string * string) list }
+
+type conf = (Glob.globber * conf_values) list
+
+let empty = { plus_flags = []; minus_flags = []; plus_tags = []; minus_tags = [] }
+
+}
+
+let newline = ('\n' | '\r' | "\r\n")
+let space = [' ' '\t' '\012']
+let blank = newline | space
+let not_blank = [^' ' '\t' '\012' '\n' '\r']
+let not_space_nor_comma = [^' ' '\t' '\012' ',']
+let not_newline = [^ '\n' '\r' ]
+let not_newline_nor_colon = [^ '\n' '\r' ':' ]
+let normal_flag_value = [^ '(' ')' '\n' '\r']
+let normal = [^ ':' ',' '(' ')' ''' ' ' '\n' '\r']
+let tag = normal+ | ( normal+ ':' normal+ )
+let flag_name = normal+
+let flag_value = normal_flag_value+
+
+rule ocamldep_output = parse
+ | ([^ ':' '\n' '\r' ]+ as k) ':' { let x = (k, space_sep_strings_nl lexbuf) in x :: ocamldep_output lexbuf }
+ | eof { [] }
+ | _ { raise (Error "Expecting colon followed by space-separated module name list") }
+
+and space_sep_strings_nl = parse
+ | space* (not_blank+ as word) { word :: space_sep_strings_nl lexbuf }
+ | space* newline { [] }
+ | _ { raise (Error "Expecting space-separated strings terminated with newline") }
+
+and space_sep_strings = parse
+ | space* (not_blank+ as word) { word :: space_sep_strings lexbuf }
+ | space* newline? eof { [] }
+ | _ { raise (Error "Expecting space-separated strings") }
+
+and blank_sep_strings = parse
+ | blank* '#' not_newline* newline { blank_sep_strings lexbuf }
+ | blank* (not_blank+ as word) { word :: blank_sep_strings lexbuf }
+ | blank* eof { [] }
+ | _ { raise (Error "Expecting blank-separated strings") }
+
+and comma_sep_strings = parse
+ | space* (not_space_nor_comma+ as word) space* eof { [word] }
+ | space* (not_space_nor_comma+ as word) { word :: comma_sep_strings_aux lexbuf }
+ | space* eof { [] }
+ | _ { raise (Error "Expecting comma-separated strings (1)") }
+and comma_sep_strings_aux = parse
+ | space* ',' space* (not_space_nor_comma+ as word) { word :: comma_sep_strings_aux lexbuf }
+ | space* eof { [] }
+ | _ { raise (Error "Expecting comma-separated strings (2)") }
+
+and colon_sep_strings = parse
+ | ([^ ':']+ as word) eof { [word] }
+ | ([^ ':']+ as word) { word :: colon_sep_strings_aux lexbuf }
+ | eof { [] }
+ | _ { raise (Error "Expecting colon-separated strings (1)") }
+and colon_sep_strings_aux = parse
+ | ':' ([^ ':']+ as word) { word :: colon_sep_strings_aux lexbuf }
+ | eof { [] }
+ | _ { raise (Error "Expecting colon-separated strings (2)") }
+
+and conf_lines dir pos err = parse
+ | space* '#' not_newline* newline { conf_lines dir (pos + 1) err lexbuf }
+ | space* newline { conf_lines dir (pos + 1) err lexbuf }
+ | space* eof { [] }
+ | space* (not_newline_nor_colon+ as k) space* ':' space*
+ {
+ let bexpr = Glob.parse ?dir k in
+ let v1 = conf_value pos err empty lexbuf in
+ let v2 = conf_values pos err v1 lexbuf in
+ let rest = conf_lines dir (pos + 1) err lexbuf in (bexpr, v2) :: rest
+ }
+ | _ { raise (Error(Printf.sprintf "Bad key in configuration line at line %d (from %s)" pos err)) }
+
+and conf_value pos err x = parse
+ | '-' (flag_name as t1) '(' (flag_value as t2) ')' { { (x) with minus_flags = (t1, t2) :: x.minus_flags } }
+ | '+'? (flag_name as t1) '(' (flag_value as t2) ')' { { (x) with plus_flags = (t1, t2) :: x.plus_flags } }
+ | '-' (tag as tag) { { (x) with minus_tags = tag :: x.minus_tags } }
+ | '+'? (tag as tag) { { (x) with plus_tags = tag :: x.plus_tags } }
+ | (_ | eof) { raise (Error(Printf.sprintf "Bad value in configuration line at line %d (from %s)" pos err)) }
+
+and conf_values pos err x = parse
+ | space* ',' space* { conf_values pos err (conf_value pos err x lexbuf) lexbuf }
+ | (newline | eof) { x }
+ | (_ | eof) { raise (Error(Printf.sprintf "Bad values in configuration line at line %d (from %s)" pos err)) }
+
+and meta_path = parse
+ | ([^ '%' ]+ as prefix)
+ { (prefix, false) :: meta_path lexbuf }
+ | "%(" ([ 'a'-'z' 'A'-'Z' '_' '-' '0'-'9' ]* as var) ')'
+ { (var, true) :: meta_path lexbuf }
+ | '%'
+ { ("", true) :: meta_path lexbuf }
+ | eof
+ { [] }
diff --git a/ocamlbuild/log.ml b/ocamlbuild/log.ml
new file mode 100644
index 0000000000..c0ed1f68ea
--- /dev/null
+++ b/ocamlbuild/log.ml
@@ -0,0 +1,49 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+
+module Debug = struct
+let mode _ = true
+end
+include Debug
+
+let level = ref 1
+
+let classic_display = ref false
+let log_file = ref (lazy None)
+
+let internal_display = lazy begin
+ let mode =
+ if !classic_display || !*My_unix.is_degraded || !level <= 0 || not (My_unix.stdout_isatty ()) then
+ `Classic
+ else
+ `Sophisticated
+ in
+ Display.create ~mode ?log_file:!*(!log_file) ~log_level:!level ()
+end
+
+let raw_dprintf log_level = Display.dprintf ~log_level !*internal_display
+
+let dprintf log_level fmt = raw_dprintf log_level ("@[<2>"^^fmt^^"@]@.")
+let eprintf fmt = dprintf (-1) fmt
+
+let update () = Display.update !*internal_display
+let event ?pretend x = Display.event !*internal_display ?pretend x
+let display x = Display.display !*internal_display x
+
+let finish ?how () =
+ if Lazy.lazy_is_val internal_display then
+ Display.finish ?how !*internal_display
+
+(*let () = My_unix.at_exit_once finish*)
diff --git a/ocamlbuild/log.mli b/ocamlbuild/log.mli
new file mode 100644
index 0000000000..8fbb1da7c3
--- /dev/null
+++ b/ocamlbuild/log.mli
@@ -0,0 +1,34 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* Log *)
+
+(** Module for modulating the logging output with the logging level. *)
+include Signatures.LOG
+
+(** Turn it to true to have a classic display of commands. *)
+val classic_display : bool ref
+
+(** The optional log file. *)
+val log_file : string option Lazy.t ref
+
+(** See {Display.event}. *)
+val event : ?pretend:bool -> string -> string -> Tags.t -> unit
+
+(**/**)
+
+val internal_display : Display.display Lazy.t
+val finish : ?how:[`Success|`Error|`Quiet] -> unit -> unit
+val display : (out_channel -> unit) -> unit
+val update : unit -> unit
+val mode : string -> bool
diff --git a/ocamlbuild/main.ml b/ocamlbuild/main.ml
new file mode 100644
index 0000000000..59033274d3
--- /dev/null
+++ b/ocamlbuild/main.ml
@@ -0,0 +1,266 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+open My_std
+open Log
+open Pathname.Operators
+open Command
+open Tools
+open Ocaml_specific
+open Format
+;;
+
+exception Exit_build_error of string
+exception Exit_silently
+
+let clean () =
+ Shell.rm_rf !Options.build_dir;
+ begin
+ match !Options.internal_log_file with
+ | None -> ()
+ | Some fn -> Shell.rm_f fn
+ end;
+ let entry =
+ Slurp.map (fun _ _ _ -> true)
+ (Slurp.slurp Filename.current_dir_name)
+ in
+ Slurp.force (Pathname.clean_up_links entry);
+ raise Exit_silently
+;;
+
+let proceed () =
+ Hooks.call_hook Hooks.Before_options;
+ Options.init ();
+ if !Options.must_clean then clean ();
+ Hooks.call_hook Hooks.After_options;
+ Tools.default_tags := Tags.of_list !Options.tags;
+ Plugin.execute_plugin_if_needed ();
+
+ if !Options.targets = [] then raise Exit_silently;
+
+ let target_dirs = List.union [] (List.map Pathname.dirname !Options.targets) in
+
+ let newpwd = Sys.getcwd () in
+ Sys.chdir Pathname.pwd;
+ let entry_include_dirs = ref [] in
+ let entry =
+ Slurp.filter
+ begin fun path name _ ->
+ let dir =
+ if path = Filename.current_dir_name then
+ None
+ else
+ Some path
+ in
+ let path_name = path/name in
+ if name = "_tags" then
+ ignore (Configuration.parse_file ?dir path_name);
+
+ (String.length name > 0 && name.[0] <> '_' && not (List.mem name !Options.exclude_dirs))
+ && begin
+ if path_name <> Filename.current_dir_name && Pathname.is_directory path_name then
+ let tags = tags_of_pathname path_name in
+ if Tags.mem "include" tags
+ || List.mem path_name !Options.include_dirs then
+ (entry_include_dirs := path_name :: !entry_include_dirs; true)
+ else
+ Tags.mem "traverse" tags
+ || List.exists (Pathname.is_prefix path_name) !Options.include_dirs
+ || List.exists (Pathname.is_prefix path_name) target_dirs
+ else true
+ end
+ end
+ (Slurp.slurp Filename.current_dir_name)
+ in
+ let hygiene_entry =
+ Slurp.map begin fun path name () ->
+ let tags = tags_of_pathname (path/name) in
+ not (Tags.mem "not_hygienic" tags) && not (Tags.mem "precious" tags)
+ end entry in
+ Hooks.call_hook Hooks.Before_hygiene;
+ let entry =
+ if !Options.hygiene then
+ Fda.inspect hygiene_entry
+ else
+ (Slurp.force hygiene_entry; hygiene_entry)
+ in
+ Hooks.call_hook Hooks.After_hygiene;
+ Options.include_dirs := Pathname.current_dir_name :: List.rev !entry_include_dirs;
+ dprintf 3 "include directories are:@ %a" print_string_list !Options.include_dirs;
+ Options.entry := Some entry;
+
+ Hooks.call_hook Hooks.Before_rules;
+ Ocaml_specific.init ();
+ Hooks.call_hook Hooks.After_rules;
+
+ Sys.chdir newpwd;
+ (*let () = dprintf 0 "source_dir_path_set:@ %a" StringSet.print source_dir_path_set*)
+
+ dprintf 8 "Rules are:@ %a" (List.print Rule.print) (Rule.get_rules ());
+ Resource.Cache.init ();
+
+ Configuration.parse_string
+ "<**/*.ml> or <**/*.mli> or <**/*.mlpack> or <**/*.ml.depends>: ocaml
+ <**/*.byte>: ocaml, byte, program
+ <**/*.odoc>: ocaml, doc
+ <**/*.native>: ocaml, native, program
+ <**/*.cma>: ocaml, byte, library
+ <**/*.cmxa>: ocaml, native, library
+ <**/*.cmo>: ocaml, byte
+ <**/*.cmi>: ocaml, byte, native
+ <**/*.cmx>: ocaml, native
+ ";
+
+ Sys.catch_break true;
+
+ let targets =
+ List.map begin fun starget ->
+ let target = path_and_context_of_string starget in
+ let ext = Pathname.get_extension starget in
+ (target, starget, ext)
+ end !Options.targets in
+
+ try
+ let targets =
+ List.map begin fun (target, starget, ext) ->
+ Shell.mkdir_p (Pathname.dirname starget);
+ let target = Solver.solve_target starget target in
+ (target, ext)
+ end targets in
+
+ Log.finish ();
+
+ Shell.chdir Pathname.pwd;
+
+ let call spec = sys_command (Command.string_of_command_spec spec) in
+
+ let cmds =
+ List.fold_right begin fun (target, ext) acc ->
+ let cmd = !Options.build_dir/target in
+ if ext = "byte" || ext = "native" then begin
+ if !Options.make_links then ignore (call (S [A"ln"; A"-sf"; P cmd; A Pathname.current_dir_name]));
+ cmd :: acc
+ end else begin
+ if !Options.program_to_execute then
+ eprintf "Warning: Won't execute %s whose extension is neither .byte nor .native" cmd;
+ acc
+ end
+ end targets [] in
+
+ if !Options.program_to_execute then
+ begin
+ match List.rev cmds with
+ | [] -> raise (Exit_usage "Using -- requires one target");
+ | cmd :: rest ->
+ if rest <> [] then dprintf 0 "Warning: Using -- only run the last target";
+ let cmd_spec = S [P cmd; atomize !Options.program_args] in
+ dprintf 3 "Running the user command:@ %a" Pathname.print cmd;
+ raise (Exit_with_code (call cmd_spec)) (* Exit with the exit code of the called command *)
+ end
+ else
+ ()
+ with
+ | Ocaml_dependencies.Circular_dependencies(seen, p) ->
+ raise
+ (Exit_build_error
+ (sbprintf "@[<2>Circular dependencies: %S already seen in@ %a@]@." p pp_l seen))
+;;
+
+module Exit_codes =
+ struct
+ let rc_ok = 0
+ let rc_usage = 1
+ let rc_failure = 2
+ let rc_invalid_argument = 3
+ let rc_system_error = 4
+ let rc_hygiene = 1
+ let rc_circularity = 5
+ let rc_solver_failed = 6
+ let rc_ocamldep_error = 7
+ let rc_lexing_error = 8
+ let rc_build_error = 9
+ let rc_executor_reserved_1 = 10 (* Redefined in Executor *)
+ let rc_executor_reserved_2 = 11
+ let rc_executor_reserved_3 = 12
+ let rc_executor_reserved_4 = 13
+ end
+
+open Exit_codes;;
+
+let main () =
+ let exit rc =
+ Log.finish ~how:(if rc <> 0 then `Error else `Success) ();
+ Pervasives.exit rc
+ in
+ try
+ proceed ()
+ with
+ | Exit_OK -> exit rc_ok
+ | Fda.Exit_hygiene_failed ->
+ Log.eprintf "Exiting due to hygiene violations (try -sterilize).";
+ exit rc_hygiene
+ | Exit_usage u ->
+ Log.eprintf "Usage:@ %s." u;
+ exit rc_usage
+ | Exit_system_error msg ->
+ Log.eprintf "System error:@ %s." msg;
+ exit rc_system_error
+ | Exit_with_code rc ->
+ exit rc
+ | Exit_silently ->
+ Log.finish ~how:`Quiet ();
+ Pervasives.exit rc_ok
+ | Exit_silently_with_code rc ->
+ Log.finish ~how:`Quiet ();
+ Pervasives.exit rc
+ | Solver.Failed backtrace ->
+ Log.raw_dprintf (-1) "@[<v0>@[<2>Solver failed:@ %a@]@\n@[<v2>Backtrace:%a@]@]@."
+ Report.print_backtrace_analyze backtrace Report.print_backtrace backtrace;
+ exit rc_solver_failed
+ | Failure s ->
+ Log.eprintf "Failure:@ %s." s;
+ exit rc_failure
+ | Solver.Circular(r, rs) ->
+ Log.eprintf "Circular build detected@ (%a already seen in %a)"
+ Resource.print r (List.print Resource.print) rs;
+ exit rc_circularity
+ | Invalid_argument s ->
+ Log.eprintf
+ "INTERNAL ERROR: Invalid argument %s\n\
+ This is likely to be a bug, please report this to the ocamlbuild\n\
+ developers." s;
+ exit rc_invalid_argument
+ | Ocamldep.Error msg ->
+ Log.eprintf "Ocamldep error: %s" msg;
+ exit rc_ocamldep_error
+ | Lexers.Error msg ->
+ Log.eprintf "Lexical analysis error: %s" msg;
+ exit rc_lexing_error
+ | Arg.Bad msg ->
+ Log.eprintf "%s" msg;
+ exit rc_usage
+ | Exit_build_error msg ->
+ Log.eprintf "%s" msg;
+ exit rc_build_error
+ | Arg.Help msg ->
+ Log.eprintf "%s" msg;
+ exit rc_ok
+ | e ->
+ try
+ Log.eprintf "%a" My_unix.report_error e;
+ exit 100
+ with
+ | e ->
+ Log.eprintf "Exception@ %s." (Printexc.to_string e);
+ exit 100
+;;
diff --git a/ocamlbuild/main.mli b/ocamlbuild/main.mli
new file mode 100644
index 0000000000..a7a816ea79
--- /dev/null
+++ b/ocamlbuild/main.mli
@@ -0,0 +1,14 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+val main : unit -> unit
diff --git a/ocamlbuild/man/ocamlbuild.1 b/ocamlbuild/man/ocamlbuild.1
new file mode 100644
index 0000000000..aa75159466
--- /dev/null
+++ b/ocamlbuild/man/ocamlbuild.1
@@ -0,0 +1,253 @@
+.TH OCAMLBUILD 1
+
+.SH NAME
+ocamlbuild \- The Objective Caml project compilation tool
+
+
+.SH SYNOPSIS
+.B ocamlbuild
+[
+.B \-Is \ dir1,...
+]
+[
+.BI \-libs \ lib1,...
+]
+[
+.BI \-lflags \ flag1,...
+]
+[
+.BI \-pp \ flags
+]
+[
+.BI \-tags \ tag1,...
+]
+[
+.B \-j \ parallel-jobs
+]
+.I target.native
+[
+.B \-\- arg1 arg2 ...
+]
+
+.I (same options)
+
+.SH DESCRIPTION
+
+.BR ocamlbuild (1)
+orchestrates the compilation process of your OCaml project. It is similar
+in function to
+.BR make (1)
+except that it is tailor-made to automatically compile most OCaml projects
+with very little user input.
+
+.BR ocamlbuild
+should be invoked in the root of a clean project tree (e.g., with no leftover
+compilation files). Given one or more targets to compile, it scans the required
+subdirectories to gather information about the various files present, running
+tools such as
+.BR ocamldep (1)
+to extract dependency information, and gathering optional files that fine-tune
+its behaviour.
+Target names are very significant.
+
+.SH TARGET NAMES
+.BR ocamlbuild
+uses a set of target naming conventions to select the kind of objects to
+produce. Target names are of the form
+.BR base.extension
+where
+.BR base
+is usually the name of the underlying Ocaml module and
+.BR extension
+denotes the kind of object to produce from that file -- a byte code executable,
+a native executable, documentation...
+Of course extensions such as
+.BR .cmo,
+.BR .cma,
+.BR .cmi...
+map to their usual counterparts. Here is a list of the most important
+.BR ocamlbuild \&-specific
+extensions:
+
+.TP 2i
+.B .native
+Native code executable
+
+.TP 2i
+.B .byte
+Byte code executable
+
+.TP 2i
+.B .inferred.mli
+Interface inferred with
+.BR ocamlc -i
+
+.TP 2i
+.B .docdir/index.html
+HTML documentation generated with
+.BR ocamldoc
+
+.PP
+
+.SH OPTIONS
+
+The following command-line options are recognized by
+.BR ocamlbuild (1).
+
+.TP
+\fB\-version\fR
+Display the version
+.TP
+\fB\-verbose\fR
+Turn on the verbose mode
+.TP
+\fB\-quiet\fR
+Make as quiet as possible
+.TP
+\fB\-debug\fR <level>
+Set the debug level
+.TP
+\fB\-log\fR <file>
+Set log file
+.TP
+\fB\-no\-log\fR
+No log file
+.TP
+\fB\-clean\fR
+Remove build directory and other files, then exit
+.TP
+\fB\-I\fR <path>
+Add to include directories
+.TP
+\fB\-Is\fR <path,...>
+(same as above, but accepts a comma\-separated list)
+.TP
+\fB\-X\fR <path>
+Directory to ignore
+.TP
+\fB\-Xs\fR <path,...>
+(idem)
+.TP
+\fB\-lib\fR <flag>
+Link to this ocaml library
+.TP
+\fB\-libs\fR <flag,...>
+(idem)
+.TP
+\fB\-lflag\fR <flag>
+Add to ocamlc link flags
+.TP
+\fB\-lflags\fR <flag,...>
+(idem)
+.TP
+\fB\-cflag\fR <flag>
+Add to ocamlc compile flags
+.TP
+\fB\-cflags\fR <flag,...>
+(idem)
+.TP
+\fB\-yaccflag\fR <flag>
+Add to ocamlyacc flags
+.TP
+\fB\-yaccflags\fR <flag,...>
+(idem)
+.TP
+\fB\-lexflag\fR <flag>
+Add to ocamllex flags
+.TP
+\fB\-lexflags\fR <flag,...>
+(idem)
+.TP
+\fB\-ppflag\fR <flag>
+Add to ocaml preprocessing flags
+.TP
+\fB\-pp\fR <flag,...>
+(idem)
+.TP
+\fB\-tag\fR <tag>
+Add to default tags
+.TP
+\fB\-tags\fR <tag,...>
+(idem)
+.TP
+\fB\-ignore\fR <module,...>
+Don't try to build these modules
+.TP
+\fB\-no\-links\fR
+Don't make links of produced final targets
+.TP
+\fB\-no\-skip\fR
+Don't skip modules that are requested by ocamldep but cannot be built
+.TP
+\fB\-no\-hygiene\fR
+Don't apply sanity\-check rules
+.TP
+\fB\-no\-plugin\fR
+Don't build myocamlbuild.ml
+.TP
+\fB\-no\-stdlib\fR
+Don't ignore stdlib modules
+.TP
+\fB\-just\-plugin\fR
+Just build myocamlbuild.ml
+.TP
+\fB\-byte\-plugin\fR
+Don't use a native plugin but bytecode
+.TP
+\fB\-sterilize\fR
+Enforce sanity\-check rules by removing leftover files (DANGER)
+.TP
+\fB\-nothing\-should\-be\-rebuilt\fR
+Fail if something needs to be rebuilt
+.TP
+\fB\-classic\-display\fR
+Display executed commands the old\-fashioned way
+.TP
+\fB\-j\fR <N>
+Allow N jobs at once (0 for unlimited)
+.TP
+\fB\-build\-dir\fR <path>
+Set build directory
+.TP
+\fB\-install\-dir\fR <path>
+Set the install directory
+.TP
+\fB\-where\fR
+Display the install directory
+.TP
+\fB\-ocamlc\fR <command>
+Set the OCaml bytecode compiler
+.TP
+\fB\-ocamlopt\fR <command>
+Set the OCaml native compiler
+.TP
+\fB\-ocamldep\fR <command>
+Set the OCaml dependency tool
+.TP
+\fB\-ocamlyacc\fR <command>
+Set the ocamlyacc tool
+.TP
+\fB\-ocamllex\fR <command>
+Set the ocamllex tool
+.TP
+\fB\-ocamlrun\fR <command>
+Set the ocamlrun tool
+.TP
+\fB\-\-\fR
+Stop argument processing, remaining arguments are given to the user program
+.TP
+\fB\-help\fR
+Display the list of options
+.TP
+\fB\-\-help\fR
+Display the list of options
+.PP
+
+.SH SEE ALSO
+The
+.BR ocamlbuild
+manual,
+.BR ocaml (1),
+.BR make (1).
+.br
+.I The Objective Caml user's manual, chapter "Batch compilation".
diff --git a/ocamlbuild/manual/Makefile b/ocamlbuild/manual/Makefile
new file mode 100644
index 0000000000..4c2ef88b2c
--- /dev/null
+++ b/ocamlbuild/manual/Makefile
@@ -0,0 +1,11 @@
+# Makefile
+
+manual.pdf: manual.tex
+
+%.pdf: %.tex
+ pdflatex $<
+
+.PHONY: clean
+
+clean:
+ rm -f *.pdf *.log *.aux *.ps *.dvi
diff --git a/ocamlbuild/manual/manual.tex b/ocamlbuild/manual/manual.tex
new file mode 100644
index 0000000000..c255e9a220
--- /dev/null
+++ b/ocamlbuild/manual/manual.tex
@@ -0,0 +1,943 @@
+%(*** preamble
+\documentclass[12pt]{article}
+\usepackage[utf8]{inputenc}
+\usepackage{palatino}
+\usepackage{mathrsfs}
+\usepackage[T1]{fontenc}
+\usepackage[english]{babel}
+\usepackage[a4paper,lmargin=1cm,rmargin=1cm,tmargin=1cm,bmargin=1cm]{geometry}
+%***)
+%(*** title
+\begin{document}
+\newcommand{\ocb}{\texttt{ocamlbuild}~}
+\newcommand{\tags}{\texttt{\_tags}~}
+\title{\ocb, a tool for \\ automatic compilation \\ of OCaml projects}
+\author{Nicolas \textsc{Pouillard}, Berke \textsc{Durak}}
+\date{January 2007}
+\maketitle
+%***)
+%(*** abstract
+\abstract{
+
+}
+%***)
+%(*** Motivations
+\section{Motivations}
+{\em This section describes the frustation that led us to write \ocb.}
+
+Many people have painfully found that the utilities of the \texttt{make}
+family, namely GNU Make, BSD Make, and their derivatives, fail to scale to
+large projects, especially when using multi-stage compilation rules, such as
+custom pre-processors, unless dependencies are hand-defined. But as your
+project gets larger, more modular, and uses more diverse pre-processing tools,
+it becomes increasingly difficult to correctly define dependencies by hand.
+Hence people tend to use language-specific tools that attempt to extract
+dependencies. However another problem then appears: \texttt{make} was designed
+with the idea of a static dependency graph. Dependency extracting tools,
+however, are typically run by a rule in \texttt{make} itself; this means that
+make has to reload the dependency information. This is the origin of the
+\texttt{make clean; make depend; make} mantra. This approach tends to work
+quite well as long as all the files sit in a single directory and there is only
+one stage of pre-processing. If there are two or more stages, then dependency
+extracting tools must be run two or more times - and this means multiple
+invocations of \texttt{make}. Also, if one distributes the modules of a large
+project into multiple subdirectories, it becomes difficult to distribute the
+makefiles themselves, because the language of \texttt{make} was not conceived
+to be modular; the only two mechanisms permitted, inclusion of makefile
+fragments, and invocation of other make instances, must be skillfully
+coordinated with phony target names (\texttt{depend1, depend2...}) to insure
+inclusion of generated dependencies with multi-stage programming; changes in
+the structure of the project must be reflected by hand and the order of
+variable definitions must be well-thought ahead to avoid long afternoons spent
+combinatorially fiddling makefiles until it works but no one understands why.
+
+These problems become especially apparent with OCaml: to ensure type safety and
+to allow a small amount of cross-unit optimization when compiling native code,
+interface and object files include cryptographical digests of interfaces they
+are to be linked with. This means that linking is safer, but that makefile sloppiness
+leads to messages such as:
+\begin{verbatim}
+Files foo.cmo and bar.cmo
+make inconsistent assumptions over interface Bar
+\end{verbatim}
+
+The typical reaction is then to issue the mantra \texttt{make clean; make
+depend; make} and everything compiles just fine... from the beginning. Hence
+on medium projects, the programmer often has to wait for minutes instead of the
+few seconds that would be taken if \texttt{make} could correctly guess the
+small number of files that really had to be recompiled.
+
+It is not surprising that hacking a build tool such as \texttt{make} to include
+a programming language while retaining the original syntax and semantics gives
+an improvised and cumbersome macro language of dubious expressive power. For
+example, using GNU make, suppose you have a list of \texttt{.ml}s that you want
+to convert into a list including both \texttt{.cmo}s and \texttt{.cmi}s, that
+is you want to transform \texttt{a.ml b.ml c.ml} into \texttt{a.cmi a.cmo b.cmi
+b.cmo c.cmi c.cmo} while preserving the dependency order which must be hand
+specified for linking \footnote{By the way, what's the point of having a
+declarative language if \texttt{make} can't sort the dependencies in
+topological order for giving them to \texttt{gcc} or whatever ?}.
+Unfortunately \texttt{\$patsubst \%.ml, \%.cmi \%.cmo, a.ml b.ml c.ml} won't
+work since the \%-sign in the right-hand of a \texttt{patsubst} gets
+substituted only once. You then have to delve into something that is hardly
+lambda calculus: an intricate network of \texttt{foreach}, \texttt{eval},
+\texttt{call} and \texttt{define}s may get you the job done, unless you chicken
+out and opt for an external \texttt{awk}, \texttt{sed} or \texttt{perl} call.
+People who at this point have not lost their temper or sanity usually resort to
+metaprogramming by writing Makefile generators using a mixture of shell and m4.
+One such an attempt gave something that is the nightmare of wannabe package
+maintainers: it's called \texttt{autotools}.
+
+Note that it is also difficult to write \texttt{Makefiles} to build object
+files in a separate directory. It is not impossible since the language of
+\texttt{make} is Turing-complete, a proof of which is left as an exercise.
+Note that building things in a separate directory is not necessarily a young
+enthousiast's way of giving a different look and feel to his projects -- it may
+be a good way of telling the computer that \texttt{foo.mli} is generated by
+\texttt{ocamlyacc} using \texttt{foo.mly} and can thus be removed.
+%***)
+%(*** Features of ocamlbuild
+\section{Features of \ocb}
+{\em This section is intended to read like a sales brochure or a datasheet.}
+
+\begin{itemize}
+\item Built-in compilation rules for OCaml projects handle all the nasty cases : native and bytecode,
+missing \texttt{.mli} files, preprocessor rules, debugging and profiling flags, C stubs.
+\item Plugin mechanism for writing compilation rules and actions in a real programming language,
+OCaml itself.
+\item Automatic inference of dependencies
+\item Correct handling of dynamically discovered dependencies
+\item Object files and other temporary files are created in a specific directory, leaving your main directory uncluttered.
+\item Sanity checks ensure that object files are where they are supposed to be: in the build directory.
+\item Simple projects are built using a single command with no extra files.
+\item Parallel compilation to speed up things on multi-core systems.
+\item Sophisticated display mode to keep your screen free of boring and repetitive compilation message
+while giving you important progress information in a glimpse, and correctly multiplexing the error messages.
+\item Tags and flags provide a concise and convenient mechanism for automatic selection of compilation, preprocessing and
+other options
+\item Extended shell-like glob patterns, that can be combined using boolean operators,
+allow you to concisely define the tags that apply to a given file.
+\item Mechanisms for defining the mutual visibility of subdirectories.
+\item Cache mechanism avoiding unnecessary compilations where reasonably computable.
+\end{itemize}
+%***)
+%(*** Limitations
+\section{Limitations}
+{\em Not perfect nor complete yet, but already pretty damn useful.}
+
+We were not expecting to write the ultimate compilation tool in a few man-months, however we believe we have
+a tool that solves many compilation problems, especially our own, in a satisfactory way. Hence there are a
+lot of missing features, incomplete options and hideous bugs lurking in \ocb, and we hope that the OCaml community
+will find our first try at \ocb useful and hopefully help it grow into a tool that satisfies most needs of most users
+by providing feedback, bug reports and patches.
+
+The plugin API is lacking in maturity, as it has only been tested by the
+authors. We believe a good API can only evolve under pressure from many peers
+and the courage to rewrite things cleanly when time is ripe by the developers.
+
+Nonetheless the parts of \ocb that do not rely on the plugin API, namely, the command-line
+options, the \texttt{\_tags} file, the target names, names of the tags, and so
+on, are not expected to change in incompatible ways. We intend to keep a project that compiles
+without a plugin compilable without modifications in the future.
+
+As for plugins, we recommend that users isolate calls to the \ocb library from their logic
+to be able to keep the later when incompatible API changes arise.
+
+\begin{itemize}
+\item Plugin API not stable
+\item No built-in rules for creating toplevels or librairies
+\end{itemize}
+%***)
+%(*** Using ocamlbuild
+\section{Using \ocb}
+{\em Learn how to use \ocb with short, specific, straight-to-the-point examples.}
+
+The amount of time and effort spent on the compilation process of a project
+should be proportionate to that spent on the project itself. It should be easy
+to set up a small project, maybe a little harder for a medium-sized project,
+and it may take some more time, but not too much, for a big project. Ideally
+setting up a big project would be as easy as setting up a small project. However,
+as projects grow, modularization techniques start to be used, and the probability
+of using meta programming or multiple programming languages increases, thus making
+the compilation process more delicate.
+
+\ocb is intended to be very easy to use for projects, large or small, with a simple
+compilation process: typing
+\texttt{ocamlbuild foo.native} should be enough to compile the native version
+of a program whose top module is \texttt{foo.ml} and whose dependencies are in
+the same directory. As your project gets more complex, you will gradually
+start to use command-line options to specify libraries to link with, then
+configuration files, ultimately culminating in a custom OCaml plugin for
+complex projects with arbitrary dependencies and actions.
+
+%(*** Hygiene *)
+\subsection{Hygiene \& where is my code ?}
+Your code is in the \texttt{\_build} directory, but \ocb automatically creates
+a symbolic link to the executables it produces in the current directory.
+\ocb copies the source files and compiles them in a separate directory
+which is \texttt{\_build} by default.
+
+For \ocb, any file that is not in the build directory is a source file.
+It is not unreasonable to think that some users may have bought binary object files
+they keep in their project directory. Usually binary files cluttering the project
+directory are due to previous builds using other systems. \ocb has so-called
+``hygiene'' rules that state that object files (\texttt{.cmo}, \texttt{.cmi},
+or \texttt{.o} files, for instance) must not appear outside of the build
+directory. These rules are enforced at startup; any violations will be reported
+and \ocb will exit. You must then remove these files by hand or use, with caution,
+the \texttt{-sterilize} option which will remove them for you, after prompting
+you for confirmation.
+
+To disable these checks, you can use the \texttt{-no-hygiene} flag. If you have
+files that must elude the hygiene squad, just tag them with \texttt{precious}
+or \texttt{not\_hygienic}.
+%***)
+%(*** Hello, world !
+\subsection{Hello, world !}
+Assuming we are in a directory named \texttt{example1} containing one file \texttt{hello.ml}
+whose contents are
+\begin{verbatim}
+let _ =
+ Printf.printf "Hello, %s ! My name is %s\n"
+ (if Array.length Sys.argv > 1 then Sys.argv.(1) else "stranger")
+ Sys.argv.(0)
+;;
+\end{verbatim}
+we can compile and link it into a native executable by invoking \texttt{ocamlbuild hello.native}.
+Here, \texttt{hello} is the basename of the top-level module and \texttt{native} is an extension used
+by \ocb to denote native code executables.
+\begin{verbatim}
+% ls
+hello.ml
+% ocamlbuild hello.native
+Finished, 4 targets (0 cached) in 00:00:00.
+% ls -l
+total 12
+drwxrwx--- 2 linus gallium 4096 2007-01-17 16:24 _build/
+-rw-rw---- 1 linus gallium 43 2007-01-17 16:23 hello.ml
+lrwxrwxrwx 1 linus gallium 19 2007-01-17 16:24 hello.native -> _build/hello.native*
+-rw-r----- 1 linus gallium 460 2007-01-17 16:24 _log
+\end{verbatim}
+What's this funny \texttt{\_build} directory ? Well that's where \ocb does its dirty work
+of compiling. You usually won't have to look very often into this directory. Source files are be copied
+into \texttt{\_build} and this is where the compilers will be run. Various cache files are also stored
+there. Its contents may look like this:
+\begin{verbatim}
+% ls -l _build
+total 208
+-rw-rw---- 1 linus gallium 337 2007-01-17 16:24 _digests
+-rw-rw---- 1 linus gallium 191 2007-01-17 16:24 hello.cmi
+-rw-rw---- 1 linus gallium 262 2007-01-17 16:24 hello.cmo
+-rw-rw---- 1 linus gallium 225 2007-01-17 16:24 hello.cmx
+-rw-rw---- 1 linus gallium 43 2007-01-17 16:23 hello.ml
+-rw-rw---- 1 linus gallium 17 2007-01-17 16:24 hello.ml.depends
+-rwxrwx--- 1 linus gallium 173528 2007-01-17 16:24 hello.native*
+-rw-rw---- 1 linus gallium 936 2007-01-17 16:24 hello.o
+-rw-rw---- 1 linus gallium 22 2007-01-17 16:24 ocamlc.where
+\end{verbatim}
+%***)
+%(*** Executing my code
+\subsection{Executing my code}
+You can execute your code the old-fashioned way (\texttt{./hello.native}).
+You may also type
+\begin{verbatim}
+ocamlbuild main.native -- Caesar
+\end{verbatim}
+and it will compile and then run \texttt{main.native} with the arguments following \texttt{-{}-},
+which should display:
+\begin{verbatim}
+% ocamlbuild hello.native -- Caesar
+Finished, 4 targets (0 cached) in 00:00:00.
+Hello, Caesar ! My name is _build/hello.native
+\end{verbatim}
+%***)
+%(*** The log file, verbosity and debugging
+\subsection{The log file, verbosity and debugging}
+By default, if you run \ocb on a terminal, it will use some ANSI escape sequences
+to display a nice, one-line progress indicator. To see what commands \ocb has actually run,
+you can check the contents of the \texttt{\_log} file. To change the name of the
+log file or to disable logging, use the \texttt{-log <file>} or \texttt{-no-log} options.
+Note that the log file is truncated at each execution of \ocb.
+
+The log file contains all the external commands that \ocb ran or intended to
+run along with the target name and the computed tags. With the
+\texttt{-verbose <level>} option, \ocb will also write more or less useful
+debugging information; a verbosity level of $1$ (which can also be specified
+using the \texttt{-verbose} switch) prints generally useful information; higher
+levels produce much more output.
+%***)
+%(*** Cleaning
+\subsection{Cleaning}
+\ocb may leave a \texttt{\_build} directory, symbolic links to executables in
+that directory, and a \texttt{\_log} file. All of these can be removed safely
+by hand, or by invoking \ocb with the \texttt{-clean} flag.
+%***)
+%(*** Where and how to run \ocb
+\subsection{Where and how to run \ocb ?}
+An important point is that \ocb must be invoked from the root of the project,
+even if this project has multiple, nested subdirectories. This is because \ocb
+likes to store the object files in a single \texttt{\_build} directory. You
+can change the name of that directory with the \texttt{-build-dir} option.
+
+\ocb can be either invoked manually from the UNIX or Windows shell, or
+automatically from a build script or a Makefile. Unless run with the
+\texttt{-no-hygiene} option, there is the possibility that \ocb will prompt the
+user for a response. By default, on UNIX systems, if \ocb senses that the
+standard output is a terminal, it will use a nice progress indicator using ANSI
+codes, instrumenting the output of the processes it spawns to have a consistent
+display. Under non-UNIX systems, or if the standard output is not a terminal,
+it will run in classic mode where it will echo the executed commands on its
+standard output. This selection can be overridden with the \texttt{-classic-display} option.
+%***)
+%(*** Dependencies
+\subsection{Dependencies}
+{\em Dependencies are automatically discovered.}
+
+Most of the value of \ocb lies in the fact that it often needs no extra
+information to compile a project besides the name of the top-level module.
+\ocb calls \texttt{ocamldep} to automatically find the dependencies of any
+modules it wants to compile. These dependencies are dynamically incorporated
+in the depdendency graph, something \texttt{make} cannot do.
+For instance, let's add a module \texttt{Greet} that implements various ways of
+greeting people.
+\begin{verbatim}
+% cat greet.ml
+type how = Nicely | Badly;;
+
+let greet how who =
+ match how with Nicely -> Printf.printf "Hello, %s !\n" who
+ | Badly -> Printf.printf "Oh, here is that %s again.\n" who
+;;
+% cat hello.ml
+open Greet
+
+let _ =
+ let name =
+ if Array.length Sys.argv > 1 then
+ Sys.argv.(1)
+ else
+ "stranger"
+ in
+ greet
+ (if name = "Caesar" then Nicely else Badly)
+ name;
+ Printf.printf "My name is %s\n" Sys.argv.(0)
+;;
+\end{verbatim}
+Then the module \texttt{Main} depends on the module \texttt{Greet} and \ocb can
+figure this out for himself -- we still only have to invoke \texttt{\ocb
+main.native}. Needless to say, this works for any number of modules.
+%***)
+%(*** Native and byte code
+\subsection{Native and bytecode}
+If we want to compile bytecode instead of native, we just a target name of
+\texttt{main.byte} instead of \texttt{main.native}, i.e., we type
+\texttt{\ocb hello.byte}.
+%***)
+%(*** Compile flags
+\subsection{Compile flags}
+To pass a flag to the compiler, such as the \texttt{-rectypes} option,
+use the \texttt{-cflag} option as in :
+\begin{verbatim}
+ocamlbuild -cflag -rectypes hello.native
+\end{verbatim}
+You can put multiple \texttt{-cflag} options, they will be passed to the compiler
+in the same order. You can also given them in a comma-separated list with the
+\texttt{-cflags} option (notice the plural):
+\begin{verbatim}
+ocamlbuild -cflags -I,+lablgtk,-rectypes hello.native
+\end{verbatim}
+These flags apply when compiling, that is, when producing \texttt{.cmi},
+\texttt{.cmo},\texttt{.cmx} and \texttt{.o} files from \texttt{.ml} or
+\texttt{.mli} files.
+%***)
+%(*** Link flags
+\subsection{Link flags}
+Link flags apply when the various object files are collected and linked into
+one executable. These will typically be include directories for libraries.
+They are given using the \texttt{-lflag} and \texttt{-lflags} options, which
+work in the same way as the \texttt{-cflag} and \texttt{-cflags} options.
+%***)
+%(*** Linking with external libraries
+\subsection{Linking with external libraries}
+In our third example, we use one Unix system call and functions from the \texttt{num}
+library:
+\begin{verbatim}
+% cat epoch.ml
+let _ =
+ let s = Num.num_of_string (Printf.sprintf "%.0f" (Unix.gettimeofday ())) in
+ let ps = Num.mult_num (Num.num_of_string "1000000000000") s in
+ Printf.printf "%s picoseconds have passed since January 1st, 1970.\n"
+ (Num.string_of_num ps)
+;;
+\end{verbatim}
+This requires linking with the \texttt{unix} and \texttt{num} modules, which is accomplished
+by using the \texttt{-lib unix} and \texttt{-lib num} flags, or, alternatively, \texttt{-libs unix,num}:
+\begin{verbatim}
+% ocamlbuild -libs nums,unix epoch.native -- a
+Finished, 4 targets (4 cached) in 00:00:00.
+1169051647000000000000 picoseconds have passed since January 1st, 1970.
+\end{verbatim}
+You may need to add options such as \texttt{-cflags -I,/usr/local/lib/ocaml/}
+and \texttt{-lflags -I,/usr/local/lib/ocaml/} if the librairies you wish to
+link with are not in OCaml's default search path.
+%***)
+%(*** The _tags files
+\subsection{The \tags files}
+Finer control over the compiler flags applied to each source file, such as
+preprocessing, debugging, profiling and linking options, can be gained using
+\ocb's tagging mechanism.
+
+Every source file has a set of tags which tells \ocb what kind of file it is
+and what to do with it. A tag is simply a string, usually lowercase, for
+example \texttt{ocaml} or \texttt{native}. The set of tags attached to a file
+is computed by applying the tagging rules to the filename. Tagging rules are
+defined in \tags files in any parent directory of a file, up to the main
+project directory.
+
+Each line in the \tags file is made of a glob pattern (see subsection
+\ref{subsec:glob}) and a list of tags. More than one rule can apply to a file
+and rules are applied in the order in which they appear in a file.
+By preceding a tag with a minus sign, one may remove tags from one or more files.
+
+\subsubsection{Example: the built-in \tags file}
+\begin{verbatim}
+ "<**/*.ml> or <**/*.mli> or <**/*.mlpack> or <**/*.ml.depends>: ocaml
+ <**/*.byte>: ocaml, byte, program
+ <**/*.odoc>: ocaml, doc
+ <**/*.native>: ocaml, native, program
+ <**/*.cma>: ocaml, byte, library
+ <**/*.cmxa>: ocaml, native, library
+ <**/*.cmo>: ocaml, byte
+ <**/*.cmi>: ocaml, byte, native
+ <**/*.cmx>: ocaml, native
+\end{verbatim}
+
+A special tag made from the path name of the file relative to the toplevel
+of the project is automatically defined for each file. For a file
+\texttt{foo/bar.ml} this tag wil be \texttt{file:foo/bar.ml}.
+
+If you do not have subdirectories, you can put \texttt{*.ml} instead of
+\texttt{**/*.ml}.
+%***)
+%(*** Glob patterns and expressions
+\subsection{Glob patterns and expressions}
+\label{subsec:glob}
+Glob patterns have a syntax similar to those used by UNIX shells to select path
+names (like \texttt{foo\_\*\.ba?}). They are used in \ocb to define the files
+and directories to which tags apply. Glob expressions are glob patterns
+enclosed in brackets \texttt{<} and \texttt{>} combined using the standard
+boolean operators \texttt{and}, \texttt{or}, \texttt{not}. This allows one to
+describe sets of path names in more concise and more readable ways.
+
+Please note that file and directory names are supposed to be made of the
+following characters: $\texttt{a}$, $\dots$, $\texttt{z}$, $\texttt{A}$,
+$\dots$, $\texttt{Z}$, $\texttt{0}$, $\dots$, $\texttt{9}$, $\texttt{\_}$,
+$\texttt{-}$ and $\texttt{.}$. This is called the pathname alphabet $P$.
+
+\begin{table}[h]
+ \begin{center}
+ \small
+ \begin{tabular}{|p{3cm}|l|p{3cm}|p{3cm}|p{5cm}|}
+ \hline
+ {\em Formal syntax} &
+ {\em Example} & {\em Matches} & {\em Doesn't match} &
+ {\em Meaning (formal meaning)} \\
+ \hline
+ \hline
+%%
+ {$u$ \vskip 0.5em A string of pathname characters} &
+ \texttt{foo.ml} &
+ \texttt{foo.ml} &
+ \texttt{fo.ml}, \texttt{bar/foo.ml} &
+ The exact string $u$
+ ($\{ u \}$, where $u \in P^*$) \\
+ \hline
+%%
+ {\texttt{*} \vskip 0.5em The wildcard star}&
+ \texttt{*}&
+ $\varepsilon$, \texttt{foo}, \texttt{bar} &
+ \texttt{foo/bar}, \texttt{/bar} &
+ Any string not containing a slash
+ ($P^*$) \\
+ \hline
+%%
+ {\texttt{?} \vskip 0.5em The joker}&
+ \texttt{?}&
+ \texttt{a}, \texttt{b}, \texttt{z} &
+ \texttt{/}, \texttt{bar} &
+ Any one-letter string, excluding the slash \\
+ \hline
+%%
+ {\texttt{**/} \vskip 0.5em The prefix interdirectory star}&
+ \texttt{**/foo.ml}&
+ \texttt{foo.ml}, \texttt{bar/foo.ml}, \texttt{bar/baz/foo.ml} &
+ \texttt{foo/bar}, \texttt{/bar} &
+ The empty string, or any string ending with a slash
+ ($\varepsilon \cup P^*\mathtt{/}$) \\
+ \hline
+%%
+ {\texttt{/**} \vskip 0.5em The suffix interdirectory star}&
+ \texttt{foo/**}&
+ \texttt{foo}, \texttt{foo/bar} &
+ \texttt{bar/foo} &
+ Any string starting with a slash, or the empty string.
+ ($\varepsilon \cup \mathtt{/}P^*$) \\
+ \hline
+%%
+ {\texttt{/**/} \vskip 0.5em The infix interdirectory star}&
+ \texttt{bar/**/foo.ml}&
+ \texttt{bar/foo.ml}, \texttt{bar/baz/foo.ml} &
+ \texttt{foo.ml} &
+ Any string starting and ending with a slash
+ ($\varepsilon \cup \mathtt{/}P^*\mathtt{/}$) \\
+ \hline
+%%
+ {$\mathtt{[} r_1 r_2 \cdots r_k \mathtt{]}$
+ where $r_i$ is either $c$ or $c_1-c_2$ $(1 \leq i \leq k)$
+ \vskip 0.5em The positive character class}&
+ \texttt{[a-fA-F0-9\_.]}&
+ \texttt{3}, \texttt{F}, \texttt{.} &
+ \texttt{z}, \texttt{bar} &
+ Any one-letter string made of characters from one of the ranges
+ $r_i$ ($1 \leq i \leq n$).
+ ($\mathscr L(r_1) \cup \cdots \cup \mathscr L(r_n)$) \\
+ \hline
+%%
+ {\texttt{[\char`\^}$r_1 r_2 \cdots r_k \mathtt{]}$
+ where $r_i$ is either $c$ or $c_1-c_2$ $(1 \leq i \leq k)$
+ \vskip 0.5em The negative character class}&
+ \texttt{[\char`\^a-fA-F0-9\_.]}&
+ \texttt{z}, \texttt{bar} &
+ \texttt{3}, \texttt{F}, \texttt{.} &
+ Any one-letter string NOT made of characters from one of the ranges
+ $r_i$ ($1 \leq i \leq n$).
+ ($\Sigma^* \setminus \left(\mathscr L(r_1) \cup \cdots \cup \mathscr L(r_n)\right)$) \\
+ \hline
+%%
+ {$p_1 p_2$ \vskip 0.5em A concatenation of patterns}&
+ \texttt{foo*}&
+ \texttt{foo}, \texttt{foob}, \texttt{foobar} &
+ \texttt{fo}, \texttt{bar} &
+ Any string with a prefix matching $p_1$ and the corresponding suffix
+ matching $p_2$,
+ ($\{ uv \mid u \in \mathscr L(p_1), v \in \mathscr L(p_2) \}$) \\
+ \hline
+%%
+ {$\mathtt{\{} p_1 \mathtt{,} p_2 \mathtt{,} \cdots \mathtt{,} p_k \mathtt{\}}$ \vskip 0.5em A union of patterns}&
+ \texttt{toto.\{ml,mli\}}&
+ \texttt{toto.ml}, \texttt{toto.mli} &
+ \texttt{toto.} &
+ Any string matching one of the patterns $p_i$ for $1 \leq i \leq k$.
+ ($\mathscr L(p_1) \cup \cdots \cup \mathscr L(p_k)$) \\
+ \hline
+%%
+ \end{tabular}
+ \end{center}
+ \caption{
+ Syntax and semantics of glob patterns.
+ }
+\end{table}
+\begin{table}
+ \begin{center}
+ \small
+ \begin{tabular}{|p{2cm}|l|p{7cm}|}
+ \hline
+ {\em Formal syntax} &
+ {\em Example} &
+ {\em Meaning (formal meaning)} \\
+ \hline
+ \hline
+ {$\mathtt{<}p\mathtt{>}$} &
+ \texttt{<foo.ml>} &
+ Pathnames matching the pattern $p$ \\
+ \hline
+ {$e_1 \; \mathtt{or} \; e_2$} &
+ \texttt{<*.ml> or <foo/bar.ml>} &
+ Pathnames matching at least one of the expressions $e_1$ and $e_2$ \\
+ \hline
+ {$e_1 \; \mathtt{and} \; e_2$} &
+ \texttt{<*.ml> and <foo\_*>} &
+ Pathnames matching both expressions $e_1$ and $e_2$ \\
+ \hline
+ {$\mathtt{not} \; e$} &
+ \texttt{not <*.mli>} &
+ Pathnames not matching the expression $e$ \\
+ \hline
+ {$\mathtt{true}$} &
+ \texttt{true} &
+ All pathnames \\
+ \hline
+ {$\mathtt{false}$} &
+ \texttt{false} &
+ No pathnames \\
+ \hline
+ \end{tabular}
+ \end{center}
+ \caption{
+ Syntax and semantics of glob expressions.
+ }
+\end{table}
+%***)
+%(*** Subdirectories
+\subsection{Subdirectories}
+If the files of your project are held in one or more subdirectories,
+\ocb must be made aware of that fact using the \texttt{-I} or \texttt{-Is} options
+or by adding an \texttt{include} tag. For instance, assume your project is made
+of three subdirectories, \texttt{foo}, \texttt{bar} and \texttt{baz} containing
+various \texttt{.ml} files, the main file being \texttt{foo/main.ml}. Then you can
+either type:
+\begin{verbatim}
+% ocamlbuild -Is foo,bar,baz foo/main.native
+\end{verbatim}
+or add the following line in the \texttt{\_tags} file
+\begin{verbatim}
+<foo> or <bar> or <baz>: include
+\end{verbatim}
+and call
+\begin{verbatim}
+% ocamlbuild foo/main.native
+\end{verbatim}
+
+There are then two cases. If no other modules named \texttt{Bar} or
+\texttt{Baz} exist elsewhere in the project, then you are done. Just use
+\texttt{Foo}, \texttt{Foo.Bar} and \texttt{Foo.Baz} in your code.
+Otherwise, you will need to use the plugin mechanism and define the mutual
+visibility of the subdirectories using the XXX function.
+%***)
+%(*** Grouping targets
+\subsection{Grouping targets with \texttt{.itarget}}
+You can create a file named \texttt{foo.itarget} containing
+a list of targets, one per line, such as
+\begin{verbatim}
+main.native
+main.byte
+stuff.docdir/index.html
+\end{verbatim}
+Requesting the target \texttt{foo.otarget} will then build every target
+listed in the file \texttt{foo.itarget}. Blank lines and dashes to comment
+out lines are accepted.
+%***)
+%(*** Packing subdirectories into modules
+\subsection{Packing subdirectories into modules}
+OCaml's \texttt{-pack} option allows you to structure the contents of a
+module in a subdirectory. For instance, assume you have a directory
+\texttt{foo} containing two modules \texttt{bar.ml} and \texttt{baz.ml}.
+You want from these to build a module \texttt{Foo} containing \texttt{Bar}
+and \texttt{Baz} as submodules. In the case where no modules named
+\texttt{Bar} or \texttt{Baz} exist outside of \texttt{Foo}, To do this you
+must write a file \texttt{foo.mlpack}, preferably sitting in the same
+directory as the directory \texttt{Foo} and containing the list of modules
+(one per line) it must contain:
+\begin{verbatim}
+Bar
+Baz
+\end{verbatim}
+%***)
+%(*** Preprocessor options
+\subsection{Preprocessor options and tags}
+You can specify preprocessor options with \texttt{-pp} followed by the
+preprocessor string, for instance \texttt{ocamlbuild -pp "camlp4o.opt -unsafe"}
+would run your sources thru CamlP4 with the \texttt{-unsafe} option.
+Another way is to use the tags file.
+\begin{center}
+ \begin{tabular}{|l|l|l|}
+ \hline
+ \textbf{Tag} & \textbf{Preprocessor command} & \textbf{Remark} \\
+ \hline
+ \hline
+ \texttt{pp(cmd...)} & \texttt{cmd...} & Arbitrary
+ preprocessor command\footnote{The command must not contain newlines or parentheses.} \\
+ \hline
+ \texttt{camlp4o} & \texttt{camlp4o} & Original OCaml syntax \\
+ \hline
+ \texttt{camlp4r} & \texttt{camlp4r} & Revised OCaml syntax \\
+ \hline
+ \texttt{camlp4of} & \texttt{camlp4of} & Original OCaml syntax with extensions \\
+ \hline
+ \texttt{camlp4rf} & \texttt{camlp4rf} & Revised OCaml syntax with extensions \\
+ \hline
+ \end{tabular}
+\end{center}
+%***)
+%(*** Debugging and profiling
+\subsection{Debugging byte code and profiling native code}
+The preferred way of compiling code suitable for debugging with \texttt{ocamldebug} or
+profiling native code with \texttt{ocamlprof} is to use the appropriate target
+extensions, \texttt{.d.byte} for debugging or \texttt{.p.native}.
+
+Another way is to add use the \texttt{debug} or \texttt{profile} tags.
+Note that these tags must be applied at the compilation and linking stages.
+Hence you must either use \texttt{-tag debug} or \texttt{-tag profile}
+on the command line, or add a
+\begin{verbatim}
+true: debug
+\end{verbatim}
+line to your \texttt{\_tags} file.
+Please note that the bytecode profiler works in a wholly different way
+and is not supported by \ocb.
+%***)
+%(*** The display line
+\subsection{The display line}
+Provided \ocb runs in a terminal under a POSIX environment, it will
+display a sophisticated progress-indicator line that graciously interacts
+with the output of subcommands. This line looks like this:
+\begin{verbatim}
+00:00:02 210 (180 ) main.cmx ONbp--il /
+\end{verbatim}
+Here, 00:00:02 is the elapsed time in hour:minute:second format since \ocb has
+been invoked; 210 is the number of external commands, typically calls to the
+compiler or the like, that may or may not have been invoked; 180 is the number
+of external commands that have not been invoked since their result is already
+in the build directory; \texttt{main.cmx} is the name of the last target built;
+\texttt{ONbp--il} is a short string that describes the tags that have been
+encountered and the slash at the end is a frame from a rotating ticker. Hence,
+the display line has the following structure:
+\begin{verbatim}
+HH:MM:SS JOBS (CACHED) PATHNAME TAGS TICKER
+\end{verbatim}
+
+The tag string is made of 8 indicators which each monitor a tag. These tags
+are \texttt{ocaml}, \texttt{native}, \texttt{byte}, \texttt{program},
+\texttt{pp}, \texttt{debug}, \texttt{interf} and \texttt{link}. Initially,
+each indicator displays a dash \texttt{-}. If the current target has the
+monitored tag, then the indicator displays the corresponding character
+(see table \ref{tab:tag-chars}) in uppercase. Otherwise, it displays that
+character in lowercase. This allows you to see the set of tags that have
+been applied to files in your project during the current invocation of \ocb.
+
+Hence the tag string \texttt{ONbp--il} means that the current target
+\texttt{main.cmx} has the tags \texttt{ocaml} and \texttt{native}, and that
+the tags \texttt{ocaml}, \texttt{native}, \texttt{byte}, \texttt{program},
+\texttt{interf} and \texttt{link} have already been seen.
+
+\begin{table}
+ \begin{center}
+ \begin{tabular}{|l|c|}
+ \hline
+ \textbf{Tag} & \textbf{Display character} \\
+ \hline
+ \hline
+ ocaml & O \\
+ \hline
+ native & N \\
+ \hline
+ byte & B \\
+ \hline
+ program & P \\
+ \hline
+ pp & R \\
+ \hline
+ debug & D \\
+ \hline
+ interf & I \\
+ \hline
+ link & L \\
+ \hline
+ \end{tabular}
+ \end{center}
+ \caption{\label{tab:tag-chars} Relation between the characters displayed in
+ the tag string and the tags.}
+\end{table}
+%***)
+%(*** ocamllex, ocamlyacc and menhir
+\subsection{\texttt{ocamllex}, \texttt{ocamlyacc} and \texttt{menhir}}
+\ocb knows how to run the standard lexer and parser generator tools
+\texttt{ocamllex} and \texttt{ocamlyacc} when your files have the
+standard \texttt{.mll} and \texttt{.mly} extensions. If you want to
+use \texttt{menhir} instead of \texttt{ocamlyacc}, you can either
+launch \ocb with the \texttt{-use-menhir} option or add a
+\begin{verbatim}
+true: use_menhir
+\end{verbatim}
+line to your \texttt{\_tags} file. Note that there is currently no way
+of using \texttt{menhir} and \texttt{ocamlyacc} in the same execution
+of \ocb.
+%***)
+%(*** Changing the compilers
+\subsection{Changing the compilers or tools}
+As \ocb is part of your OCaml distribution, it knows if it can call the
+native compilers and tools (\texttt{ocamlc.opt}, \texttt{ocamlopt.opt}...)
+or not. However you may want \ocb to use another \texttt{ocaml} compiler
+for different reasons (such as cross-compiling or using a wrapper such as
+\texttt{ocamlfind}). Here is the list of relevant options:
+\begin{itemize}
+ \item \texttt{-ocamlc <command>}
+ \item \texttt{-ocamlopt <command>}
+ \item \texttt{-ocamldep <command>}
+ \item \texttt{-ocamlyacc <command>}
+ \item \texttt{-menhir <command>}
+ \item \texttt{-ocamllex <command>}
+ \item \texttt{-ocamlrun <command>}
+\end{itemize}
+
+%***)
+\subsection{Writing a \texttt{myocamlbuild.ml} plugin}
+%(*** Interaction with version control systems
+\subsection{Interaction with version control systems}
+Here are tips for configuring your version control system to ignore the files
+and directories generated by \ocb.
+
+The directory \texttt{\_build}, the file \texttt{\_log} and any symbolic links
+pointing into \texttt{\_build} should be ignored.
+To do this, you must add the following ignore patterns to your version
+control system's ignore set:
+\begin{verbatim}
+_log
+_build
+*.native
+*.byte
+*.d.native
+*.p.byte
+\end{verbatim}
+
+For CVS, add the above lines to the \texttt{.cvsignore} file.
+For Subversion (SVN), type \texttt{svn propedit svn:ignore .} and add the
+above lines.
+%***)
+%(*** A shell script for driving it all?
+\subsection{A shell script for driving it all?}
+{\em To shell or to make ?}
+Traditionally, makefiles have two major functions. The first one
+is the dependency-ordering, rule-matching logic used for compiling.
+The second one is as a dispatcher for various actions defined using
+phony targets with shell script actions. These actions include cleaning,
+cleaning really well, archiving, uploading and so on. Their characteristic
+is that they rely little or not on the building process -- they either need
+the building to have been completed, or they don't need anything.
+As \texttt{/bin/sh} scripts have been here for three to four decades and are
+not going anywhere, why not replace that functionality of makefiles with a
+shell script ? We have thought of three bad reasons:
+\begin{itemize}
+ \item Typing \texttt{make} to compile is now an automatism,
+ \item We need to share variable definitions between rules and actions,
+ \item Escaping already way too special-character-sensitive shell code with
+ invisible tabs and backslashes is a dangerously fun game.
+\end{itemize}
+We also have bad reasons for not using an OCaml script to drive everything:
+\begin{itemize}
+ \item \texttt{Sys.command} calls the \texttt{/bin/sh} anyway,
+ \item Shell scripts can execute partial commands or commands with badly formed arguments.
+ \item Shell scripts are more concise for expressing... shell scripts.
+\end{itemize}
+Anyway you are of course free to use a makefile or an OCaml script to call ocamlbuild.
+Here is an example shell driver script:
+\begin{verbatim}
+#!/bin/sh
+
+set -e
+
+TARGET=epoch
+FLAGS="-libs unix,nums"
+OCAMLBUILD=ocamlbuild
+
+ocb()
+{
+ $OCAMLBUILD $FLAGS $*
+}
+
+rule() {
+ case $1 in
+ clean) ocb -clean;;
+ native) ocb $TARGET.native;;
+ byte) ocb $TARGET.byte;;
+ all) ocb $TARGET.native $TARGET.byte;;
+ depend) echo "Not needed.";;
+ *) echo "Unknown action $1";;
+ esac;
+}
+
+if [ $# -eq 0 ]; then
+ rule all
+else
+ while [ $# -gt 0 ]; do
+ rule $1;
+ shift
+ done
+fi
+\end{verbatim}
+%***)
+\subsection{Common errors}
+%***)
+\appendix
+%(*** Default rules
+\section{Default rules}
+\begin{center}
+\small
+\begin{tabular}{|l|l|p{5cm}|}
+ \hline
+ \textbf{Tags} & \textbf{Dependencies} & \textbf{Targets} \\
+ \hline
+ \hline
+ & \%.itarget & \%.otarget \\
+ \hline
+ ocaml & \%.mli \%.mli.depends & \%.cmi \\
+ \hline
+ byte, debug, ocaml & \%.mlpack \%.cmi & \%.d.cmo \\
+ \hline
+ byte, ocaml & \%.mlpack & \%.cmo \%.cmi \\
+ \hline
+ byte, ocaml & \%.mli \%.ml \%.ml.depends \%.cmi & \%.d.cmo \\
+ \hline
+ byte, ocaml & \%.mli \%.ml \%.ml.depends \%.cmi & \%.cmo \\
+ \hline
+ native, ocaml, profile & \%.mlpack \%.cmi & \%.p.cmx \%.p.o \\
+ \hline
+ native, ocaml & \%.mlpack \%.cmi & \%.cmx \%.o \\
+ \hline
+ native, ocaml, profile & \%.ml \%.ml.depends \%.cmi & \%.p.cmx \%.p.o \\
+ \hline
+ native, ocaml & \%.ml \%.ml.depends \%.cmi & \%.cmx \%.o \\
+ \hline
+ debug, ocaml & \%.ml \%.ml.depends \%.cmi & \%.d.cmo \\
+ \hline
+ ocaml & \%.ml \%.ml.depends & \%.cmo \%.cmi \\
+ \hline
+ byte, debug, ocaml, program & \%.d.cmo & \%.d.byte \\
+ \hline
+ byte, ocaml, program & \%.cmo & \%.byte \\
+ \hline
+ native, ocaml, profile, program & \%.p.cmx \%.p.o & \%.p.native \\
+ \hline
+ native, ocaml, program & \%.cmx \%.o & \%.native \\
+ \hline
+ byte, debug, library, ocaml & \%.mllib & \%.d.cma \\
+ \hline
+ byte, library, ocaml & \%.mllib & \%.cma \\
+ \hline
+ byte, debug, library, ocaml & \%.d.cmo & \%.d.cma \\
+ \hline
+ byte, library, ocaml & \%.cmo & \%.cma \\
+ \hline
+ & lib\%(libname).clib & lib\%(libname).a dll\%(libname).so \\
+ \hline
+ & \%(path)/lib\%(libname).clib & \%(path)/lib\%(libname).a \%(path)/dll\%(libname).so \\
+ \hline
+ library, native, ocaml, profile & \%.mllib & \%.p.cmxa \%.p.a \\
+ \hline
+ library, native, ocaml & \%.mllib & \%.cmxa \%.a \\
+ \hline
+ library, native, ocaml, profile & \%.p.cmx \%.p.o & \%.p.cmxa \%.p.a \\
+ \hline
+ library, native, ocaml & \%.cmx \%.o & \%.cmxa \%.a \\
+ \hline
+ & \%.ml & \%.ml.depends \\
+ \hline
+ & \%.mli & \%.mli.depends \\
+ \hline
+ ocaml & \%.mll & \%.ml \\
+ \hline
+ doc, ocaml & \%.mli \%.mli.depends & \%.odoc \\
+ \hline
+ & \%.odocl & \%.docdir/index.html \\
+ \hline
+ ocaml & \%.mly & \%.ml \%.mli \\
+ \hline
+ & \%.c & \%.o \\
+ \hline
+ & \%.ml \%.ml.depends & \%.inferred.mli \\
+ \hline
+\end{tabular}
+\end{center}
+%***)
+\end{document}
diff --git a/ocamlbuild/misc/opentracer.ml b/ocamlbuild/misc/opentracer.ml
new file mode 100644
index 0000000000..1aa62b98ca
--- /dev/null
+++ b/ocamlbuild/misc/opentracer.ml
@@ -0,0 +1,101 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+open My_std
+
+module type TRACER = sig
+ (** Call the given command using the tracer, it returns the exit status. *)
+ val call : string -> string list -> StringSet.t * Unix.process_status
+end
+
+module Ktrace = struct
+ let process_line line (wait_a_string, set) =
+ let strings = Lexers.space_sep_strings (Lexing.from_string line) in
+ if wait_a_string then
+ match strings with
+ | [_; _; "NAMI"; file] -> false, StringSet.add file set
+ | _ -> failwith (Printf.sprintf "unexpected ktrace output line (%S)" line)
+ else
+ match strings with
+ | [_; _; "CALL"; fct] ->
+ (String.length fct > 5 && String.sub fct 0 5 = "open("), set
+ | _ -> false, set
+
+ let call cmd args =
+ let tmp = Filename.temp_file "ktrace" "out" in
+ match Unix.fork () with
+ | 0 -> Unix.execvp "ktrace" (Array.of_list("-d"::"-i"::"-t"::"nc"::"-f"::tmp::cmd::args))
+ | pid ->
+ let _, st = Unix.waitpid [] pid in
+ let ic = Unix.open_process_in (Printf.sprintf "kdump -f %s" (Filename.quote tmp)) in
+ let close () = ignore (Unix.close_process_in ic); Sys.remove tmp in
+ let set =
+ try
+ let rec loop acc =
+ match try Some (input_line ic) with End_of_file -> None with
+ | Some line -> loop (process_line line acc)
+ | None -> acc in
+ let _, set = loop (false, StringSet.empty) in
+ close ();
+ set
+ with e -> (close (); raise e)
+ in set, st
+
+end
+
+module Driver (T : TRACER) = struct
+ let usage () =
+ Printf.eprintf "Usage: %s [-a <authorized_file>]* <cmd> <args>*\n%!" Sys.argv.(0);
+ exit 2
+
+ let main () =
+ let log = "opentracer.log" in
+ let oc =
+ if sys_file_exists log then
+ open_out_gen [Open_wronly;Open_append;Open_text] 0 log
+ else
+ let oc = open_out log in
+ let () = output_string oc "---\n" in
+ oc in
+ let rec loop acc =
+ function
+ | "-a" :: file :: rest -> loop (StringSet.add file acc) rest
+ | "-a" :: _ -> usage ()
+ | "--" :: cmd :: args -> acc, cmd, args
+ | cmd :: args -> acc, cmd, args
+ | [] -> usage () in
+ let authorized_files, cmd, args =
+ loop StringSet.empty (List.tl (Array.to_list Sys.argv)) in
+ let opened_files, st = T.call cmd args in
+ let forbidden_files = StringSet.diff opened_files authorized_files in
+
+ if not (StringSet.is_empty forbidden_files) then begin
+ Printf.fprintf oc "- cmd: %s\n args:\n%!" cmd;
+ let pp = Printf.fprintf oc " - %s\n%!" in
+ List.iter pp args;
+ Printf.fprintf oc " forbidden_files:\n%!";
+ StringSet.iter pp forbidden_files;
+ end;
+ close_out oc;
+ match st with
+ | Unix.WEXITED st -> exit st
+ | Unix.WSIGNALED s | Unix.WSTOPPED s -> Unix.kill (Unix.getpid ()) s
+end
+
+let main =
+ (* match os with *)
+ (* | "macos" -> *)
+ let module M = Driver(Ktrace) in M.main
+ (* | "linux" -> *)
+ (* let module M = Driver(Strace) in M.main *)
+
+let () = main ()
diff --git a/ocamlbuild/my_std.ml b/ocamlbuild/my_std.ml
new file mode 100644
index 0000000000..9d3c0a97ce
--- /dev/null
+++ b/ocamlbuild/my_std.ml
@@ -0,0 +1,359 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open Format
+
+exception Exit_OK
+exception Exit_usage of string
+exception Exit_system_error of string
+exception Exit_with_code of int
+exception Exit_silently_with_code of int
+
+module Outcome = struct
+ type ('a,'b) t =
+ | Good of 'a
+ | Bad of 'b
+
+ let ignore_good =
+ function
+ | Good _ -> ()
+ | Bad e -> raise e
+
+ let good =
+ function
+ | Good x -> x
+ | Bad exn -> raise exn
+
+ let wrap f x =
+ try Good (f x) with e -> Bad e
+
+end
+
+let opt_print elt ppf =
+ function
+ | Some x -> fprintf ppf "@[<2>Some@ %a@]" elt x
+ | None -> pp_print_string ppf "None"
+
+open Format
+let ksbprintf g fmt =
+ let buff = Buffer.create 42 in
+ let f = formatter_of_buffer buff in
+ kfprintf (fun f -> (pp_print_flush f (); g (Buffer.contents buff))) f fmt
+let sbprintf fmt = ksbprintf (fun x -> x) fmt
+
+(** Some extensions of the standard library *)
+module Set = struct
+
+ module type OrderedTypePrintable = sig
+ include Set.OrderedType
+ val print : formatter -> t -> unit
+ end
+
+ module type S = sig
+ include Set.S
+ val find : (elt -> bool) -> t -> elt
+ val map : (elt -> elt) -> t -> t
+ val of_list : elt list -> t
+ val print : formatter -> t -> unit
+ end
+
+ module Make (M : OrderedTypePrintable) : S with type elt = M.t = struct
+ include Set.Make(M)
+ exception Found of elt
+ let find p set =
+ try
+ iter begin fun elt ->
+ if p elt then raise (Found elt)
+ end set; raise Not_found
+ with Found elt -> elt
+ let map f set = fold (fun x -> add (f x)) set empty
+ let of_list l = List.fold_right add l empty
+ let print f s =
+ let () = fprintf f "@[<hv0>@[<hv2>{.@ " in
+ let _ =
+ fold begin fun elt first ->
+ if not first then fprintf f ",@ ";
+ M.print f elt;
+ false
+ end s true in
+ fprintf f "@]@ .}@]"
+ end
+end
+
+module List = struct
+ include List
+ let print pp_elt f ls =
+ fprintf f "@[<2>[@ ";
+ let _ =
+ fold_left begin fun first elt ->
+ if not first then fprintf f ";@ ";
+ pp_elt f elt;
+ false
+ end true ls in
+ fprintf f "@ ]@]"
+
+ let filter_opt f xs =
+ List.fold_right begin fun x acc ->
+ match f x with
+ | Some x -> x :: acc
+ | None -> acc
+ end xs []
+
+ let union a b =
+ let rec self a b =
+ if a = [] then b else
+ match b with
+ | [] -> a
+ | x :: xs ->
+ if mem x a then self a xs
+ else self (x :: a) xs
+ in rev (self (rev a) b)
+end
+
+module String = struct
+ include String
+
+ let print f s = fprintf f "%S" s
+
+ let chomp s =
+ let ls = length s in
+ if ls = 0 then s
+ else if s.[ls-1] = '\n' then sub s 0 (ls - 1)
+ else s
+
+ let before s pos = sub s 0 pos
+ let after s pos = sub s pos (length s - pos)
+ let first_chars s n = sub s 0 n
+ let last_chars s n = sub s (length s - n) n
+
+ let rec eq_sub_strings s1 p1 s2 p2 len =
+ if len > 0 then s1.[p1] = s2.[p2] && eq_sub_strings s1 (p1+1) s2 (p2+1) (len-1)
+ else true
+
+ let rec contains_string s1 p1 s2 =
+ let ls1 = length s1 in
+ let ls2 = length s2 in
+ try let pos = index_from s1 p1 s2.[0] in
+ if ls1 - pos < ls2 then None
+ else if eq_sub_strings s1 pos s2 0 ls2 then
+ Some pos else contains_string s1 (pos + 1) s2
+ with Not_found -> None
+
+ let subst patt repl s =
+ let lpatt = length patt in
+ let lrepl = length repl in
+ let rec loop s from =
+ match contains_string s from patt with
+ | Some pos ->
+ loop (before s pos ^ repl ^ after s (pos + lpatt)) (pos + lrepl)
+ | None -> s
+ in loop s 0
+
+ let tr patt subst text =
+ let len = length text in
+ let text = copy text in
+ let rec loop pos =
+ if pos < len then begin
+ (if text.[pos] = patt then text.[pos] <- subst);
+ loop (pos + 1)
+ end
+ in loop 0; text
+
+ (*** is_prefix : is v a prefix of u ? *)
+ let is_prefix u v =
+ let m = String.length u
+ and n = String.length v
+ in
+ m <= n &&
+ let rec loop i = i = m or u.[i] = v.[i] && loop (i + 1) in
+ loop 0
+ (* ***)
+
+ (*** is_suffix : is v a suffix of u ? *)
+ let is_suffix u v =
+ let m = String.length u
+ and n = String.length v
+ in
+ n <= m &&
+ let rec loop i = i = n or u.[m - 1 - i] = v.[n - 1 - i] && loop (i + 1) in
+ loop 0
+ (* ***)
+
+ let rev s =
+ let sl = String.length s in
+ let s' = String.create sl in
+ for i = 0 to sl - 1 do
+ s'.[i] <- s.[sl - i - 1]
+ done;
+ s';;
+end
+
+module StringSet = Set.Make(String)
+
+let sys_readdir, reset_readdir_cache, reset_readdir_cache_for =
+ let cache = Hashtbl.create 103 in
+ let sys_readdir dir =
+ try Hashtbl.find cache dir with Not_found ->
+ let res = Outcome.wrap Sys.readdir dir in
+ (Hashtbl.add cache dir res; res)
+ and reset_readdir_cache () =
+ Hashtbl.clear cache
+ and reset_readdir_cache_for dir =
+ Hashtbl.remove cache dir in
+ (sys_readdir, reset_readdir_cache, reset_readdir_cache_for)
+
+let sys_file_exists x =
+ let dirname = Filename.dirname x in
+ let basename = Filename.basename x in
+ if basename = Filename.current_dir_name then true else
+ match sys_readdir dirname with
+ | Outcome.Bad _ -> false
+ | Outcome.Good a -> try Array.iter (fun x -> if x = basename then raise Exit) a; false with Exit -> true
+
+let sys_command =
+ match Sys.os_type with
+ | "Win32" -> fun cmd ->
+ let cmd = "bash -c "^Filename.quote cmd in
+ (* FIXME fix Filename.quote for windows *)
+ let cmd = String.subst "\"&\"\"&\"" "&&" cmd in
+ Sys.command cmd
+ | _ -> Sys.command
+
+(* FIXME warning fix and use Filename.concat *)
+let filename_concat x y =
+ if x = Filename.current_dir_name || x = "" then y else
+ if y = "" && x.[String.length x - 1] = '/' then x
+ else x ^ "/" ^ y
+
+(* let reslash =
+ match Sys.os_type with
+ | "Win32" -> tr '\\' '/'
+ | _ -> (fun x -> x) *)
+
+open Format
+
+let invalid_arg' fmt = ksbprintf invalid_arg fmt
+
+let the = function Some x -> x | None -> invalid_arg "the: expect Some not None"
+
+let getenv ?default var =
+ try Sys.getenv var
+ with Not_found ->
+ match default with
+ | Some x -> x
+ | None -> failwith (sprintf "This command must have %S in his environment" var);;
+
+let with_input_file ?(bin=false) x f =
+ let ic = (if bin then open_in_bin else open_in) x in
+ try let res = f ic in close_in ic; res with e -> (close_in ic; raise e)
+
+let with_output_file ?(bin=false) x f =
+ reset_readdir_cache_for (Filename.dirname x);
+ let oc = (if bin then open_out_bin else open_out) x in
+ try let res = f oc in close_out oc; res with e -> (close_out oc; raise e)
+
+let read_file x =
+ with_input_file ~bin:true x begin fun ic ->
+ let len = in_channel_length ic in
+ let buf = String.create len in
+ let () = really_input ic buf 0 len in
+ buf
+ end
+
+let copy_chan ic oc =
+ let m = in_channel_length ic in
+ let m = (m lsr 12) lsl 12 in
+ let m = max 16384 (min 16777216 m) in
+ let buf = String.create m in
+ let rec loop () =
+ let len = input ic buf 0 m in
+ if len > 0 then begin
+ output oc buf 0 len;
+ loop ()
+ end
+ in loop ()
+
+let copy_file src dest =
+ reset_readdir_cache_for (Filename.dirname dest);
+ with_input_file ~bin:true src begin fun ic ->
+ with_output_file ~bin:true dest begin fun oc ->
+ copy_chan ic oc
+ end
+ end
+
+let ( !* ) = Lazy.force
+
+let ( @:= ) ref list = ref := !ref @ list
+
+let print_string_list = List.print String.print
+
+module Digest = struct
+ include Digest
+(* USEFUL FOR DIGEST DEBUGING
+ let digest_log_hash = Hashtbl.create 103;;
+ let digest_log = "digest.log";;
+ let digest_log_oc = open_out_gen [Open_append;Open_wronly;Open_text;Open_creat] 0o644 digest_log;;
+ let my_to_hex x = to_hex x ^ ";";;
+ if sys_file_exists digest_log then
+ with_input_file digest_log begin fun ic ->
+ try while true do
+ let l = input_line ic in
+ Scanf.sscanf l "%S: %S" (Hashtbl.replace digest_log_hash)
+ done with End_of_file -> ()
+ end;;
+ let string s =
+ let res = my_to_hex (string s) in
+ if try let x = Hashtbl.find digest_log_hash res in s <> x with Not_found -> true then begin
+ Hashtbl.replace digest_log_hash res s;
+ Printf.fprintf digest_log_oc "%S: %S\n%!" res s
+ end;
+ res
+ let file f = my_to_hex (file f)
+ let to_hex x = x
+*)
+
+ let digest_cache = Hashtbl.create 103
+ let reset_digest_cache () = Hashtbl.clear digest_cache
+ let reset_digest_cache_for file = Hashtbl.remove digest_cache file
+ let file f =
+ try Hashtbl.find digest_cache f
+ with Not_found ->
+ let res = file f in
+ (Hashtbl.add digest_cache f res; res)
+end
+
+let reset_filesys_cache () =
+ Digest.reset_digest_cache ();
+ reset_readdir_cache ()
+
+let reset_filesys_cache_for_file file =
+ Digest.reset_digest_cache_for file;
+ reset_readdir_cache_for (Filename.dirname file)
+
+let sys_remove x =
+ reset_filesys_cache_for_file x;
+ Sys.remove x
+
+let with_temp_file pre suf fct =
+ let tmp = Filename.temp_file pre suf in
+ (* Sys.remove is used instead of sys_remove since we know that the tempfile is not that important *)
+ try let res = fct tmp in Sys.remove tmp; res
+ with e -> (Sys.remove tmp; raise e)
+
+let memo f =
+ let cache = Hashtbl.create 103 in
+ fun x ->
+ try Hashtbl.find cache x
+ with Not_found ->
+ let res = f x in
+ (Hashtbl.add cache x res; res)
diff --git a/ocamlbuild/my_std.mli b/ocamlbuild/my_std.mli
new file mode 100644
index 0000000000..9281f471e9
--- /dev/null
+++ b/ocamlbuild/my_std.mli
@@ -0,0 +1,65 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* My_std *)
+
+(** Generic utility functions, and system-independent glue. *)
+
+exception Exit_OK
+exception Exit_usage of string
+exception Exit_system_error of string
+exception Exit_with_code of int
+exception Exit_silently_with_code of int
+
+module Outcome : Signatures.OUTCOME
+
+open Format
+
+val ksbprintf : (string -> 'a) -> ('b, formatter, unit, 'a) format4 -> 'b
+val sbprintf : ('a, formatter, unit, string) format4 -> 'a
+
+module Set : sig
+ module type OrderedTypePrintable = Signatures.OrderedTypePrintable
+ module type S = Signatures.SET
+ module Make (M : OrderedTypePrintable) : S with type elt = M.t
+end
+
+module List : Signatures.LIST
+
+module String : Signatures.STRING
+
+module Digest : sig
+ type t = string
+ val string : string -> t
+ val substring : string -> int -> int -> t
+ external channel : in_channel -> int -> t = "caml_md5_chan"
+ val file : string -> t
+ val output : out_channel -> t -> unit
+ val input : in_channel -> t
+ val to_hex : t -> string
+end
+
+module StringSet : Set.S with type elt = String.t
+
+val sys_readdir : string -> (string array, exn) Outcome.t
+val sys_remove : string -> unit
+val reset_readdir_cache : unit -> unit
+val reset_filesys_cache : unit -> unit
+val reset_filesys_cache_for_file : string -> unit
+val sys_file_exists : string -> bool
+val sys_command : string -> int
+val filename_concat : string -> string -> string
+
+val invalid_arg' : ('a, formatter, unit, 'b) format4 -> 'a
+
+include Signatures.MISC
diff --git a/ocamlbuild/my_unix.ml b/ocamlbuild/my_unix.ml
new file mode 100644
index 0000000000..0e9514444d
--- /dev/null
+++ b/ocamlbuild/my_unix.ml
@@ -0,0 +1,139 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Format
+
+type file_kind =
+| FK_dir
+| FK_file
+| FK_link
+| FK_other
+
+type stats =
+ {
+ stat_file_kind : file_kind;
+ stat_key : string
+ }
+
+type implem =
+ {
+ mutable is_degraded : bool;
+ mutable is_link : string -> bool;
+ mutable run_and_open : 'a . string -> (in_channel -> 'a) -> 'a;
+ mutable readlink : string -> string;
+ mutable execute_many : ?max_jobs:int ->
+ ?ticker:(unit -> unit) ->
+ ?period:float ->
+ ?display:((out_channel -> unit) -> unit) ->
+ ((string * (unit -> unit)) list list) ->
+ (bool list * exn) option;
+ mutable report_error : Format.formatter -> exn -> unit;
+ mutable at_exit_once : (unit -> unit) -> unit;
+ mutable gettimeofday : unit -> float;
+ mutable stdout_isatty : unit -> bool;
+ mutable stat : string -> stats;
+ mutable lstat : string -> stats;
+ }
+
+let is_degraded = true
+
+let stat f =
+ { stat_key = f;
+ stat_file_kind =
+ try let _ = with_input_file f input_char in FK_file
+ with
+ | Sys_error "Is a directory" -> FK_dir
+ | End_of_file -> FK_file }
+
+let run_and_open s kont =
+ with_temp_file "ocamlbuild" "out" begin fun tmp ->
+ let s = sprintf "%s > '%s'" s tmp in
+ let st = sys_command s in
+ if st <> 0 then failwith (Printf.sprintf "Error while running: %s" s);
+ with_input_file tmp kont
+ end
+
+exception Not_a_link
+exception No_such_file
+exception Link_to_directories_not_supported
+
+let readlinkcmd =
+ let cache = Hashtbl.create 32 in
+ fun x ->
+ try Hashtbl.find cache x
+ with Not_found ->
+ run_and_open (Printf.sprintf "readlink %s" (Filename.quote x)) begin fun ic ->
+ let y = String.chomp (input_line ic) in
+ Hashtbl.replace cache x y; y
+ end
+
+let rec readlink x =
+ if sys_file_exists x then
+ try
+ let y = readlinkcmd x in
+ if (lstat y).stat_file_kind = FK_dir then raise Link_to_directories_not_supported else y
+ with Failure(_) -> raise Not_a_link
+ else raise No_such_file
+
+and is_link x =
+ try ignore(readlink x); true with
+ | No_such_file | Not_a_link -> false
+
+and lstat x =
+ if is_link x then { stat_key = x; stat_file_kind = FK_link } else stat x
+
+let implem =
+ {
+ is_degraded = true;
+
+ stat = stat;
+ lstat = lstat;
+ readlink = readlink;
+ is_link = is_link;
+ run_and_open = run_and_open;
+
+ (* at_exit_once is at_exit in the degraded mode since fork is not accessible in this mode *)
+ at_exit_once = at_exit;
+ report_error = (fun _ -> raise);
+ gettimeofday = (fun () -> assert false);
+ stdout_isatty = (fun () -> false);
+ execute_many = (fun ?max_jobs:(_) ?ticker:(_) ?period:(_) ?display:(_) _ -> assert false)
+ }
+
+let is_degraded = lazy implem.is_degraded
+let stat x = implem.stat x
+let lstat x = implem.lstat x
+let readlink x = implem.readlink x
+let is_link x = implem.is_link x
+let run_and_open x = implem.run_and_open x
+let at_exit_once x = implem.at_exit_once x
+let report_error x = implem.report_error x
+let gettimeofday x = implem.gettimeofday x
+let stdout_isatty x = implem.stdout_isatty x
+let execute_many ?max_jobs = implem.execute_many ?max_jobs
+
+let run_and_read cmd =
+ let bufsiz = 2048 in
+ let buf = String.create bufsiz in
+ let totalbuf = Buffer.create 4096 in
+ implem.run_and_open cmd begin fun ic ->
+ let rec loop pos =
+ let len = input ic buf 0 bufsiz in
+ if len > 0 then begin
+ Buffer.add_substring totalbuf buf 0 len;
+ loop (pos + len)
+ end
+ in loop 0; Buffer.contents totalbuf
+ end
+
diff --git a/ocamlbuild/my_unix.mli b/ocamlbuild/my_unix.mli
new file mode 100644
index 0000000000..5233415d42
--- /dev/null
+++ b/ocamlbuild/my_unix.mli
@@ -0,0 +1,73 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+type file_kind =
+| FK_dir
+| FK_file
+| FK_link
+| FK_other
+
+type stats =
+ {
+ stat_file_kind : file_kind;
+ stat_key : string
+ }
+
+val is_degraded : bool Lazy.t
+
+val is_link : string -> bool
+val run_and_open : string -> (in_channel -> 'a) -> 'a
+val readlink : string -> string
+val run_and_read : string -> string
+
+(** See [Executor.execute] *)
+val execute_many :
+ ?max_jobs:int ->
+ ?ticker:(unit -> unit) ->
+ ?period:float ->
+ ?display:((out_channel -> unit) -> unit) ->
+ ((string * (unit -> unit)) list list) ->
+ (bool list * exn) option
+
+val report_error : Format.formatter -> exn -> unit
+val at_exit_once : (unit -> unit) -> unit
+
+val gettimeofday : unit -> float
+
+val stdout_isatty : unit -> bool
+
+val stat : string -> stats
+val lstat : string -> stats
+
+(** internal usage only *)
+type implem =
+ {
+ mutable is_degraded : bool;
+ mutable is_link : string -> bool;
+ mutable run_and_open : 'a . string -> (in_channel -> 'a) -> 'a;
+ mutable readlink : string -> string;
+ mutable execute_many : ?max_jobs:int ->
+ ?ticker:(unit -> unit) ->
+ ?period:float ->
+ ?display:((out_channel -> unit) -> unit) ->
+ ((string * (unit -> unit)) list list) ->
+ (bool list * exn) option;
+ mutable report_error : Format.formatter -> exn -> unit;
+ mutable at_exit_once : (unit -> unit) -> unit;
+ mutable gettimeofday : unit -> float;
+ mutable stdout_isatty : unit -> bool;
+ mutable stat : string -> stats;
+ mutable lstat : string -> stats;
+ }
+
+val implem : implem
diff --git a/ocamlbuild/my_unix_with_unix.ml b/ocamlbuild/my_unix_with_unix.ml
new file mode 100644
index 0000000000..1c0dd1e6fa
--- /dev/null
+++ b/ocamlbuild/my_unix_with_unix.ml
@@ -0,0 +1,75 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open Format
+open Ocamlbuild_pack
+open My_unix
+
+let report_error f =
+ function
+ | Unix.Unix_error(err, fun_name, arg) ->
+ fprintf f "%s: %S failed" Sys.argv.(0) fun_name;
+ if String.length arg > 0 then
+ fprintf f " on %S" arg;
+ fprintf f ": %s" (Unix.error_message err)
+ | exn -> raise exn
+
+let mkstat unix_stat x =
+ let st =
+ try unix_stat x
+ with Unix.Unix_error _ as e -> raise (Sys_error (My_std.sbprintf "%a" report_error e))
+ in
+ { stat_key = sprintf "(%d,%d)" st.Unix.st_dev st.Unix.st_ino;
+ stat_file_kind =
+ match st.Unix.st_kind with
+ | Unix.S_LNK -> FK_link
+ | Unix.S_DIR -> FK_dir
+ | Unix.S_CHR | Unix.S_BLK | Unix.S_FIFO | Unix.S_SOCK -> FK_other
+ | Unix.S_REG -> FK_file }
+
+let is_link s = (Unix.lstat s).Unix.st_kind = Unix.S_LNK
+
+let at_exit_once callback =
+ let pid = Unix.getpid () in
+ at_exit begin fun () ->
+ if pid = Unix.getpid () then callback ()
+ end
+
+let run_and_open s kont =
+ let ic = Unix.open_process_in s in
+ let close () =
+ match Unix.close_process_in ic with
+ | Unix.WEXITED 0 -> ()
+ | Unix.WEXITED _ | Unix.WSIGNALED _ | Unix.WSTOPPED _ ->
+ failwith (Printf.sprintf "Error while running: %s" s) in
+ try
+ let res = kont ic in close (); res
+ with e -> (close (); raise e)
+
+let stdout_isatty () =
+ (* 3.10
+ Unix.isatty Unix.stdout *)
+ true
+
+let setup () =
+ implem.is_degraded <- false;
+ implem.stdout_isatty <- stdout_isatty;
+ implem.gettimeofday <- Unix.gettimeofday;
+ implem.report_error <- report_error;
+ implem.execute_many <- Executor.execute;
+ implem.readlink <- Unix.readlink;
+ implem.run_and_open <- run_and_open;
+ implem.at_exit_once <- at_exit_once;
+ implem.is_link <- is_link;
+ implem.stat <- mkstat Unix.stat;
+ implem.lstat <- mkstat Unix.lstat;
diff --git a/ocamlbuild/my_unix_with_unix.mli b/ocamlbuild/my_unix_with_unix.mli
new file mode 100644
index 0000000000..1d87e4deed
--- /dev/null
+++ b/ocamlbuild/my_unix_with_unix.mli
@@ -0,0 +1,14 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+val setup : unit -> unit
diff --git a/ocamlbuild/ocaml_arch.ml b/ocamlbuild/ocaml_arch.ml
new file mode 100644
index 0000000000..c7627383f8
--- /dev/null
+++ b/ocamlbuild/ocaml_arch.ml
@@ -0,0 +1,135 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Command
+open Pathname.Operators
+
+type 'a arch =
+ | Arch_dir of string * 'a * 'a arch list
+ | Arch_dir_pack of string * 'a * 'a arch list
+ | Arch_file of string * 'a
+
+let dir name contents = Arch_dir(name, (), contents)
+let dir_pack name contents = Arch_dir_pack(name, (), contents)
+let file name = Arch_file(name, ())
+
+type info =
+{
+ current_path : string;
+ include_dirs : string list;
+ for_pack : string;
+}
+
+let join_pack parent base =
+ if parent = "" then base else parent ^ "." ^ base
+
+let annotate arch =
+ let rec self arch acc =
+ match arch with
+ | Arch_dir_pack(name, _, contents) ->
+ let acc = { (acc) with for_pack = join_pack acc.for_pack name } in
+ let (_, _, i, new_contents) = self_contents name contents acc in
+ ([], Arch_dir_pack(name, i, List.rev new_contents))
+ | Arch_dir(name, _, contents) ->
+ let (current_path, include_dirs, i, new_contents) = self_contents name contents acc in
+ (current_path :: include_dirs, Arch_dir(name, i, List.rev new_contents))
+ | Arch_file(name, _) ->
+ ([], Arch_file(name, acc))
+ and self_contents name contents acc =
+ let current_path = acc.current_path/name in
+ let include_dirs = if current_path = "" then acc.include_dirs else current_path :: acc.include_dirs in
+ let i = { (acc) with current_path = current_path; include_dirs = include_dirs } in
+ let (include_dirs, new_contents) =
+ List.fold_left begin fun (include_dirs, new_contents) x ->
+ let j = { (i) with include_dirs = include_dirs @ i.include_dirs } in
+ let (include_dirs', x') = self x j in
+ (include_dirs @ include_dirs', x' :: new_contents)
+ end ([], []) contents in
+ (current_path, include_dirs, i, new_contents) in
+ let init = { current_path = ""; include_dirs = []; for_pack = "" } in
+ snd (self arch init)
+
+let rec print print_info f =
+ let rec print_contents f =
+ function
+ | [] -> ()
+ | x :: xs -> Format.fprintf f "@ %a%a" (print print_info) x print_contents xs in
+ function
+ | Arch_dir(name, info, contents) ->
+ Format.fprintf f "@[<v2>dir %S%a%a@]" name print_info info print_contents contents
+ | Arch_dir_pack(name, info, contents) ->
+ Format.fprintf f "@[<v2>dir_pack %S%a%a@]" name print_info info print_contents contents
+ | Arch_file(name, info) ->
+ Format.fprintf f "@[<2>file %S%a@]" name print_info info
+
+let print_include_dirs = List.print String.print
+
+let print_info f i =
+ Format.fprintf f "@ @[<v2>{ @[<2>current_path =@ %S@];@\
+ \ @[<2>include_dirs =@ %a@];@\
+ \ @[<2>for_pack =@ %S@] }@]"
+ i.current_path print_include_dirs i.include_dirs i.for_pack
+
+let rec iter_info f =
+ function
+ | Arch_dir_pack(_, i, xs) | Arch_dir(_, i, xs) ->
+ f i; List.iter (iter_info f) xs
+ | Arch_file(_, i) -> f i
+
+let rec fold_info f arch acc =
+ match arch with
+ | Arch_dir_pack(_, i, xs) | Arch_dir(_, i, xs) ->
+ List.fold_right (fold_info f) xs (f i acc)
+ | Arch_file(_, i) -> f i acc
+
+module SS = Set.Make(String)
+
+let iter_include_dirs arch =
+ let set = fold_info (fun i -> List.fold_right SS.add i.include_dirs) arch SS.empty in
+ fun f -> SS.iter f set
+
+let forpack_flags_of_pathname = ref (fun _ -> N)
+
+let print_table print_value f table =
+ Format.fprintf f "@[<hv0>{:@[<hv0>";
+ Hashtbl.iter begin fun k v ->
+ if k <> "" then
+ Format.fprintf f "@ @[<2>%S =>@ %a@];" k print_value v;
+ end table;
+ Format.fprintf f "@]@ :}@]"
+
+let print_tables f (include_dirs_table, for_pack_table) =
+ Format.fprintf f "@[<2>@[<2>include_dirs_table:@ %a@];@ @[<2>for_pack_table: %a@]@]"
+ (print_table (List.print String.print)) include_dirs_table
+ (print_table String.print) for_pack_table
+
+let mk_tables arch =
+ let include_dirs_table = Hashtbl.create 17
+ and for_pack_table = Hashtbl.create 17 in
+ iter_info begin fun i ->
+ Hashtbl.replace include_dirs_table i.current_path i.include_dirs;
+ Hashtbl.replace for_pack_table i.current_path i.for_pack
+ end arch;
+ let previous_forpack_flags_of_pathname = !forpack_flags_of_pathname in
+ forpack_flags_of_pathname := begin fun m ->
+ let m' = Pathname.dirname m in
+ try
+ let for_pack = Hashtbl.find for_pack_table m' in
+ if for_pack = "" then N else S[A"-for-pack"; A for_pack]
+ with Not_found -> previous_forpack_flags_of_pathname m
+ end;
+ (* Format.eprintf "@[<2>%a@]@." print_tables (include_dirs_table, for_pack_table); *)
+ (include_dirs_table, for_pack_table)
+
+let forpack_flags_of_pathname m = !forpack_flags_of_pathname m
diff --git a/ocamlbuild/ocaml_arch.mli b/ocamlbuild/ocaml_arch.mli
new file mode 100644
index 0000000000..f72783567c
--- /dev/null
+++ b/ocamlbuild/ocaml_arch.mli
@@ -0,0 +1,16 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+
+include Signatures.ARCH
+val forpack_flags_of_pathname : string -> Command.spec
diff --git a/ocamlbuild/ocaml_compiler.ml b/ocamlbuild/ocaml_compiler.ml
new file mode 100644
index 0000000000..f536af8d11
--- /dev/null
+++ b/ocamlbuild/ocaml_compiler.ml
@@ -0,0 +1,315 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Format
+open Log
+open Pathname.Operators
+open Tools
+open Command
+open Rule
+open Tags.Operators
+open Ocaml_utils
+open Rule.Common_commands
+open Outcome
+
+let forpack_flags arg tags =
+ if Tags.mem "pack" tags then
+ Ocaml_arch.forpack_flags_of_pathname arg
+ else N
+
+let ocamlc_c tags arg out =
+ let tags = tags++"ocaml"++"byte" in
+ Cmd (S [!Options.ocamlc; A"-c"; T(tags++"compile");
+ ocaml_ppflags tags; flags_of_pathname arg;
+ ocaml_include_flags arg; A"-o"; Px out; P arg])
+
+let ocamlc_link flag tags deps out =
+ Cmd (S [!Options.ocamlc; flag; T tags;
+ atomize_paths deps; flags_of_pathname out; A"-o"; Px out])
+
+let ocamlc_link_lib = ocamlc_link (A"-a")
+let ocamlc_link_prog = ocamlc_link N
+
+let ocamlmklib tags deps out =
+ Cmd (S [!Options.ocamlmklib; T tags;
+ atomize_paths deps; flags_of_pathname out; A"-o"; Px (Pathname.remove_extensions out)])
+
+let byte_lib_linker tags =
+ if Tags.mem "ocamlmklib" tags then
+ ocamlmklib tags
+ else
+ ocamlc_link_lib tags
+
+let byte_lib_linker_tags tags = tags++"ocaml"++"link"++"byte"++"library"
+
+let ocamlc_p tags deps out =
+ Cmd (S [!Options.ocamlc; A"-pack"; T tags;
+ atomize_paths deps; flags_of_pathname out; A"-o"; Px out])
+
+let ocamlopt_c tags arg out =
+ let tags = tags++"ocaml"++"native" in
+ Cmd (S [!Options.ocamlopt; A"-c"; Ocaml_arch.forpack_flags_of_pathname arg;
+ T(tags++"compile"); ocaml_ppflags tags; flags_of_pathname arg;
+ flags_of_pathname out; ocaml_include_flags arg;
+ A"-o"; Px out (* FIXME ocamlopt bug -o cannot be after the input file *); P arg])
+
+let ocamlopt_link flag tags deps out =
+ Cmd (S [!Options.ocamlopt; flag; forpack_flags out tags; T tags;
+ atomize_paths deps; flags_of_pathname out; A"-o"; Px out])
+
+let ocamlopt_link_lib = ocamlopt_link (A"-a")
+let ocamlopt_link_prog = ocamlopt_link N
+
+let ocamlopt_p tags deps out =
+ let include_flags = List.fold_right begin fun dep ->
+ ocaml_add_include_flag (Pathname.dirname dep)
+ end deps [] in
+ let cmi = cmi_of out and cmitmp = Pathname.update_extensions "cmitmp" out in
+ Seq[mv cmi cmitmp;
+ Cmd (S [!Options.ocamlopt; A"-pack"; forpack_flags out tags; T tags; S include_flags;
+ atomize_paths deps; flags_of_pathname out; (* FIXME: P (cmi_of out);*) A"-o"; Px out]);
+ cmp cmitmp cmi]
+
+let native_lib_linker tags =
+ if Tags.mem "ocamlmklib" tags then
+ ocamlmklib tags
+ else
+ ocamlopt_link_lib tags
+
+let native_lib_linker_tags tags = tags++"ocaml"++"link"++"native"++"library"
+
+let prepare_compile build ml =
+ let dir = Pathname.dirname ml in
+ let include_dirs = Pathname.include_dirs_of dir in
+ let modules = Ocamldep.module_dependencies_of ml in
+ let results =
+ build (List.map (fun x -> expand_module include_dirs x ["cmi"]) modules) in
+ List.iter2 begin fun name res ->
+ match res with
+ | Good _ -> ()
+ | Bad exn ->
+ if !Options.ignore_auto then
+ dprintf 3 "Warning: Failed to build the module \
+ %s requested by ocamldep" name
+ else raise exn
+ end modules results
+
+let byte_compile_ocaml_interf mli cmi env build =
+ let mli = env mli and cmi = env cmi in
+ prepare_compile build mli;
+ ocamlc_c (tags_of_pathname mli++"interf") mli cmi
+
+let byte_compile_ocaml_implem ?tag ml cmo env build =
+ let ml = env ml and cmo = env cmo in
+ prepare_compile build ml;
+ ocamlc_c (tags_of_pathname ml++"implem"+++tag) ml cmo
+
+let cache_prepare_link = Hashtbl.create 107
+let rec prepare_link tag cmx extensions build =
+ let key = (tag, cmx, extensions) in
+ let dir = Pathname.dirname cmx in
+ let include_dirs = Pathname.include_dirs_of dir in
+ if Hashtbl.mem cache_prepare_link key then () else
+ let () = Hashtbl.add cache_prepare_link key true in
+ let modules = List.map (fun x -> expand_module include_dirs x extensions)
+ (Ocamldep.module_dependencies_of (Pathname.update_extensions "ml" cmx)) in
+ List.iter begin function
+ | Good p -> prepare_link tag p extensions build
+ | Bad exn -> if not !Options.ignore_auto then raise exn
+ end (build modules)
+
+let native_compile_ocaml_implem ?tag ?(cmx_ext="cmx") ml env build =
+ let ml = env ml in
+ let cmi = Pathname.update_extensions "cmi" ml in
+ let cmx = Pathname.update_extensions cmx_ext ml in
+ prepare_link cmx cmi [cmx_ext; "cmi"] build;
+ ocamlopt_c (tags_of_pathname ml++"implem"+++tag) ml cmx
+
+let libs_of_use_lib tags =
+ Tags.fold begin fun tag acc ->
+ if String.is_prefix "use_" tag then
+ let lib = String.after tag 4 in
+ try let libpath, extern = Hashtbl.find info_libraries lib in
+ if extern then acc else libpath :: acc
+ with Not_found -> acc
+ else acc
+ end tags []
+
+let prepare_libs cma_ext a_ext out build =
+ let out_no_ext = Pathname.remove_extension out in
+ let libs1 = List.union (libraries_of out_no_ext) (libs_of_use_lib (tags_of_pathname out)) in
+ let () = dprintf 10 "prepare_libs: %S -> %a" out pp_l libs1 in
+ let libs = List.map (fun x -> x-.-cma_ext) libs1 in
+ let libs2 = List.map (fun lib -> [lib-.-a_ext]) libs1 in
+ List.iter ignore_good (build libs2); libs
+
+let library_index = Hashtbl.create 32
+let package_index = Hashtbl.create 32
+let hidden_packages = ref []
+
+let hide_package_contents package = hidden_packages := package :: !hidden_packages
+
+module Ocaml_dependencies_input = struct
+ let fold_dependencies = Resource.Cache.fold_dependencies
+ let fold_libraries f = Hashtbl.fold f library_index
+ let fold_packages f = Hashtbl.fold f package_index
+end
+module Ocaml_dependencies = Ocaml_dependencies.Make(Ocaml_dependencies_input)
+
+let caml_transitive_closure = Ocaml_dependencies.caml_transitive_closure
+
+let link_gen cmX_ext cma_ext a_ext extensions linker tagger cmX out env build =
+ let cmX = env cmX and out = env out in
+ let tags = tagger (tags_of_pathname out) in
+ let dyndeps = Rule.build_deps_of_tags build tags in
+ let cmi = Pathname.update_extensions "cmi" cmX in
+ prepare_link cmX cmi extensions build;
+ let libs = prepare_libs cma_ext a_ext out build in
+ let hidden_packages = List.map (fun x -> x-.-cmX_ext) !hidden_packages in
+ let deps =
+ caml_transitive_closure
+ ~caml_obj_ext:cmX_ext ~caml_lib_ext:cma_ext
+ ~used_libraries:libs ~hidden_packages (cmX :: dyndeps) in
+ let deps = (List.filter (fun l -> not (List.mem l deps)) libs) @ deps in
+ if deps = [] then failwith "Link list cannot be empty";
+ let () = dprintf 6 "link: %a -o %a" print_string_list deps Pathname.print out in
+ linker tags deps out
+
+let byte_link_gen = link_gen "cmo" "cma" "cma" ["cmo"; "cmi"]
+
+let byte_link = byte_link_gen ocamlc_link_prog
+ (fun tags -> tags++"ocaml"++"link"++"byte"++"program")
+
+let byte_library_link = byte_link_gen byte_lib_linker byte_lib_linker_tags
+
+let byte_debug_link_gen =
+ link_gen "d.cmo" "d.cma" "d.cma" ["d.cmo"; "cmi"]
+
+let byte_debug_link = byte_debug_link_gen ocamlc_link_prog
+ (fun tags -> tags++"ocaml"++"link"++"byte"++"debug"++"program")
+
+let byte_debug_library_link = byte_debug_link_gen byte_lib_linker
+ (fun tags -> byte_lib_linker_tags tags++"debug")
+
+let native_link_gen linker =
+ link_gen "cmx" "cmxa" !Options.ext_lib [!Options.ext_obj; "cmi"] linker
+
+let native_link x = native_link_gen ocamlopt_link_prog
+ (fun tags -> tags++"ocaml"++"link"++"native"++"program") x
+
+let native_library_link x =
+ native_link_gen native_lib_linker native_lib_linker_tags x
+
+let native_profile_link_gen linker =
+ link_gen "p.cmx" "p.cmxa" ("p" -.- !Options.ext_lib) ["p" -.- !Options.ext_obj; "cmi"] linker
+
+let native_profile_link x = native_profile_link_gen ocamlopt_link_prog
+ (fun tags -> tags++"ocaml"++"link"++"native"++"profile"++"program") x
+
+let native_profile_library_link x = native_profile_link_gen native_lib_linker
+ (fun tags -> native_lib_linker_tags tags++"profile") x
+
+let link_units table extensions cmX_ext cma_ext a_ext linker tagger contents_list cmX env build =
+ let cmX = env cmX in
+ let tags = tagger (tags_of_pathname cmX) in
+ let _ = Rule.build_deps_of_tags build tags in
+ let dir =
+ let dir1 = Pathname.remove_extensions cmX in
+ if Pathname.exists_in_source_dir dir1 then dir1
+ else Pathname.dirname cmX in
+ let include_dirs = Pathname.include_dirs_of dir in
+ let extension_keys = List.map fst extensions in
+ let libs = prepare_libs cma_ext a_ext cmX build in
+ let results =
+ build begin
+ List.map begin fun module_name ->
+ expand_module include_dirs module_name extension_keys
+ end contents_list
+ end in
+ let module_paths =
+ List.map begin function
+ | Good p ->
+ let extension_values = List.assoc (Pathname.get_extensions p) extensions in
+ List.iter begin fun ext ->
+ List.iter ignore_good (build [[Pathname.update_extensions ext p]])
+ end extension_values; p
+ | Bad exn -> raise exn
+ end results in
+ Hashtbl.replace table cmX module_paths;
+ let hidden_packages = List.map (fun x -> x-.-cmX_ext) !hidden_packages in
+ let deps =
+ caml_transitive_closure
+ ~caml_obj_ext:cmX_ext ~caml_lib_ext:cma_ext
+ ~hidden_packages ~pack_mode:true module_paths in
+ let full_contents = libs @ module_paths in
+ let deps = List.filter (fun x -> List.mem x full_contents) deps in
+ let deps = (List.filter (fun l -> not (List.mem l deps)) libs) @ deps in
+ linker tags deps cmX
+
+let link_modules = link_units library_index
+let pack_modules = link_units package_index
+
+let link_from_file link modules_file cmX env build =
+ let modules_file = env modules_file in
+ let contents_list = string_list_of_file modules_file in
+ link contents_list cmX env build
+
+let byte_library_link_modules =
+ link_modules [("cmo",[]); ("cmi",[])] "cmo" "cma" "cma" byte_lib_linker byte_lib_linker_tags
+
+let byte_library_link_mllib = link_from_file byte_library_link_modules
+
+let byte_debug_library_link_modules =
+ link_modules [("d.cmo",[]); ("cmi",[])] "d.cmo" "d.cma" "d.cma" byte_lib_linker
+ (fun tags -> byte_lib_linker_tags tags++"debug")
+
+let byte_debug_library_link_mllib = link_from_file byte_debug_library_link_modules
+
+let byte_pack_modules =
+ pack_modules [("cmo",["cmi"]); ("cmi",[])] "cmo" "cma" "cma" ocamlc_p
+ (fun tags -> tags++"ocaml"++"pack"++"byte")
+
+let byte_pack_mlpack = link_from_file byte_pack_modules
+
+let byte_debug_pack_modules =
+ pack_modules [("d.cmo",["cmi"]); ("cmi",[])] "d.cmo" "d.cma" "d.cma" ocamlc_p
+ (fun tags -> tags++"ocaml"++"pack"++"byte"++"debug")
+
+let byte_debug_pack_mlpack = link_from_file byte_debug_pack_modules
+
+let native_pack_modules x =
+ pack_modules [("cmx",["cmi"; !Options.ext_obj]); ("cmi",[])] "cmx" "cmxa" !Options.ext_lib ocamlopt_p
+ (fun tags -> tags++"ocaml"++"pack"++"native") x
+
+let native_pack_mlpack = link_from_file native_pack_modules
+
+let native_profile_pack_modules x =
+ pack_modules [("p.cmx",["cmi"; "p" -.- !Options.ext_obj]); ("cmi",[])] "p.cmx" "p.cmxa"
+ ("p" -.- !Options.ext_lib) ocamlopt_p
+ (fun tags -> tags++"ocaml"++"pack"++"native"++"profile") x
+
+let native_profile_pack_mlpack = link_from_file native_profile_pack_modules
+
+let native_library_link_modules x =
+ link_modules [("cmx",[!Options.ext_obj]); ("cmi",[])] "cmx" "cmxa"
+ !Options.ext_lib native_lib_linker native_lib_linker_tags x
+
+let native_library_link_mllib = link_from_file native_library_link_modules
+
+let native_profile_library_link_modules x =
+ link_modules [("p.cmx",["p" -.- !Options.ext_obj]); ("cmi",[])] "p.cmx" "p.cmxa"
+ ("p" -.- !Options.ext_lib) native_lib_linker
+ (fun tags -> native_lib_linker_tags tags++"profile") x
+
+let native_profile_library_link_mllib = link_from_file native_profile_library_link_modules
diff --git a/ocamlbuild/ocaml_compiler.mli b/ocamlbuild/ocaml_compiler.mli
new file mode 100644
index 0000000000..fdf127d45d
--- /dev/null
+++ b/ocamlbuild/ocaml_compiler.mli
@@ -0,0 +1,81 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+
+val forpack_flags : string -> Tags.t -> Command.spec
+val ocamlc_c : Tags.t -> Pathname.t -> Pathname.t -> Command.t
+val ocamlc_link_lib : Tags.t -> Pathname.t list -> Pathname.t -> Command.t
+val ocamlc_link_prog : Tags.t -> Pathname.t list -> Pathname.t -> Command.t
+val ocamlc_p : Tags.t -> Pathname.t list -> Pathname.t -> Command.t
+val ocamlopt_c : Tags.t -> Pathname.t -> Pathname.t -> Command.t
+val ocamlopt_link_lib : Tags.t -> Pathname.t list -> Pathname.t -> Command.t
+val ocamlopt_link_prog : Tags.t -> Pathname.t list -> Pathname.t -> Command.t
+val ocamlopt_p : Tags.t -> Pathname.t list -> Pathname.t -> Command.t
+val ocamlmklib : Tags.t -> Pathname.t list -> Pathname.t -> Command.t
+val prepare_compile : Rule.builder -> Pathname.t -> unit
+val byte_compile_ocaml_interf : string -> string -> Rule.action
+val byte_compile_ocaml_implem : ?tag:string -> string -> string -> Rule.action
+val prepare_link :
+ Pathname.t -> Pathname.t ->
+ string list -> Rule.builder -> unit
+val native_compile_ocaml_implem : ?tag:string -> ?cmx_ext:string -> string -> Rule.action
+val prepare_libs :
+ string -> string -> Pathname.t ->
+ Rule.builder -> Pathname.t list
+val link_gen :
+ string -> string -> string -> string list ->
+ (Tags.t -> Pathname.t list -> Pathname.t -> Command.t) ->
+ (Tags.t -> Tags.t) ->
+ string -> string -> Rule.action
+val byte_link : string -> string -> Rule.action
+val byte_library_link : string -> string -> Rule.action
+val byte_debug_link : string -> string -> Rule.action
+val byte_debug_library_link : string -> string -> Rule.action
+val native_link : string -> string -> Rule.action
+val native_library_link : string -> string -> Rule.action
+val native_profile_link : string -> string -> Rule.action
+val native_profile_library_link : string -> string -> Rule.action
+val link_modules :
+ (Pathname.t * string list) list ->
+ string -> string ->
+ string -> (Tags.t -> Pathname.t list -> Pathname.t -> Command.t) ->
+ (Tags.t -> Tags.t) ->
+ string list -> string -> Rule.action
+val pack_modules :
+ (Pathname.t * string list) list ->
+ string -> string ->
+ string -> (Tags.t -> Pathname.t list -> Pathname.t -> Command.t) ->
+ (Tags.t -> Tags.t) ->
+ string list -> string -> Rule.action
+val byte_library_link_modules : string list -> string -> Rule.action
+val byte_library_link_mllib : string -> string -> Rule.action
+val byte_debug_library_link_modules : string list -> string -> Rule.action
+val byte_debug_library_link_mllib : string -> string -> Rule.action
+val byte_pack_modules : string list -> string -> Rule.action
+val byte_pack_mlpack : string -> string -> Rule.action
+val byte_debug_pack_modules : string list -> string -> Rule.action
+val byte_debug_pack_mlpack : string -> string -> Rule.action
+val native_pack_modules : string list -> string -> Rule.action
+val native_pack_mlpack : string -> string -> Rule.action
+val native_library_link_modules : string list -> string -> Rule.action
+val native_library_link_mllib : string -> string -> Rule.action
+val native_profile_pack_modules : string list -> string -> Rule.action
+val native_profile_pack_mlpack : string -> string -> Rule.action
+val native_profile_library_link_modules : string list -> string -> Rule.action
+val native_profile_library_link_mllib : string -> string -> Rule.action
+
+(** [hide_package_contents pack_name]
+ Don't treat the given package as an open package.
+ So a module will not be replaced during linking by
+ this package even if it contains that module. *)
+val hide_package_contents : string -> unit
diff --git a/ocamlbuild/ocaml_dependencies.ml b/ocamlbuild/ocaml_dependencies.ml
new file mode 100644
index 0000000000..4a10bf1dcf
--- /dev/null
+++ b/ocamlbuild/ocaml_dependencies.ml
@@ -0,0 +1,219 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Log
+open Tools
+open Ocaml_utils
+
+let mydprintf fmt = dprintf 10 fmt
+
+exception Circular_dependencies of string list * string
+
+module type INPUT = sig
+ val fold_dependencies : (string -> string -> 'a -> 'a) -> 'a -> 'a
+ val fold_libraries : (string -> string list -> 'a -> 'a) -> 'a -> 'a
+ val fold_packages : (string -> string list -> 'a -> 'a) -> 'a -> 'a
+end
+
+module Make (I : INPUT) = struct
+ open I
+
+ module SMap = Map.Make(String)
+
+ module Resources = Resource.Resources
+
+ module Utils = struct
+ let add = SMap.add
+
+ let empty = SMap.empty
+
+ let find_all_set x acc =
+ try SMap.find x acc with Not_found -> Resources.empty
+
+ let smap_add_set src dst acc =
+ SMap.add src (Resources.add dst (find_all_set src acc)) acc
+
+ let print_smap pp f smap =
+ Format.fprintf f "@[<hv0>{:@[<hv2>";
+ SMap.iter begin fun k v ->
+ Format.fprintf f "@ @[<2>%S =>@ %a@];" k pp v
+ end smap;
+ Format.fprintf f "@]@,:}@]"
+
+ let print_smap_list = print_smap pp_l
+
+ let print_smap_set = print_smap Resources.print
+
+ let print_lazy pp f l = pp f !*l
+
+ let find_all_list x acc =
+ try SMap.find x acc with Not_found -> []
+
+ let find_all_rec xs map =
+ let visited = Hashtbl.create 32 in
+ let rec self x acc =
+ try
+ Hashtbl.find visited x; acc
+ with Not_found ->
+ Hashtbl.replace visited x ();
+ let acc = Resources.add x acc in
+ try Resources.fold self (SMap.find x map) acc
+ with Not_found -> acc
+ in List.fold_right self xs Resources.empty
+
+ let mkindex fold filter =
+ fold begin fun name contents acc ->
+ if filter name then
+ List.fold_right begin fun elt acc ->
+ add elt (name :: (find_all_list elt acc)) acc
+ end contents acc
+ else
+ acc
+ end empty
+
+ end
+ open Utils
+
+ let caml_transitive_closure
+ ?(caml_obj_ext="cmo")
+ ?(caml_lib_ext="cma")
+ ?(pack_mode=false)
+ ?(used_libraries=[])
+ ?(hidden_packages=[]) fns =
+
+ let valid_link_exts =
+ if pack_mode then [caml_obj_ext; "cmi"]
+ else [caml_obj_ext; caml_lib_ext] in
+
+ mydprintf "caml_transitive_closure@ ~caml_obj_ext:%S@ ~pack_mode:%b@ ~used_libraries:%a@ %a"
+ caml_obj_ext pack_mode pp_l used_libraries pp_l fns;
+
+ let packages = fold_packages (fun name _ -> Resources.add name) Resources.empty in
+ mydprintf "packages:@ %a" Resources.print packages;
+
+ let caml_obj_ext_of_cmi x =
+ if Filename.check_suffix x ".cmi" then
+ Pathname.update_extensions caml_obj_ext x
+ else x in
+
+ let maybe_caml_obj_ext_of_cmi x =
+ if pack_mode then
+ if Filename.check_suffix x ".cmi" then
+ let caml_obj = Pathname.update_extensions caml_obj_ext x in
+ if Pathname.exists_in_build_dir caml_obj then
+ caml_obj
+ else
+ x
+ else
+ x
+ else
+ if Filename.check_suffix x ".cmi" then
+ Pathname.update_extensions caml_obj_ext x
+ else x in
+
+ let not_linkable x =
+ not (List.exists (Pathname.check_extension x) valid_link_exts) in
+
+ let dependency_map =
+ fold_dependencies begin fun x y acc ->
+ let x = maybe_caml_obj_ext_of_cmi x
+ and y = maybe_caml_obj_ext_of_cmi y in
+ if x = y || not_linkable x || not_linkable y then acc
+ else smap_add_set x y acc
+ end SMap.empty in
+ mydprintf "dependency_map:@ %a" print_smap_set dependency_map;
+
+ let used_files = find_all_rec fns dependency_map in
+ mydprintf "used_files:@ %a" Resources.print used_files;
+
+ let open_packages =
+ Resources.fold begin fun file acc ->
+ if Resources.mem file packages && not (List.mem file hidden_packages)
+ then file :: acc else acc
+ end used_files [] in
+ mydprintf "open_packages:@ %a" pp_l open_packages;
+
+ let index_filter ext list x =
+ Pathname.check_extension x ext && List.mem x list in
+
+ let lib_index =
+ lazy (mkindex fold_libraries (index_filter caml_lib_ext used_libraries)) in
+ mydprintf "lib_index:@ %a" (print_lazy print_smap_list) lib_index;
+
+ let package_index =
+ lazy (mkindex fold_packages (index_filter caml_obj_ext open_packages)) in
+
+ let rec resolve_packages x =
+ match find_all_list x !*package_index with
+ | [] -> x
+ | [x] -> resolve_packages x
+ | pkgs ->
+ failwith (sbprintf "the file %S is included in more than one active open package (%a)"
+ x pp_l pkgs) in
+
+ let libs_of x = find_all_list x !*lib_index in
+
+ let lib_of x =
+ match libs_of x with
+ | [] -> None
+ | [lib] -> Some(lib)
+ | libs ->
+ failwith (sbprintf "the file %S is included in more than one active library (%a)"
+ x pp_l libs) in
+
+ let convert_dependency src dst acc =
+ let src = resolve_packages src in
+ let dst = resolve_packages dst in
+ let add_if_diff x y = if x = y then acc else smap_add_set x y acc in
+ match (lib_of src, lib_of dst) with
+ | None, None -> add_if_diff src dst
+ | Some(liba), Some(libb) -> add_if_diff liba libb
+ | Some(lib), None -> add_if_diff lib dst
+ | None, Some(lib) -> add_if_diff src lib in
+
+ let dependencies = lazy begin
+ SMap.fold begin fun k ->
+ Resources.fold (convert_dependency k)
+ end dependency_map empty
+ end in
+
+ mydprintf "dependencies:@ %a" (print_lazy print_smap_set) dependencies;
+
+ let dependencies_of x =
+ try SMap.find x !*dependencies with Not_found -> Resources.empty in
+
+ let needed = ref [] in
+ let seen = ref [] in
+ let rec aux fn =
+ if sys_file_exists fn && not (List.mem fn !needed) then begin
+ if List.mem fn !seen then raise (Circular_dependencies (!seen, fn));
+ seen := fn :: !seen;
+ Resources.iter begin fun f ->
+ if sys_file_exists f then
+ if Filename.check_suffix f ".cmi" then
+ let f' = caml_obj_ext_of_cmi f in
+ if f' <> fn then
+ if sys_file_exists f' then aux f'
+ else if pack_mode then aux f else ()
+ else ()
+ else aux f
+ end (dependencies_of fn);
+ needed := fn :: !needed
+ end
+ in
+ List.iter aux fns;
+ mydprintf "caml_transitive_closure:@ %a ->@ %a" pp_l fns pp_l !needed;
+ List.rev !needed
+
+end
diff --git a/ocamlbuild/ocaml_dependencies.mli b/ocamlbuild/ocaml_dependencies.mli
new file mode 100644
index 0000000000..713de0a04a
--- /dev/null
+++ b/ocamlbuild/ocaml_dependencies.mli
@@ -0,0 +1,43 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(** Ocaml dependencies *)
+
+exception Circular_dependencies of string list * string
+
+(** Give to this module a way to access libraries, packages,
+ and dependencies between files. *)
+module type INPUT = sig
+ val fold_dependencies : (string -> string -> 'a -> 'a) -> 'a -> 'a
+ val fold_libraries : (string -> string list -> 'a -> 'a) -> 'a -> 'a
+ val fold_packages : (string -> string list -> 'a -> 'a) -> 'a -> 'a
+end
+
+(** Wait an [INPUT] module and gives a function to compute the
+ transitive closure of caml file takeing in account libraries and packages. *)
+module Make (I : INPUT) : sig
+
+ (** [caml_transitive_closure] takes a list of root ocaml compiled files and returns
+ the list of files that must be given to a linker. Optionally you can change the
+ extension of caml object/library files (cmo/cma by default); use the pack mode
+ (false by default) to include only root files (just sort them); and gives the
+ list of used libraries (empty by default). *)
+ val caml_transitive_closure :
+ ?caml_obj_ext:string ->
+ ?caml_lib_ext:string ->
+ ?pack_mode:bool ->
+ ?used_libraries:string list ->
+ ?hidden_packages:string list ->
+ Pathname.t list -> Pathname.t list
+
+end
diff --git a/ocamlbuild/ocaml_specific.ml b/ocamlbuild/ocaml_specific.ml
new file mode 100644
index 0000000000..79532f8c82
--- /dev/null
+++ b/ocamlbuild/ocaml_specific.ml
@@ -0,0 +1,373 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Format
+open Log
+open Pathname.Operators
+open Tags.Operators
+open Rule
+open Tools
+open Rule.Common_commands
+open Outcome
+open Command;;
+
+open Ocaml_utils
+
+module C_tools = struct
+ let link_C_library clib a libname env build =
+ let clib = env clib and a = env a and libname = env libname in
+ let objs = string_list_of_file clib in
+ let include_dirs = Pathname.include_dirs_of (Pathname.dirname a) in
+ let obj_of_o x =
+ if Filename.check_suffix x ".o" && !Options.ext_obj <> "o" then
+ Pathname.update_extension !Options.ext_obj x
+ else x in
+ let resluts = build (List.map (fun o -> List.map (fun dir -> dir / obj_of_o o) include_dirs) objs) in
+ let objs = List.map begin function
+ | Good o -> o
+ | Bad exn -> raise exn
+ end resluts in
+ Cmd(S[!Options.ocamlmklib; A"-o"; Px libname; T(tags_of_pathname a++"c"++"ocamlmklib"); atomize objs]);;
+end
+
+open Flags
+open Command
+open Rule
+
+let nop _env _build = ()
+
+let ocaml_lib ?(extern=false) ?(byte=true) ?(native=true) ?dir libpath =
+ let add_dir x =
+ match dir with
+ | Some dir -> S[A"-I"; P dir; x]
+ | None -> x
+ and lib = Pathname.basename libpath in
+ Hashtbl.replace info_libraries lib (libpath, extern);
+ if byte then flag ["ocaml"; "use_"^lib; "link"; "byte"] (add_dir (A (libpath^".cma")));
+ if native then flag ["ocaml"; "use_"^lib; "link"; "native"] (add_dir (A (libpath^".cmxa")));;
+
+let init () = let module M = struct
+
+let ext_lib = !Options.ext_lib;;
+let ext_obj = !Options.ext_obj;;
+let ext_dll = !Options.ext_dll;;
+let x_o = "%"-.-ext_obj;;
+let x_a = "%"-.-ext_lib;;
+let x_dll = "%"-.-ext_dll;;
+let x_p_o = "%.p"-.-ext_obj;;
+let x_p_a = "%.p"-.-ext_lib;;
+
+rule "target files"
+ ~dep:"%.itarget"
+ ~prod:"%.otarget"
+ begin fun env build ->
+ let itarget = env "%.itarget" and otarget = env "%.otarget" in
+ let dir = Pathname.dirname itarget in
+ List.iter ignore_good
+ (build (List.map (fun x -> [dir/x]) (string_list_of_file itarget)));
+ touch otarget
+ end;;
+
+rule "ocaml: mli -> cmi"
+ ~tags:["ocaml"]
+ ~prod:"%.cmi"
+ ~deps:["%.mli"; "%.mli.depends"]
+ (Ocaml_compiler.byte_compile_ocaml_interf "%.mli" "%.cmi");;
+
+rule "ocaml: mlpack & d.cmo* -> d.cmo & cmi"
+ ~tags:["ocaml"; "debug"; "byte"]
+ ~prods:["%.d.cmo"]
+ ~deps:["%.mlpack"; "%.cmi"]
+ (Ocaml_compiler.byte_debug_pack_mlpack "%.mlpack" "%.d.cmo");;
+
+rule "ocaml: mlpack & cmo* -> cmo & cmi"
+ ~tags:["ocaml"; "byte"]
+ ~prods:["%.cmo"; "%.cmi"]
+ ~dep:"%.mlpack"
+ (Ocaml_compiler.byte_pack_mlpack "%.mlpack" "%.cmo");;
+
+rule "ocaml: ml & cmi -> d.cmo"
+ ~tags:["ocaml"; "byte"]
+ ~prod:"%.d.cmo"
+ ~deps:["%.mli"(* This one is inserted to force this rule to be skiped when
+ a .ml is provided without a .mli *); "%.ml"; "%.ml.depends"; "%.cmi"]
+ (Ocaml_compiler.byte_compile_ocaml_implem ~tag:"debug" "%.ml" "%.d.cmo");;
+
+rule "ocaml: ml & cmi -> cmo"
+ ~tags:["ocaml"; "byte"]
+ ~prod:"%.cmo"
+ ~deps:["%.mli"(* This one is inserted to force this rule to be skiped when
+ a .ml is provided without a .mli *); "%.ml"; "%.ml.depends"; "%.cmi"]
+ (Ocaml_compiler.byte_compile_ocaml_implem "%.ml" "%.cmo");;
+
+rule "ocaml: mlpack & cmi & p.cmx* & p.o* -> p.cmx & p.o"
+ ~tags:["ocaml"; "profile"; "native"]
+ ~prods:["%.p.cmx"; x_p_o(* no cmi here you must make the byte version to have it *)]
+ ~deps:["%.mlpack"; "%.cmi"]
+ (Ocaml_compiler.native_profile_pack_mlpack "%.mlpack" "%.p.cmx");;
+
+rule "ocaml: mlpack & cmi & cmx* & o* -> cmx & o"
+ ~tags:["ocaml"; "native"]
+ ~prods:["%.cmx"; x_o(* no cmi here you must make the byte version to have it *)]
+ ~deps:["%.mlpack"; "%.cmi"]
+ (Ocaml_compiler.native_pack_mlpack "%.mlpack" "%.cmx");;
+
+rule "ocaml: ml & cmi -> p.cmx & p.o"
+ ~tags:["ocaml"; "native"; "profile"]
+ ~prods:["%.p.cmx"; x_p_o]
+ ~deps:["%.ml"; "%.ml.depends"; "%.cmi"]
+ (Ocaml_compiler.native_compile_ocaml_implem ~tag:"profile" ~cmx_ext:"p.cmx" "%.ml");;
+
+rule "ocaml: ml & cmi -> cmx & o"
+ ~tags:["ocaml"; "native"]
+ ~prods:["%.cmx"; x_o]
+ ~deps:["%.ml"; "%.ml.depends"; "%.cmi"]
+ (Ocaml_compiler.native_compile_ocaml_implem "%.ml");;
+
+rule "ocaml: ml -> d.cmo & cmi"
+ ~tags:["ocaml"; "debug"]
+ ~prods:["%.d.cmo"]
+ ~deps:["%.ml"; "%.ml.depends"; "%.cmi"]
+ (Ocaml_compiler.byte_compile_ocaml_implem ~tag:"debug" "%.ml" "%.d.cmo");;
+
+rule "ocaml: ml -> cmo & cmi"
+ ~tags:["ocaml"]
+ ~prods:["%.cmo"; "%.cmi"]
+ ~deps:["%.ml"; "%.ml.depends"]
+ (Ocaml_compiler.byte_compile_ocaml_implem "%.ml" "%.cmo");;
+
+rule "ocaml: d.cmo* -> d.byte"
+ ~tags:["ocaml"; "byte"; "debug"; "program"]
+ ~prod:"%.d.byte"
+ ~dep:"%.d.cmo"
+ (Ocaml_compiler.byte_debug_link "%.d.cmo" "%.d.byte");;
+
+rule "ocaml: cmo* -> byte"
+ ~tags:["ocaml"; "byte"; "program"]
+ ~prod:"%.byte"
+ ~dep:"%.cmo"
+ (Ocaml_compiler.byte_link "%.cmo" "%.byte");;
+
+rule "ocaml: p.cmx* & p.o* -> p.native"
+ ~tags:["ocaml"; "native"; "profile"; "program"]
+ ~prod:"%.p.native"
+ ~deps:["%.p.cmx"; x_p_o]
+ (Ocaml_compiler.native_profile_link "%.p.cmx" "%.p.native");;
+
+rule "ocaml: cmx* & o* -> native"
+ ~tags:["ocaml"; "native"; "program"]
+ ~prod:"%.native"
+ ~deps:["%.cmx"; x_o]
+ (Ocaml_compiler.native_link "%.cmx" "%.native");;
+
+rule "ocaml: mllib & d.cmo* -> d.cma"
+ ~tags:["ocaml"; "byte"; "debug"; "library"]
+ ~prod:"%.d.cma"
+ ~dep:"%.mllib"
+ (Ocaml_compiler.byte_debug_library_link_mllib "%.mllib" "%.d.cma");;
+
+rule "ocaml: mllib & cmo* -> cma"
+ ~tags:["ocaml"; "byte"; "library"]
+ ~prod:"%.cma"
+ ~dep:"%.mllib"
+ (Ocaml_compiler.byte_library_link_mllib "%.mllib" "%.cma");;
+
+rule "ocaml: d.cmo* -> d.cma"
+ ~tags:["ocaml"; "byte"; "debug"; "library"]
+ ~prod:"%.d.cma"
+ ~dep:"%.d.cmo"
+ (Ocaml_compiler.byte_debug_library_link "%.d.cmo" "%.d.cma");;
+
+rule "ocaml: cmo* -> cma"
+ ~tags:["ocaml"; "byte"; "library"]
+ ~prod:"%.cma"
+ ~dep:"%.cmo"
+ (Ocaml_compiler.byte_library_link "%.cmo" "%.cma");;
+
+rule "ocaml C stubs (short): clib & (o|obj)* -> (a|lib) & (so|dll)"
+ ~prods:["lib%(libname)"-.-ext_lib; "dll%(libname)"-.-ext_dll]
+ ~dep:"lib%(libname).clib"
+ (C_tools.link_C_library "lib%(libname).clib" ("lib%(libname)"-.-ext_lib) "%(libname)");;
+
+rule "ocaml C stubs: clib & (o|obj)* -> (a|lib) & (so|dll)"
+ ~prods:["%(path)/lib%(libname)"-.-ext_lib; "%(path)/dll%(libname)"-.-ext_dll]
+ ~dep:"%(path)/lib%(libname).clib"
+ (C_tools.link_C_library "%(path)/lib%(libname).clib" ("%(path)/lib%(libname)"-.-ext_lib) "%(path)/%(libname)");;
+
+rule "ocaml: mllib & p.cmx* & p.o* -> p.cmxa & p.a"
+ ~tags:["ocaml"; "native"; "profile"; "library"]
+ ~prods:["%.p.cmxa"; x_p_a]
+ ~dep:"%.mllib"
+ (Ocaml_compiler.native_profile_library_link_mllib "%.mllib" "%.p.cmxa");;
+
+rule "ocaml: mllib & cmx* & o* -> cmxa & a"
+ ~tags:["ocaml"; "native"; "library"]
+ ~prods:["%.cmxa"; x_a]
+ ~dep:"%.mllib"
+ (Ocaml_compiler.native_library_link_mllib "%.mllib" "%.cmxa");;
+
+rule "ocaml: p.cmx* & p.o* -> p.cmxa & p.a"
+ ~tags:["ocaml"; "native"; "profile"; "library"]
+ ~prods:["%.p.cmxa"; x_p_a]
+ ~deps:["%.p.cmx"; x_p_o]
+ (Ocaml_compiler.native_profile_library_link "%.p.cmx" "%.p.cmxa");;
+
+rule "ocaml: cmx* & o* -> cmxa & a"
+ ~tags:["ocaml"; "native"; "library"]
+ ~prods:["%.cmxa"; x_a]
+ ~deps:["%.cmx"; x_o]
+ (Ocaml_compiler.native_library_link "%.cmx" "%.cmxa");;
+
+Ocamldep.depends "ocaml dependencies ml"
+ ~prod:"%.ml.depends"
+ ~dep:"%.ml" ();;
+
+Ocamldep.depends "ocaml dependencies mli"
+ ~prod:"%.mli.depends"
+ ~dep:"%.mli" ();;
+
+rule "ocamllex"
+ ~tags:["ocaml"] (* FIXME "lexer" *)
+ ~prod:"%.ml"
+ ~dep:"%.mll"
+ (Ocaml_tools.ocamllex "%.mll");;
+
+rule "ocaml: mli -> odoc"
+ ~tags:["ocaml"; "doc"]
+ ~prod:"%.odoc"
+ ~deps:["%.mli"; "%.mli.depends"]
+ (Ocaml_tools.document_ocaml_interf "%.mli" "%.odoc");;
+
+rule "ocamldoc: document ocaml project *odoc -> docdir"
+ ~prod:"%.docdir/index.html"
+ ~dep:"%.odocl"
+ (Ocaml_tools.document_ocaml_project "%.odocl" "%.docdir");;
+
+(* To use menhir give the -use-menhir option at command line,
+ Or put true: use_menhir in your tag file. *)
+if !Options.use_menhir || Configuration.has_tag "use_menhir" then begin
+ rule "ocaml: menhir"
+ ~prods:["%.ml"; "%.mli"]
+ ~deps:["%.mly"; "%.mly.depends"]
+ (Ocaml_tools.menhir "%.mly");
+
+ Ocamldep.depends "ocaml: menhir dependencies"
+ ~prod:"%.mly.depends"
+ ~dep:"%.mly"
+ ~ocamldep_command:Ocamldep.menhir_ocamldep_command ();
+end else
+ rule "ocamlyacc"
+ ~tags:["ocaml"] (* FIXME "parser" *)
+ ~prods:["%.ml"; "%.mli"]
+ ~dep:"%.mly"
+ (Ocaml_tools.ocamlyacc "%.mly");;
+
+rule "ocaml C stubs: c -> o"
+ ~prod:x_o
+ ~dep:"%.c"
+ begin fun env _build ->
+ let c = env "%.c" in
+ let o = env x_o in
+ let cc = Cmd(S[!Options.ocamlc; T(tags_of_pathname c++"c"++"compile"); A"-c"; Px c]) in
+ if Pathname.dirname o = Pathname.current_dir_name then cc
+ else Seq[cc; mv (Pathname.basename o) o]
+ end;;
+
+rule "ocaml: ml & ml.depends & *cmi -> .inferred.mli"
+ ~prod:"%.inferred.mli"
+ ~deps:["%.ml"; "%.ml.depends"]
+ (Ocaml_tools.infer_interface "%.ml" "%.inferred.mli");;
+
+flag ["ocaml"; "pp"] begin
+ S (List.fold_right (fun x acc -> Sh x :: acc) !Options.ocaml_ppflags [])
+end;;
+
+flag ["ocaml"; "compile"] begin
+ atomize !Options.ocaml_cflags
+end;;
+
+flag ["ocaml"; "link"] begin
+ atomize !Options.ocaml_lflags
+end;;
+
+flag ["ocaml"; "ocamlyacc"] (atomize !Options.ocaml_yaccflags);;
+
+flag ["ocaml"; "ocamllex"] (atomize !Options.ocaml_lexflags);;
+
+flag ["ocaml"; "byte"; "link"] begin
+ S (List.map (fun x -> A (x^".cma")) !Options.ocaml_libs)
+end;;
+
+flag ["ocaml"; "native"; "link"] begin
+ S (List.map (fun x -> A (x^".cmxa")) !Options.ocaml_libs)
+end;;
+
+let camlp4_flags camlp4s =
+ List.iter begin fun camlp4 ->
+ flag ["ocaml"; "pp"; camlp4] (A camlp4)
+ end camlp4s;;
+
+camlp4_flags ["camlp4o"; "camlp4r"; "camlp4of"; "camlp4rf"; "camlp4orf"];;
+
+ocaml_lib ~extern:true ~native:false "dynlink";;
+ocaml_lib ~extern:true "unix";;
+ocaml_lib ~extern:true "str";;
+ocaml_lib ~extern:true "bigarray";;
+ocaml_lib ~extern:true "nums";;
+ocaml_lib ~extern:true "dbm";;
+ocaml_lib ~extern:true "graphics";;
+ocaml_lib ~extern:true "labltk";;
+ocaml_lib ~extern:true ~dir:"+camlp4" "camlp4";;
+
+flag ["ocaml"; "debug"; "compile"; "byte"] (A "-g");;
+flag ["ocaml"; "debug"; "link"; "byte"] (A "-g");;
+flag ["ocaml"; "debug"; "pack"; "byte"] (A "-g");;
+flag ["ocaml"; "dtypes"; "compile"] (A "-dtypes");;
+flag ["ocaml"; "rectypes"; "compile"] (A "-rectypes");;
+flag ["ocaml"; "linkall"; "link"] (A "-linkall");;
+flag ["ocaml"; "link"; "profile"; "native"] (A "-p");;
+flag ["ocaml"; "link"; "program"; "custom"; "byte"] (A "-custom");;
+flag ["ocaml"; "compile"; "profile"; "native"] (A "-p");;
+flag ["ocaml"; "compile"; "thread"] (A "-thread");;
+flag ["ocaml"; "link"; "thread"] (S[A "threads.cmxa"; A "-thread"]);;
+flag ["ocaml"; "compile"; "nopervasives"] (A"-nopervasives");;
+flag ["ocaml"; "compile"; "nolabels"] (A"-nolabels");;
+
+(*flag ["ocaml"; "ocamlyacc"; "quiet"] (A"-q");;*)
+flag ["ocaml"; "ocamllex"; "quiet"] (A"-q");;
+
+let ocaml_warn_flag c =
+ flag ["ocaml"; "compile"; sprintf "warn_%c" (Char.uppercase c)]
+ (S[A"-w"; A (sprintf "%c" (Char.uppercase c))]);
+ flag ["ocaml"; "compile"; sprintf "warn_error_%c" (Char.uppercase c)]
+ (S[A"-warn-error"; A (sprintf "%c" (Char.uppercase c))]);
+ flag ["ocaml"; "compile"; sprintf "warn_%c" (Char.lowercase c)]
+ (S[A"-w"; A (sprintf "%c" (Char.lowercase c))]);
+ flag ["ocaml"; "compile"; sprintf "warn_error_%c" (Char.lowercase c)]
+ (S[A"-warn-error"; A (sprintf "%c" (Char.lowercase c))]);;
+
+List.iter ocaml_warn_flag ['A'; 'C'; 'D'; 'E'; 'F'; 'L'; 'M'; 'P'; 'S'; 'U'; 'V'; 'Y'; 'Z'; 'X'];;
+
+(** Ocamlbuild plugin for it's own building *)
+let install_lib = lazy (try Sys.getenv "INSTALL_LIB" with Not_found -> !*stdlib_dir/"ocamlbuild" (* not My_std.getenv since it's lazy*)) in
+file_rule "ocamlbuild_where.ml"
+ ~prod:"%ocamlbuild_where.ml"
+ ~cache:(fun _ -> !*install_lib)
+ begin fun _ oc ->
+ Printf.fprintf oc "let where = ref %S;;\n" !*install_lib
+ end;;
+ocaml_lib "ocamlbuildlib";;
+ocaml_lib "ocamlbuildlightlib";;
+
+end in ()
diff --git a/ocamlbuild/ocaml_specific.mli b/ocamlbuild/ocaml_specific.mli
new file mode 100644
index 0000000000..1234b0dec2
--- /dev/null
+++ b/ocamlbuild/ocaml_specific.mli
@@ -0,0 +1,17 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+val nop : 'a -> 'b -> unit
+val ocaml_lib : ?extern:bool -> ?byte:bool -> ?native:bool -> ?dir:Pathname.t -> Pathname.t -> unit
+
+val init : unit -> unit
diff --git a/ocamlbuild/ocaml_tools.ml b/ocamlbuild/ocaml_tools.ml
new file mode 100644
index 0000000000..3c8253d33c
--- /dev/null
+++ b/ocamlbuild/ocaml_tools.ml
@@ -0,0 +1,73 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Pathname.Operators
+open Tags.Operators
+open Tools
+open Command
+open Ocaml_utils
+
+let ocamlyacc mly env _build =
+ let mly = env mly in
+ Cmd(S[!Options.ocamlyacc; T(tags_of_pathname mly++"ocaml"++"parser"++"ocamlyacc");
+ flags_of_pathname mly; Px mly])
+
+let ocamllex mll env _build =
+ let mll = env mll in
+ Cmd(S[!Options.ocamllex; T(tags_of_pathname mll++"ocaml"++"lexer"++"ocamllex");
+ flags_of_pathname mll; Px mll])
+
+let infer_interface ml mli env build =
+ let ml = env ml and mli = env mli in
+ Ocaml_compiler.prepare_compile build ml;
+ Cmd(S[!Options.ocamlc; A"-i"; T(tags_of_pathname ml++"ocaml"++"infer_interface"); P ml; Sh">"; Px mli])
+
+let menhir mly env build =
+ let mly = env mly in
+ Ocaml_compiler.prepare_compile build mly;
+ Cmd(S[!Options.ocamlyacc; T(tags_of_pathname mly++"ocaml"++"parser"++"menhir");
+ A"--infer"; flags_of_pathname mly; Px mly])
+
+let ocamldoc_c tags arg odoc =
+ let tags = tags++"ocaml" in
+ Cmd (S [!Options.ocamldoc; A"-dump"; Px odoc; T(tags++"doc");
+ ocaml_ppflags tags; flags_of_pathname arg;
+ ocaml_include_flags arg; P arg])
+
+let ocamldoc_l tags deps out =
+ let tags = tags++"ocaml" in
+ Seq[Cmd (S[A"rm"; A"-rf"; Px out]);
+ Cmd (S[A"mkdir"; A"-p"; Px out]);
+ Cmd (S [!Options.ocamldoc;
+ S(List.map (fun a -> S[A"-load"; P a]) deps);
+ T(tags++"doc");
+ A"-html";
+ A"-d";
+ Px out])]
+
+let document_ocaml_interf mli odoc env build =
+ let mli = env mli and odoc = env odoc in
+ Ocaml_compiler.prepare_compile build mli;
+ ocamldoc_c (tags_of_pathname mli++"interf") mli odoc
+
+let document_ocaml_project odocl docdir env build =
+ let odocl = env odocl and docdir = env docdir in
+ let contents = string_list_of_file odocl in
+ let include_dirs = Pathname.include_dirs_of (Pathname.dirname odocl) in
+ let to_build =
+ List.map begin fun module_name ->
+ expand_module include_dirs module_name ["odoc"]
+ end contents in
+ let module_paths = List.map Outcome.good (build to_build) in
+ ocamldoc_l (tags_of_pathname docdir) module_paths docdir
diff --git a/ocamlbuild/ocaml_tools.mli b/ocamlbuild/ocaml_tools.mli
new file mode 100644
index 0000000000..c50fb5f5ad
--- /dev/null
+++ b/ocamlbuild/ocaml_tools.mli
@@ -0,0 +1,22 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+val ocamldoc_c : Tags.t -> string -> string -> Command.t
+val ocamldoc_l : Tags.t -> string list -> string -> Command.t
+
+val ocamlyacc : string -> Rule.action
+val ocamllex : string -> Rule.action
+val menhir : string -> Rule.action
+val infer_interface : string -> string -> Rule.action
+val document_ocaml_interf : string -> string -> Rule.action
+val document_ocaml_project : string -> string -> Rule.action
diff --git a/ocamlbuild/ocaml_utils.ml b/ocamlbuild/ocaml_utils.ml
new file mode 100644
index 0000000000..f669b3e50e
--- /dev/null
+++ b/ocamlbuild/ocaml_utils.ml
@@ -0,0 +1,87 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Format
+open Log
+open Pathname.Operators
+open Tags.Operators
+open Tools
+open Command;;
+
+
+module S = Set.Make(String)
+
+let stdlib_dir = lazy begin
+ (* FIXME *)
+ let ocamlc_where = sprintf "%s/ocamlc.where" (Pathname.pwd / !Options.build_dir) in
+ let () = Command.execute ~quiet:true (Cmd(S[!Options.ocamlc; A"-where"; Sh">"; P ocamlc_where])) in
+ String.chomp (read_file ocamlc_where)
+end
+
+let module_name_of_filename f = String.capitalize (Pathname.remove_extensions f)
+let module_name_of_pathname x =
+ module_name_of_filename (Pathname.to_string (Pathname.basename x))
+
+let ignore_stdlib x =
+ if !Options.nostdlib then false
+ else
+ let x' = !*stdlib_dir/((String.uncapitalize x)-.-"cmi") in
+ Pathname.exists x'
+
+let non_dependencies = ref []
+let non_dependency m1 m2 = non_dependencies := (m1, m2) :: !non_dependencies
+
+let ignore_this_module modpath x =
+ List.mem (modpath, x) !non_dependencies
+ || (List.mem x !Options.ignore_list) || ignore_stdlib x
+
+let keep_this_module modpath x =
+ if ignore_this_module modpath x then
+ let () = dprintf 3 "This module (%s) is ignored by %s" x modpath in false
+ else true
+
+let expand_module include_dirs module_name exts =
+ List.fold_right begin fun include_dir ->
+ List.fold_right begin fun ext acc ->
+ let module_name_ext = module_name-.-ext in
+ include_dir/(String.uncapitalize module_name_ext) ::
+ include_dir/(String.capitalize module_name_ext) :: acc
+ end exts
+ end include_dirs []
+
+let string_list_of_file file =
+ with_input_file file begin fun ic ->
+ Lexers.blank_sep_strings (Lexing.from_channel ic)
+ end
+let print_path_list = Pathname.print_path_list
+
+let ocaml_ppflags tags =
+ let flags = Flags.of_tags (tags++"ocaml"++"pp") in
+ let reduced = Command.reduce flags in
+ if reduced = N then N else S[A"-pp"; Quote reduced]
+
+let ocaml_add_include_flag x acc =
+ if x = Pathname.current_dir_name then acc else A"-I" :: A x :: acc
+
+let ocaml_include_flags path =
+ S (List.fold_right ocaml_add_include_flag (Pathname.include_dirs_of (Pathname.dirname path)) [])
+
+let info_libraries = Hashtbl.create 103
+
+let libraries = Hashtbl.create 103
+let libraries_of m =
+ try Hashtbl.find libraries m with Not_found -> []
+let use_lib m lib = Hashtbl.replace libraries m (lib :: libraries_of m)
+
+let cmi_of = Pathname.update_extensions "cmi"
diff --git a/ocamlbuild/ocaml_utils.mli b/ocamlbuild/ocaml_utils.mli
new file mode 100644
index 0000000000..00ece2c6a6
--- /dev/null
+++ b/ocamlbuild/ocaml_utils.mli
@@ -0,0 +1,30 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+val stdlib_dir : Pathname.t Lazy.t
+val module_name_of_filename : Pathname.t -> string
+val module_name_of_pathname : Pathname.t -> string
+val ignore_stdlib : string -> bool
+val non_dependency : string -> string -> unit
+val expand_module :
+ Pathname.t list -> Pathname.t -> string list -> Pathname.t list
+val string_list_of_file : string -> string list
+val ocaml_ppflags : Tags.t -> Command.spec
+val ocaml_include_flags : Pathname.t -> Command.spec
+val libraries_of : Pathname.t -> Pathname.t list
+val use_lib : Pathname.t -> Pathname.t -> unit
+val cmi_of : Pathname.t -> Pathname.t
+val ocaml_add_include_flag : string -> Command.spec list -> Command.spec list
+val keep_this_module : string -> string -> bool
+
+val info_libraries : (string, string * bool) Hashtbl.t
diff --git a/ocamlbuild/ocamlbuild-presentation.rslide b/ocamlbuild/ocamlbuild-presentation.rslide
new file mode 100644
index 0000000000..6c071b6bca
--- /dev/null
+++ b/ocamlbuild/ocamlbuild-presentation.rslide
@@ -0,0 +1,116 @@
+documentclass :beamer, :t, :compress, :red
+usepackage :inputenc, :utf8
+
+title "ocamlbuild, a tool for automatic compilation of O'Caml projects"
+authors "Berke Durak", "Nicolas Pouillard"
+institute do
+ > @@Berke.Durak@inria.fr@@
+ hfill
+ > @@Nicolas.Pouillard@inria.fr@@
+end
+
+usetheme :JuanLesPins
+usefonttheme :serif
+beamer_header '\setbeamercolor*{titlelike}{parent=structure}'
+at_begin_subsection do
+ slide "Outline" do
+ tableofcontents 'sectionstyle=show/hide',
+ 'subsectionstyle=show/shaded/hide'
+ end
+end
+beamer_footline
+
+words "**O'Caml**"
+
+words "??ocamlbuild??"
+
+maketitle
+
+slide "Why such a tool?" do
+ * To make our O'Caml life easier.
+ * A Makefile is so painful.
+end
+
+slide "What does ocamlbuild handle?" do
+
+ box "Regular O'Caml projects of arbitrary size" do
+ > Trivially handled using the command line options.
+ end
+
+ box "Mostly regular O'Caml projects with common exceptions" do
+ > Requires writing one _tag_ file that declares those exceptions.
+ end
+
+ box "Almost any project" do
+ > Accomplished by writing an ocamlbuild plugin.
+ end
+
+end
+
+slide "What kind of services for a project?" do
+ * Compilation of the whole project.
+ * Minimal re-compilation after a change.
+ * Other builds like the documentation.
+ * Different build directories at a same time.
+ * Cleaning of what's built.
+ * Keeping an hygienic source directory.
+ * Saving time!
+end
+
+slide "What's a regular O'Caml project?" do
+ * O'Caml compilation units (ml and mli files).
+ * O'Caml parsers and lexers specifications (mly and mll files).
+ * Internal packages and libraries (mlpack, mllib).
+ * Use of external libraries.
+ * One main O'Caml unit that represents the starting point.
+end
+
+slide "How difficult are regular projects?" do
+ *
+end
+
+slide "What's an exception?" do
+ box "Some flags can be different for some files" do
+ * Enable/disable some warning flags.
+ * Debugging (-g), profiling (-p), type annotations flags,
+ recursive types, -linkall, -thread, -custom.
+ end
+ * Have to link this binary with that library.
+ * Include or exclude that directory.
+ * Some dependencies.
+end
+
+slide "??Make?? and exceptions" do
+ * The ??make?? tool can handle rules but not exceptions.
+ * With ??make?? exceptions are encoded as specific rules.
+ * This generally makes rules and exceptions tightly bound by variables.
+ * This way totally doesn't scale, and is not *modular*.
+end
+
+slide "The tags, our way to specify exceptions" do
+ box "Rules produce commands with *tagged holes*" do
+ : let tagged_hole = tags_for(ml)++"ocaml"++"compile"++"byte" in
+ Cmd(S[A"ocamlc"; A"-c"; T(tagged_hole); P ml; A"-o"; Px cmo])
+ end
+ box "These holes can be filled by some command pieces (flags)" do
+ : flag ["ocaml"; "compile"; "byte"; "rectypes"] (A"-rectypes")
+ end
+ box "Files can also be tagged and make things happen" do
+ : "foo/bar.ml": rectypes
+ end
+end
+
+slide "The tags file (_tags)" do
+ * Each line is a pattern and a set of tags.
+ * The pattern is a boolean tree (*and*, *or*, *not*).
+ * Leafs are either constant strings or glob patterns.
+ * In the set of tags, they can appear positively or negatively.
+end
+
+slide "" do
+
+end
+
+slide "A big thanks to" do
+ * Alain, Xavier, Michel...
+end \ No newline at end of file
diff --git a/ocamlbuild/ocamlbuild.ml b/ocamlbuild/ocamlbuild.ml
new file mode 100644
index 0000000000..96d78185b2
--- /dev/null
+++ b/ocamlbuild/ocamlbuild.ml
@@ -0,0 +1,15 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+My_unix_with_unix.setup ();
+Ocamlbuild_pack.Main.main ()
diff --git a/ocamlbuild/ocamlbuild.mli b/ocamlbuild/ocamlbuild.mli
new file mode 100644
index 0000000000..3d643e3e52
--- /dev/null
+++ b/ocamlbuild/ocamlbuild.mli
@@ -0,0 +1,15 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(** Nothing to export for now *)
+
diff --git a/ocamlbuild/ocamlbuild.odocl b/ocamlbuild/ocamlbuild.odocl
new file mode 100644
index 0000000000..d4374386af
--- /dev/null
+++ b/ocamlbuild/ocamlbuild.odocl
@@ -0,0 +1,38 @@
+Log
+My_unix
+My_std
+Std_signatures
+Signatures
+Shell
+Display
+Command
+Configuration
+Discard_printf
+Flags
+Hygiene
+Options
+Pathname
+Report
+Resource
+Rule
+Slurp
+Solver
+Tags
+Tools
+Fda
+Ocaml_specific
+Ocaml_arch
+Ocamlbuild_where
+Lexers
+Glob
+Bool
+Glob_ast
+Glob_lexer
+Plugin
+Main
+Hooks
+Ocaml_utils
+Ocaml_tools
+Ocaml_compiler
+Ocamldep
+Ocaml_dependencies
diff --git a/ocamlbuild/ocamlbuild_pack.mlpack b/ocamlbuild/ocamlbuild_pack.mlpack
new file mode 100644
index 0000000000..d4374386af
--- /dev/null
+++ b/ocamlbuild/ocamlbuild_pack.mlpack
@@ -0,0 +1,38 @@
+Log
+My_unix
+My_std
+Std_signatures
+Signatures
+Shell
+Display
+Command
+Configuration
+Discard_printf
+Flags
+Hygiene
+Options
+Pathname
+Report
+Resource
+Rule
+Slurp
+Solver
+Tags
+Tools
+Fda
+Ocaml_specific
+Ocaml_arch
+Ocamlbuild_where
+Lexers
+Glob
+Bool
+Glob_ast
+Glob_lexer
+Plugin
+Main
+Hooks
+Ocaml_utils
+Ocaml_tools
+Ocaml_compiler
+Ocamldep
+Ocaml_dependencies
diff --git a/ocamlbuild/ocamlbuild_plugin.ml b/ocamlbuild/ocamlbuild_plugin.ml
new file mode 100644
index 0000000000..827c93417d
--- /dev/null
+++ b/ocamlbuild/ocamlbuild_plugin.ml
@@ -0,0 +1,53 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+
+open Ocamlbuild_pack
+include Ocamlbuild_pack.My_std
+module Arch = Ocamlbuild_pack.Ocaml_arch
+module Command = Ocamlbuild_pack.Command
+module Pathname = Ocamlbuild_pack.Pathname
+module Tags = Ocamlbuild_pack.Tags
+include Pathname.Operators
+include Tags.Operators
+module Rule = Ocamlbuild_pack.Rule
+module Options = Ocamlbuild_pack.Options
+include Rule.Common_commands
+type env = Pathname.t -> Pathname.t
+type builder = Pathname.t list list -> (Pathname.t, exn) Ocamlbuild_pack.My_std.Outcome.t list
+type action = env -> builder -> Command.t
+let rule = Rule.rule
+let dep = Rule.dep
+let file_rule = Rule.file_rule
+let copy_rule = Rule.copy_rule
+let custom_rule = Rule.custom_rule
+let flag = Ocamlbuild_pack.Flags.flag
+let non_dependency = Ocamlbuild_pack.Ocaml_utils.non_dependency
+let use_lib = Ocamlbuild_pack.Ocaml_utils.use_lib
+let module_name_of_pathname = Ocamlbuild_pack.Ocaml_utils.module_name_of_pathname
+let string_list_of_file = Ocamlbuild_pack.Ocaml_utils.string_list_of_file
+let expand_module = Ocamlbuild_pack.Ocaml_utils.expand_module
+let tags_of_pathname = Ocamlbuild_pack.Tools.tags_of_pathname
+let hide_package_contents = Ocamlbuild_pack.Ocaml_compiler.hide_package_contents
+let tag_file file tags =
+ Ocamlbuild_pack.Configuration.parse_string (Printf.sprintf "%S: %s" file (String.concat ", " tags));;
+let tag_any tags =
+ Ocamlbuild_pack.Configuration.parse_string (Printf.sprintf "true: %s" (String.concat ", " tags));;
+type hook = Ocamlbuild_pack.Hooks.message =
+ | Before_hygiene
+ | After_hygiene
+ | Before_options
+ | After_options
+ | Before_rules
+ | After_rules
+let dispatch = Ocamlbuild_pack.Hooks.setup_hooks
diff --git a/ocamlbuild/ocamlbuild_plugin.mli b/ocamlbuild/ocamlbuild_plugin.mli
new file mode 100644
index 0000000000..8e642f31a2
--- /dev/null
+++ b/ocamlbuild/ocamlbuild_plugin.mli
@@ -0,0 +1,5 @@
+include Ocamlbuild_pack.Signatures.PLUGIN
+ with module Pathname = Ocamlbuild_pack.Pathname
+ and module Outcome = Ocamlbuild_pack.My_std.Outcome
+ and module Tags = Ocamlbuild_pack.Tags
+ and module Command = Ocamlbuild_pack.Command
diff --git a/ocamlbuild/ocamlbuild_where.mli b/ocamlbuild/ocamlbuild_where.mli
new file mode 100644
index 0000000000..ba8b3a720d
--- /dev/null
+++ b/ocamlbuild/ocamlbuild_where.mli
@@ -0,0 +1,14 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+val where : string ref
diff --git a/ocamlbuild/ocamlbuildlib.mllib b/ocamlbuild/ocamlbuildlib.mllib
new file mode 100644
index 0000000000..eb1598d64a
--- /dev/null
+++ b/ocamlbuild/ocamlbuildlib.mllib
@@ -0,0 +1,4 @@
+Executor
+My_unix_with_unix
+Ocamlbuild_pack
+Ocamlbuild_plugin
diff --git a/ocamlbuild/ocamlbuildlight.ml b/ocamlbuild/ocamlbuildlight.ml
new file mode 100644
index 0000000000..e0e90041ca
--- /dev/null
+++ b/ocamlbuild/ocamlbuildlight.ml
@@ -0,0 +1,14 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+Ocamlbuild_pack.Main.main ();;
diff --git a/ocamlbuild/ocamlbuildlight.mli b/ocamlbuild/ocamlbuildlight.mli
new file mode 100644
index 0000000000..274f0c4a23
--- /dev/null
+++ b/ocamlbuild/ocamlbuildlight.mli
@@ -0,0 +1,14 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* Nothing *)
diff --git a/ocamlbuild/ocamlbuildlightlib.mllib b/ocamlbuild/ocamlbuildlightlib.mllib
new file mode 100644
index 0000000000..dc38da3dc4
--- /dev/null
+++ b/ocamlbuild/ocamlbuildlightlib.mllib
@@ -0,0 +1,2 @@
+Ocamlbuild_pack
+Ocamlbuild_plugin
diff --git a/ocamlbuild/ocamldep.ml b/ocamlbuild/ocamldep.ml
new file mode 100644
index 0000000000..8bdfcde818
--- /dev/null
+++ b/ocamlbuild/ocamldep.ml
@@ -0,0 +1,72 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Log
+open Command
+open Tags.Operators
+open Tools
+open Ocaml_utils
+open Pathname.Operators
+
+exception Error of string
+
+let ocamldep_command arg =
+ let tags = tags_of_pathname arg++"ocaml"++"ocamldep" in
+ S [!Options.ocamldep; T tags; ocaml_ppflags tags;
+ flags_of_pathname arg; A "-modules"]
+
+let menhir_ocamldep_command arg out =
+ let tags = tags_of_pathname arg++"ocaml"++"menhir_ocamldep" in
+ Cmd (S [!Options.ocamlyacc; T tags; A"--raw-depend";
+ A"--ocamldep"; Quote (ocamldep_command arg);
+ P arg; Sh ">"; Px out])
+
+let ocamldep_command arg out =
+ Cmd (S[ocamldep_command arg; P arg; Sh ">"; Px out])
+
+let module_dependencies = Hashtbl.create 103
+let module_dependencies_of module_path =
+ try Hashtbl.find module_dependencies module_path with Not_found -> []
+let register_module_dependencies module_path deps =
+ Hashtbl.replace module_dependencies module_path
+ (List.union (module_dependencies_of module_path) (List.filter (keep_this_module module_path) deps))
+
+let depends name ?tags ~prod ~dep ?insert ?(ocamldep_command=ocamldep_command) () =
+ Rule.custom_rule name ?tags ~prod ~dep ?insert
+ ~cache:(fun env -> Command.to_string (ocamldep_command (env dep) (env prod)))
+ begin fun env ~cached ->
+ let arg = env dep in
+ let out = env prod in
+ let cmd = ocamldep_command arg out in
+ let () = dprintf 6 "ocamldep: %a %a" Pathname.print arg Command.print cmd in
+ if not (Pathname.exists arg) then
+ raise (Error(sbprintf "Ocamldep.ocamldep: no input file (%a)" Pathname.print arg))
+ else begin
+ Command.execute ~pretend:cached cmd;
+ with_input_file out begin fun ic ->
+ let ocamldep_output =
+ try Lexers.ocamldep_output (Lexing.from_channel ic)
+ with Lexers.Error msg -> raise (Error(Printf.sprintf "Ocamldep.ocamldep: bad output (%s)" msg)) in
+ let ocamldep_output =
+ List.fold_right begin fun (_, deps) acc ->
+ List.union deps acc
+ end ocamldep_output [] in
+ let ocamldep_output =
+ if !Options.nostdlib && not (Tags.mem "nopervasives" (tags_of_pathname arg)) then
+ "Pervasives" :: ocamldep_output
+ else ocamldep_output in
+ register_module_dependencies arg ocamldep_output
+ end
+ end
+ end
diff --git a/ocamlbuild/ocamldep.mli b/ocamlbuild/ocamldep.mli
new file mode 100644
index 0000000000..b576616285
--- /dev/null
+++ b/ocamlbuild/ocamldep.mli
@@ -0,0 +1,26 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+exception Error of string
+val ocamldep_command : Pathname.t -> Pathname.t -> Command.t
+val menhir_ocamldep_command : Pathname.t -> Pathname.t -> Command.t
+val module_dependencies_of : Pathname.t -> string list
+val register_module_dependencies : Pathname.t -> string list -> unit
+val depends :
+ string ->
+ ?tags:string list ->
+ prod:string ->
+ dep:string ->
+ ?insert:[`top | `before of string | `after of string | `bottom] ->
+ ?ocamldep_command:(Pathname.t -> Pathname.t -> Command.t) ->
+ unit -> unit
diff --git a/ocamlbuild/options.ml b/ocamlbuild/options.ml
new file mode 100644
index 0000000000..cc46b9f36a
--- /dev/null
+++ b/ocamlbuild/options.ml
@@ -0,0 +1,194 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+
+let version = "ocamlbuild 0.1";;
+
+type command_spec = Command.spec
+
+open My_std
+open Arg
+open Format
+open Command
+
+let entry = ref None
+let build_dir = ref "_build"
+let include_dirs = ref []
+let exclude_dirs = ref []
+let nothing_should_be_rebuilt = ref false
+let sterilize = ref false
+let hygiene = ref true
+let ignore_auto = ref true
+let plugin = ref true
+let just_plugin = ref false
+let native_plugin = ref true
+let make_links = ref true
+let nostdlib = ref false
+let use_menhir = ref false
+let ocamlc = ref (A"ocamlc.opt")
+let ocamlopt = ref (A"ocamlopt.opt")
+let ocamldep = ref (A"ocamldep.opt")
+let ocamldoc = ref (A"ocamldoc.opt")
+let ocamlyacc = ref (A"ocamlyacc")
+let ocamllex = ref (A"ocamllex")
+let ocamlmklib = ref (A"ocamlmklib")
+let ocamlrun = ref N
+let program_to_execute = ref false
+let must_clean = ref false
+let ext_lib = ref "a"
+let ext_obj = ref "o"
+let ext_dll = ref "so"
+
+let targets_internal = ref []
+let ocaml_libs_internal = ref []
+let ocaml_lflags_internal = ref []
+let ocaml_cflags_internal = ref []
+let ocaml_ppflags_internal = ref []
+let ocaml_yaccflags_internal = ref []
+let ocaml_lexflags_internal = ref []
+let program_args_internal = ref []
+let ignore_list_internal = ref []
+let tags_internal = ref [["quiet"]]
+
+let my_include_dirs = ref [[Filename.current_dir_name]]
+let my_exclude_dirs = ref [[".svn"; "CVS"]]
+
+let pwd = Sys.getcwd ()
+
+let internal_log_file = ref None
+let set_log_file file =
+ internal_log_file := Some file;
+ Log.log_file := lazy begin
+ if !Log.level <= 0
+ || ((!plugin || !just_plugin)
+ && sys_file_exists (filename_concat pwd "myocamlbuild.ml")) then
+ None
+ else Some(filename_concat pwd file)
+ end
+
+let () = set_log_file "_log"
+
+let dummy = "*invalid-dummy-string*";; (* Dummy string for delimiting the latest argument *)
+
+let add_to rxs x =
+ let xs = Lexers.comma_sep_strings (Lexing.from_string x) in
+ rxs := xs :: !rxs
+let add_to' rxs x =
+ if x <> dummy then
+ rxs := [x] :: !rxs
+ else
+ ()
+let set_cmd rcmd = String (fun s -> rcmd := Sh s)
+let spec =
+ Arg.align
+ [
+ "-version", Unit (fun () -> print_endline version; raise Exit_OK), " Display the version";
+ "-quiet", Unit (fun () -> Log.level := 0), " Make as quiet as possible";
+ "-verbose", Int (fun i -> Log.level := i + 2), "<level> Set the verbosity level";
+ "-log", String set_log_file, "<file> Set log file";
+ "-no-log", Unit (fun () -> Log.log_file := lazy None), " No log file";
+ "-clean", Set must_clean, " Remove build directory and other files, then exit";
+
+ "-I", String (add_to' my_include_dirs), "<path> Add to include directories";
+ "-Is", String (add_to my_include_dirs), "<path,...> (same as above, but accepts a comma-separated list)";
+ "-X", String (add_to' my_exclude_dirs), "<path> Directory to ignore";
+ "-Xs", String (add_to my_exclude_dirs), "<path,...> (idem)";
+
+ "-lib", String (add_to' ocaml_libs_internal), "<flag> Link to this ocaml library";
+ "-libs", String (add_to ocaml_libs_internal), "<flag,...> (idem)";
+ "-lflag", String (add_to' ocaml_lflags_internal), "<flag> Add to ocamlc link flags";
+ "-lflags", String (add_to ocaml_lflags_internal), "<flag,...> (idem)";
+ "-cflag", String (add_to' ocaml_cflags_internal), "<flag> Add to ocamlc compile flags";
+ "-cflags", String (add_to ocaml_cflags_internal), "<flag,...> (idem)";
+ "-yaccflag", String (add_to' ocaml_yaccflags_internal), "<flag> Add to ocamlyacc flags";
+ "-yaccflags", String (add_to ocaml_yaccflags_internal), "<flag,...> (idem)";
+ "-lexflag", String (add_to' ocaml_lexflags_internal), "<flag> Add to ocamllex flags";
+ "-lexflags", String (add_to ocaml_lexflags_internal), "<flag,...> (idem)";
+ "-ppflag", String (add_to' ocaml_ppflags_internal), "<flag> Add to ocaml preprocessing flags";
+ "-pp", String (add_to ocaml_ppflags_internal), "<flag,...> (idem)";
+ "-tag", String (add_to' tags_internal), "<tag> Add to default tags";
+ "-tags", String (add_to tags_internal), "<tag,...> (idem)";
+
+ "-ignore", String (add_to ignore_list_internal), "<module,...> Don't try to build these modules";
+ "-no-links", Clear make_links, " Don't make links of produced final targets";
+ "-no-skip", Clear ignore_auto, " Don't skip modules that are requested by ocamldep but cannot be built";
+ "-no-hygiene", Clear hygiene, " Don't apply sanity-check rules";
+ "-no-plugin", Clear plugin, " Don't build myocamlbuild.ml";
+ "-no-stdlib", Set nostdlib, " Don't ignore stdlib modules";
+ "-just-plugin", Set just_plugin, " Just build myocamlbuild.ml";
+ "-byte-plugin", Clear native_plugin, " Don't use a native plugin but bytecode";
+ "-sterilize", Set sterilize, " Enforce sanity-check rules by removing leftover files (DANGER)";
+ "-nothing-should-be-rebuilt", Set nothing_should_be_rebuilt, " Fail if something needs to be rebuilt";
+ "-classic-display", Set Log.classic_display, " Display executed commands the old-fashioned way";
+ "-use-menhir", Unit(fun () -> use_menhir := true; ocamlyacc := A"menhir"),
+ " Use menhir instead of ocamlyacc";
+
+ "-j", Set_int Command.jobs, "<N> Allow N jobs at once (0 for unlimited)";
+
+ "-build-dir", Set_string build_dir, "<path> Set build directory";
+ "-install-dir", Set_string Ocamlbuild_where.where, "<path> Set the install directory";
+ "-where", Unit (fun () -> print_endline !Ocamlbuild_where.where; raise Exit_OK), " Display the install directory";
+
+ "-ocamlc", set_cmd ocamlc, "<command> Set the OCaml bytecode compiler";
+ "-ocamlopt", set_cmd ocamlopt, "<command> Set the OCaml native compiler";
+ "-ocamldep", set_cmd ocamldep, "<command> Set the OCaml dependency tool";
+ "-ocamlyacc", set_cmd ocamlyacc, "<command> Set the ocamlyacc tool";
+ "-menhir", set_cmd ocamlyacc, "<command> Set the menhir tool (use it after -use-menhir)";
+ "-ocamllex", set_cmd ocamllex, "<command> Set the ocamllex tool";
+ (* Not set since we perhaps want to replace ocamlmklib *)
+ (* "-ocamlmklib", set_cmd ocamlmklib, "<command> Set the ocamlmklib tool"; *)
+ "-ocamlrun", set_cmd ocamlrun, "<command> Set the ocamlrun tool";
+
+ "--", Rest (fun x -> program_to_execute := true; add_to' program_args_internal x),
+ " Stop argument processing, remaining arguments are given to the user program";
+ ]
+
+let targets = ref []
+let ocaml_libs = ref []
+let ocaml_lflags = ref []
+let ocaml_cflags = ref []
+let ocaml_ppflags = ref []
+let ocaml_yaccflags = ref []
+let ocaml_lexflags = ref []
+let program_args = ref []
+let ignore_list = ref []
+let tags = ref []
+
+let init () =
+ let anon_fun = add_to' targets_internal in
+ let usage_msg = sprintf "Usage %s [options] <target>" Sys.argv.(0) in
+ let argv' = Array.concat [Sys.argv; [|dummy|]] in
+ parse_argv argv' spec anon_fun usage_msg;
+ Shell.mkdir_p !build_dir;
+ let reorder x y = x := (List.concat (List.rev !y)) in
+ reorder targets targets_internal;
+ reorder ocaml_libs ocaml_libs_internal;
+ reorder ocaml_cflags ocaml_cflags_internal;
+ reorder ocaml_lflags ocaml_lflags_internal;
+ reorder ocaml_ppflags ocaml_ppflags_internal;
+ reorder ocaml_yaccflags ocaml_yaccflags_internal;
+ reorder ocaml_lexflags ocaml_lexflags_internal;
+ reorder program_args program_args_internal;
+ reorder tags tags_internal;
+ reorder ignore_list ignore_list_internal;
+
+ let dir_reorder my dir =
+ let d = !dir in
+ reorder dir my;
+ dir := List.filter sys_file_exists (!dir @ d)
+ in
+ dir_reorder my_include_dirs include_dirs;
+ dir_reorder my_exclude_dirs exclude_dirs;
+
+ ignore_list := List.map String.capitalize !ignore_list
+;;
diff --git a/ocamlbuild/options.mli b/ocamlbuild/options.mli
new file mode 100644
index 0000000000..0d94c5d0b2
--- /dev/null
+++ b/ocamlbuild/options.mli
@@ -0,0 +1,18 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+
+include Signatures.OPTIONS with type command_spec = Command.spec
+
+val entry : bool Slurp.entry option ref
+val init : unit -> unit
diff --git a/ocamlbuild/pathname.ml b/ocamlbuild/pathname.ml
new file mode 100644
index 0000000000..24793ddfb8
--- /dev/null
+++ b/ocamlbuild/pathname.ml
@@ -0,0 +1,194 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Format
+open Log
+
+type t = string
+
+include Filename
+
+let print_strings = List.print String.print
+
+let concat = filename_concat
+
+let compare = compare
+
+let print = pp_print_string
+
+let mk s = s
+
+let pwd = Sys.getcwd ()
+
+let add_extension ext x = x ^ "." ^ ext
+
+let check_extension x ext =
+ let lx = String.length x and lext = String.length ext in
+ lx > lext + 1 && x.[lx - lext - 1] = '.' && String.is_suffix x ext
+
+module Operators = struct
+ let ( / ) = concat
+ let ( -.- ) file ext = add_extension ext file
+end
+open Operators
+
+let in_source_dir p =
+ if is_implicit p then pwd/p else invalid_arg (sprintf "in_source_dir: %S" p)
+
+let equal x y = x = y
+
+let to_string x = x
+
+let is_link = Shell.is_link
+let readlink = Shell.readlink
+let is_directory x =
+ try (My_unix.stat x).My_unix.stat_file_kind = My_unix.FK_dir
+ with Sys_error _ -> false
+let readdir x = Outcome.good (sys_readdir x)
+
+let dir_seps = ['/';'\\'] (* FIXME add more *)
+let parent x = concat parent_dir_name x
+
+(* [is_prefix x y] is [x] a pathname prefix of [y] *)
+let is_prefix x y =
+ let lx = String.length x and ly = String.length y in
+ if lx = ly then x = (String.before y lx)
+ else if lx < ly then x = (String.before y lx) && List.mem y.[lx] dir_seps
+ else false
+
+let link_to_dir p dir = is_link p && is_prefix dir (readlink p)
+
+let remove_extension x =
+ try chop_extension x
+ with Invalid_argument _ -> x
+let get_extension x =
+ try
+ let pos = String.rindex x '.' in
+ String.after x (pos + 1)
+ with Not_found -> ""
+let update_extension ext x =
+ add_extension ext (chop_extension x)
+
+let chop_extensions x =
+ let dirname = dirname x and basename = basename x in
+ try
+ let pos = String.index basename '.' in
+ dirname / (String.before basename pos)
+ with Not_found -> invalid_arg "chop_extensions: no extensions"
+let remove_extensions x =
+ try chop_extensions x
+ with Invalid_argument _ -> x
+let get_extensions x =
+ let basename = basename x in
+ try
+ let pos = String.index basename '.' in
+ String.after basename (pos + 1)
+ with Not_found -> ""
+let update_extensions ext x =
+ add_extension ext (chop_extensions x)
+
+let clean_up_links entry =
+ Slurp.filter begin fun path name _ ->
+ let pathname = in_source_dir (path/name) in
+ if link_to_dir pathname !Options.build_dir then
+ let z = readlink pathname in
+ (if not (Sys.file_exists z) then
+ Shell.rm pathname; false)
+ else true
+ end entry
+
+let clean_up_link_to_build () =
+ Options.entry := Some(clean_up_links (the !Options.entry))
+
+let source_dir_path_set_without_links_to_build =
+ lazy begin
+ clean_up_link_to_build ();
+ Slurp.fold (fun path name _ -> StringSet.add (path/name))
+ (the !Options.entry) StringSet.empty
+ end
+
+let exists_in_source_dir p =
+ if !*My_unix.is_degraded then sys_file_exists (in_source_dir p)
+ else StringSet.mem p !*source_dir_path_set_without_links_to_build
+
+let clean_links () =
+ if !*My_unix.is_degraded then
+ ()
+ else
+ ignore (clean_up_link_to_build ())
+
+let exists = sys_file_exists
+
+let copy = Shell.cp
+let remove = Shell.rm
+let try_remove x = if exists x then Shell.rm x
+let read = read_file
+
+let with_input_file = with_input_file
+
+let with_output_file = with_output_file
+
+let print_path_list = List.print print
+
+let root = mk "__root__"
+
+let context_table = Hashtbl.create 107
+
+let merge_include_dirs a b =
+ let rec aux a b =
+ match a, b with
+ | [], _ -> b
+ | _, [] -> a
+ | _, x::xs ->
+ if List.mem x a then aux a xs
+ else aux (x :: a) xs
+ in List.rev (aux (List.rev a) b)
+
+let define_context dir context =
+ let dir = if dir = "" then current_dir_name else dir in
+ try
+ let context = merge_include_dirs context (Hashtbl.find context_table dir) in
+ Hashtbl.replace context_table dir context
+ with Not_found ->
+ let context = merge_include_dirs context (!Options.include_dirs) in
+ Hashtbl.add context_table dir context
+
+let rec include_dirs_of dir =
+ try Hashtbl.find context_table dir
+ with Not_found -> dir :: List.filter (fun dir' -> dir <> dir') !Options.include_dirs
+
+(*
+let include_dirs_of s =
+ let res = include_dirs_of s in
+ let () = dprintf 0 "include_dirs_of %S ->@ %a" s (List.print print) res
+ in res
+*)
+
+let in_build_dir p =
+ if is_relative p then p
+ else
+ root/p (* XXX: Never reached *)
+
+let exists_in_build_dir p = exists (in_build_dir p)
+
+let same_contents x y = Digest.file x = Digest.file y
+
+let is_up_to_date b p =
+ let x = in_build_dir p in
+ if b then exists_in_source_dir p && exists x && same_contents x (in_source_dir p)
+ else not (exists_in_source_dir p) || exists x && same_contents x (in_source_dir p)
+
+let import_in_build_dir p =
+ let p_in_build_dir = in_build_dir p in
+ Shell.mkdir_p (dirname p); copy (in_source_dir p) p_in_build_dir
diff --git a/ocamlbuild/pathname.mli b/ocamlbuild/pathname.mli
new file mode 100644
index 0000000000..1bd1f09dbe
--- /dev/null
+++ b/ocamlbuild/pathname.mli
@@ -0,0 +1,22 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+include Signatures.PATHNAME
+
+val is_up_to_date : bool -> t -> bool
+val clean_up_links : bool Slurp.entry -> bool Slurp.entry
+val exists_in_source_dir : t -> bool
+val exists_in_build_dir : t -> bool
+val import_in_build_dir : t -> unit
+val in_build_dir : t -> t
+val in_source_dir : t -> t
diff --git a/ocamlbuild/plugin.ml b/ocamlbuild/plugin.ml
new file mode 100644
index 0000000000..88516d517f
--- /dev/null
+++ b/ocamlbuild/plugin.ml
@@ -0,0 +1,111 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Format
+open Log
+open Pathname.Operators
+open Tags.Operators
+open Rule
+open Tools
+open Command
+;;
+
+module Make(U:sig end) =
+ struct
+ let plugin = "myocamlbuild"
+ let plugin_file = plugin^".ml"
+ let plugin_config_file = plugin^"_config.ml"
+ let plugin_config_file_interface = plugin^"_config.mli"
+
+ let we_have_a_config_file = sys_file_exists plugin_config_file
+ let we_need_a_plugin = !Options.plugin && sys_file_exists plugin_file
+ let we_have_a_plugin = sys_file_exists (!Options.build_dir/plugin)
+ let we_have_a_config_file_interface = sys_file_exists plugin_config_file_interface
+
+ let up_to_date_or_copy fn =
+ let fn' = !Options.build_dir/fn in
+ Pathname.exists fn &&
+ begin
+ Pathname.exists fn' && Pathname.same_contents fn fn' ||
+ begin
+ Shell.cp fn fn';
+ false
+ end
+ end
+
+ let profiling = Tags.mem "profile" (tags_of_pathname plugin_file)
+
+ let debugging = Tags.mem "debug" (tags_of_pathname plugin_file)
+
+ let rebuild_plugin_if_needed () =
+ let a = up_to_date_or_copy plugin_file in
+ let b = (not we_have_a_config_file) or up_to_date_or_copy plugin_config_file in
+ let c = (not we_have_a_config_file_interface) or up_to_date_or_copy plugin_config_file_interface in
+ if a && b && c && we_have_a_plugin then
+ () (* Up to date *)
+ (* FIXME: remove ocamlbuild_config.ml in _build/ if removed in parent *)
+ else begin
+ let plugin_config =
+ if we_have_a_config_file then
+ if we_have_a_config_file_interface then
+ S[P plugin_config_file_interface; P plugin_config_file]
+ else P plugin_config_file
+ else N in
+ let cma, cmo, more_options, compiler =
+ if !Options.native_plugin then
+ "cmxa", "cmx", (if profiling then A"-p" else N), !Options.ocamlopt
+ else
+ "cma", "cmo", (if debugging then A"-g" else N), !Options.ocamlc
+ in
+ let ocamlbuildlib, ocamlbuild, libs =
+ if (not !Options.native_plugin) && !*My_unix.is_degraded then
+ "ocamlbuildlightlib", "ocamlbuildlight", N
+ else
+ "ocamlbuildlib", "ocamlbuild", A("unix"-.-cma)
+ in
+ let ocamlbuildlib = ocamlbuildlib-.-cma in
+ let ocamlbuild = ocamlbuild-.-cmo in
+ let dir = !Ocamlbuild_where.where in
+ if not (sys_file_exists (dir/ocamlbuildlib)) then
+ failwith (sprintf "Cannot found %S in ocamlbuild -where directory" ocamlbuildlib);
+ let dir = if Pathname.is_implicit dir then Pathname.pwd/dir else dir in
+ let cmd =
+ Cmd(S[compiler; A"-I"; P dir; libs; more_options;
+ P(dir/ocamlbuildlib); plugin_config; P plugin_file;
+ P(dir/ocamlbuild); A"-o"; Px plugin])
+ in
+ Shell.chdir !Options.build_dir;
+ Shell.rm_f plugin;
+ Command.execute cmd
+ end
+
+ let execute_plugin_if_needed () =
+ if we_need_a_plugin then
+ begin
+ rebuild_plugin_if_needed ();
+ Shell.chdir Pathname.pwd;
+ if not !Options.just_plugin then
+ let spec = S[!Options.ocamlrun; P(!Options.build_dir/plugin);
+ A"-no-plugin"; atomize (List.tl (Array.to_list Sys.argv))] in
+ raise (Exit_silently_with_code (sys_command (Command.string_of_command_spec spec)))
+ end
+ else
+ ()
+ end
+;;
+
+let execute_plugin_if_needed () =
+ let module P = Make(struct end) in
+ P.execute_plugin_if_needed ()
+;;
diff --git a/ocamlbuild/plugin.mli b/ocamlbuild/plugin.mli
new file mode 100644
index 0000000000..a6d85b3404
--- /dev/null
+++ b/ocamlbuild/plugin.mli
@@ -0,0 +1,16 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* Plugin *)
+
+val execute_plugin_if_needed : unit -> unit
diff --git a/ocamlbuild/ppcache.ml b/ocamlbuild/ppcache.ml
new file mode 100644
index 0000000000..fe7a7d7442
--- /dev/null
+++ b/ocamlbuild/ppcache.ml
@@ -0,0 +1,88 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Command
+open Pathname.Operators
+let () = Log.level := -1000
+
+let usage () =
+ Format.eprintf "Usage: %s <preprocess-command> <preprocess-args>@." Sys.argv.(0);
+ exit 4
+
+let () = if Array.length Sys.argv < 2 then usage ()
+
+let args = List.tl (Array.to_list Sys.argv)
+
+let buf = Buffer.create 2048
+
+let digest_file file =
+ Buffer.add_string buf (Digest.file file)
+let digest_string string =
+ Buffer.add_string buf (Digest.string string)
+
+let search_in_path x =
+ if Sys.file_exists x then x else
+ try search_in_path x
+ with Not_found -> (Format.eprintf "Command not found %s@." x; exit 3)
+
+let cmd =
+ match args with
+ | ocamlrun :: x :: _ when String.contains_string ocamlrun 0 "ocamlrun" <> None ->
+ digest_file (search_in_path ocamlrun); x
+ | x :: _ -> x
+ | _ -> usage ()
+
+let output = ref ""
+
+let () = digest_file (search_in_path cmd)
+
+let rec loop =
+ function
+ | [] -> Digest.string (Buffer.contents buf)
+ | ("-impl"|"-intf") :: x :: xs ->
+ digest_string x; digest_file x; loop xs
+ | "-o" :: x :: xs ->
+ output := x; loop xs
+ | x :: xs ->
+ let ext = Pathname.get_extension x in
+ digest_string x;
+ (match ext with
+ | "cmo" | "cma" | "ml" | "mli" -> digest_file x
+ | _ -> ());
+ loop xs
+
+let digest = loop args;;
+
+let cache_dir = "/tmp/ppcache";; (* FIXME *)
+
+let () = Shell.mkdir_p cache_dir;;
+
+let path = cache_dir/(Digest.to_hex digest);;
+
+if sys_file_exists path then
+ if !output = "" then
+ print_string (read_file path)
+ else
+ Shell.cp path !output
+else
+ let cmd = atomize args in
+ if !output = "" then begin
+ let tmp = path^".tmp" in
+ Command.execute (Cmd(S[cmd; Sh ">"; A tmp]));
+ Shell.mv tmp path;
+ print_string (read_file path)
+ end else begin
+ Command.execute (Cmd cmd);
+ Shell.cp !output path
+ end
diff --git a/ocamlbuild/ppcache.mli b/ocamlbuild/ppcache.mli
new file mode 100644
index 0000000000..419a1f5cda
--- /dev/null
+++ b/ocamlbuild/ppcache.mli
@@ -0,0 +1,14 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* nothing to export *)
diff --git a/ocamlbuild/report.ml b/ocamlbuild/report.ml
new file mode 100644
index 0000000000..df9144ceab
--- /dev/null
+++ b/ocamlbuild/report.ml
@@ -0,0 +1,61 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Report *)
+
+open My_std
+open Log
+open Format
+open Solver
+
+let sources_glob = Glob.parse "<*.ml> or <*.mli> or <*.c> or <*.h>";;
+
+let rec analyze f bt =
+ match bt with
+ | Leaf r ->
+ fprintf f "Ocamlbuild knows of no rules that apply to a target named %a. \
+ This can happen if you ask Ocamlbuild to build a target with the \
+ wrong extension (e.g. .opt instead of .native) or if the source \
+ files live in directories that have not been specified as \
+ include directories."
+ Resource.print r;
+ false
+ | Depth(r, bt) ->
+ if Glob.eval sources_glob r then
+ begin
+ fprintf f "Ocamlbuild cannot find or build %a. A file with such a name would \
+ usually be a source file. I suspect you have given a wrong target \
+ name to Ocamlbuild."
+ Resource.print r;
+ false
+ end
+ else
+ analyze f bt
+ | Choice bl -> List.for_all (analyze f) bl
+ | Target(_, bt) -> analyze f bt
+
+let rec print_backtrace f =
+ function
+ | Target (name, backtrace) ->
+ fprintf f "@\n- @[<2>Failed to build the target %s%a@]" name print_backtrace backtrace
+ | Leaf r ->
+ fprintf f "@\n- @[<2>Building %a@]" Resource.print r
+ | Depth (r, backtrace) ->
+ fprintf f "@\n- @[<v2>Building %a:%a@]" Resource.print r print_backtrace backtrace
+ | Choice [backtrace] -> print_backtrace f backtrace
+ | Choice backtraces ->
+ fprintf f "@\n- @[<v2>Failed to build all of these:";
+ List.iter (print_backtrace f) backtraces;
+ fprintf f "@]"
+
+let print_backtrace_analyze f bt = ignore (analyze f bt)
diff --git a/ocamlbuild/report.mli b/ocamlbuild/report.mli
new file mode 100644
index 0000000000..f95fa7bf02
--- /dev/null
+++ b/ocamlbuild/report.mli
@@ -0,0 +1,18 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Report *)
+
+val print_backtrace_analyze : Format.formatter -> Solver.backtrace -> unit
+
+val print_backtrace : Format.formatter -> Solver.backtrace -> unit
diff --git a/ocamlbuild/resource.ml b/ocamlbuild/resource.ml
new file mode 100644
index 0000000000..3ab416eb1a
--- /dev/null
+++ b/ocamlbuild/resource.ml
@@ -0,0 +1,324 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Format
+open Log
+
+module Resources = Set.Make(Pathname)
+
+let print = Pathname.print
+
+let equal = (=)
+let compare = compare
+
+module Cache = struct
+ open Pathname.Operators
+
+ let clean () = Shell.chdir Pathname.pwd; Shell.rm_rf !Options.build_dir
+
+ type knowledge =
+ | Yes
+ | No
+ | Unknown
+
+ type suspension = (Command.t * (unit -> unit))
+
+ type build_status =
+ | Bbuilt
+ | Bcannot_be_built
+ | Bnot_built_yet
+ | Bsuspension of suspension
+
+ type cache_entry =
+ { mutable built : build_status;
+ mutable changed : knowledge;
+ mutable dependencies : Resources.t }
+
+ let empty () =
+ { built = Bnot_built_yet;
+ changed = Unknown;
+ dependencies = Resources.empty }
+
+ let print_knowledge f =
+ function
+ | Yes -> pp_print_string f "Yes"
+ | No -> pp_print_string f "No"
+ | Unknown -> pp_print_string f "Unknown"
+
+ let print_build_status f =
+ function
+ | Bbuilt -> pp_print_string f "Bbuilt"
+ | Bnot_built_yet -> pp_print_string f "Bnot_built_yet"
+ | Bcannot_be_built -> pp_print_string f "Bcannot_be_built"
+ | Bsuspension(cmd, _) ->
+ fprintf f "@[<2>Bsuspension(%a,@ (<fun> : unit -> unit))@]" Command.print cmd
+
+ let print_cache_entry f e =
+ fprintf f "@[<2>{ @[<2>built =@ %a@];@ @[<2>changed =@ %a@];@ @[<2>dependencies =@ %a@]@ }@]"
+ print_build_status e.built print_knowledge e.changed Resources.print e.dependencies
+
+ let cache = Hashtbl.create 103
+
+ let get r =
+ try Hashtbl.find cache r
+ with Not_found ->
+ let cache_entry = empty () in
+ Hashtbl.add cache r cache_entry; cache_entry
+
+ let fold_cache f x = Hashtbl.fold f cache x
+
+ let print_cache f () =
+ fprintf f "@[<hv0>@[<hv2>{:";
+ fold_cache begin fun k v () ->
+ fprintf f "@ @[<2>%a =>@ %a@];" print k print_cache_entry v
+ end ();
+ fprintf f "@]:}@]"
+
+ let print_graph f () =
+ fprintf f "@[<hv0>@[<hv2>{:";
+ fold_cache begin fun k v () ->
+ if not (Resources.is_empty v.dependencies) then
+ fprintf f "@ @[<2>%a =>@ %a@];" print k Resources.print v.dependencies
+ end ();
+ fprintf f "@]@ :}@]"
+
+ let resource_changed r =
+ dprintf 10 "resource_changed:@ %a" print r;
+ (get r).changed <- Yes
+
+ let rec resource_has_changed r =
+ let cache_entry = get r in
+ match cache_entry.changed with
+ | Yes -> true
+ | No -> false
+ | Unknown ->
+ let res =
+ match cache_entry.built with
+ | Bbuilt -> false
+ | Bsuspension _ -> assert false
+ | Bcannot_be_built -> false
+ | Bnot_built_yet -> not (Pathname.is_up_to_date false r) in
+ let () = cache_entry.changed <- if res then Yes else No in res
+
+ let resource_state r = (get r).built
+
+ let resource_is_built r = (get r).built = Bbuilt
+
+ let resource_built r = (get r).built <- Bbuilt
+
+ let resource_is_failed r = (get r).built = Bcannot_be_built
+
+ let resource_failed r = (get r).built <- Bcannot_be_built
+
+ let suspend_resource r cmd kont prods =
+ let cache_entry = get r in
+ match cache_entry.built with
+ | Bsuspension _ -> ()
+ | Bbuilt -> ()
+ | Bcannot_be_built -> assert false
+ | Bnot_built_yet ->
+ let kont = begin fun () ->
+ kont ();
+ List.iter begin fun prod ->
+ (get prod).built <- Bbuilt
+ end prods
+ end in cache_entry.built <- Bsuspension(cmd, kont)
+
+ let resume_suspension (cmd, kont) =
+ Command.execute cmd;
+ kont ()
+
+ let resume_resource r =
+ let cache_entry = get r in
+ match cache_entry.built with
+ | Bsuspension(s) -> resume_suspension s
+ | Bbuilt -> ()
+ | Bcannot_be_built -> ()
+ | Bnot_built_yet -> ()
+
+ let get_optional_resource_suspension r =
+ match (get r).built with
+ | Bsuspension cmd_kont -> Some cmd_kont
+ | Bbuilt | Bcannot_be_built | Bnot_built_yet -> None
+
+ let clear_resource_failed r = (get r).built <- Bnot_built_yet
+
+ let dependencies r = (get r).dependencies
+
+ let fold_dependencies f =
+ fold_cache (fun k v -> Resources.fold (f k) v.dependencies)
+
+ let add_dependency r s =
+ let cache_entry = get r in
+ cache_entry.dependencies <- Resources.add s cache_entry.dependencies
+
+ let print_dependencies = print_graph
+
+ let digest_resource p =
+ let f = Pathname.to_string (Pathname.in_build_dir p) in
+ let buf = Buffer.create 1024 in
+ Buffer.add_string buf f;
+ (if sys_file_exists f then Buffer.add_string buf (Digest.file f));
+ Digest.string (Buffer.contents buf)
+
+ let digests = Hashtbl.create 103
+
+ let get_digest_for name =
+ try Some (Hashtbl.find digests name)
+ with Not_found -> None
+ let store_digest name d = Hashtbl.replace digests name d
+
+ let _digests = lazy (Pathname.pwd / !Options.build_dir / (Pathname.mk "_digests"))
+
+ let finalize () =
+ with_output_file !*_digests begin fun oc ->
+ Hashtbl.iter begin fun name digest ->
+ Printf.fprintf oc "%S: %S\n" name digest
+ end digests
+ end
+
+ let init () =
+ Shell.chdir !Options.build_dir;
+ if Pathname.exists !*_digests then
+ with_input_file !*_digests begin fun ic ->
+ try while true do
+ let l = input_line ic in
+ Scanf.sscanf l "%S: %S" store_digest
+ done with End_of_file -> ()
+ end;
+ My_unix.at_exit_once finalize
+
+end
+
+let clean p = Shell.rm_f p
+
+(*
+type env = string
+
+let split_percent s =
+ try
+ let pos = String.index s '%' in
+ Some (String.before s pos, String.after s (pos + 1))
+ with Not_found -> None
+
+let extract prefix suffix s =
+ let lprefix = String.length prefix in
+ let lsuffix = String.length suffix in
+ let ls = String.length s in
+ if lprefix + lsuffix > ls then None else
+ let s' = String.sub s lprefix (ls - lsuffix - lprefix) in
+ if equal (prefix ^ s' ^ suffix) s then Some s' else None
+
+let matchit r1 r2 =
+ match split_percent r1 with
+ | Some (x, y) -> extract x y r2
+ | _ -> if equal r1 r2 then Some "" else None
+
+let rec subst percent r =
+ match split_percent r with
+ | Some (x, y) -> x ^ percent ^ y
+ | _ -> r
+
+let print_env = pp_print_string
+*)
+
+let is_up_to_date path = Pathname.is_up_to_date true path
+
+let import x = x
+
+module MetaPath : sig
+
+ type env
+
+ val matchit : string -> string -> env option
+ val subst : env -> string -> string
+ val print_env : Format.formatter -> env -> unit
+
+end = struct
+
+ type atoms = A of string | V of string
+ type t = atoms list
+ type env = (string * string) list
+
+ exception No_solution
+
+ let mk s = List.map (fun (s, is_var) -> if is_var then V s else A s) (Lexers.meta_path (Lexing.from_string s))
+
+ let mk = memo mk
+
+ let match_prefix s pos prefix =
+ match String.contains_string s pos prefix with
+ | Some(pos') -> if pos = pos' then pos' + String.length prefix else raise No_solution
+ | None -> raise No_solution
+
+ let matchit p s =
+ let sl = String.length s in
+ let rec loop xs pos acc =
+ match xs with
+ | [] -> if pos = sl then acc else raise No_solution
+ | A prefix :: xs -> loop xs (match_prefix s pos prefix) acc
+ | V var :: A s2 :: xs ->
+ begin match String.contains_string s pos s2 with
+ | Some(pos') -> loop xs (pos' + String.length s2) ((var, String.sub s pos (pos' - pos)) :: acc)
+ | None -> raise No_solution
+ end
+ | [V var] -> (var, String.sub s pos (sl - pos)) :: acc
+ | V _ :: _ -> assert false
+ in
+ try Some (loop (mk p) 0 [])
+ with No_solution -> None
+
+ let pp_opt pp_elt f =
+ function
+ | None -> pp_print_string f "None"
+ | Some x -> Format.fprintf f "Some(%a)" pp_elt x
+
+ let print_env f env =
+ List.iter begin fun (k, v) ->
+ if k = "" then Format.fprintf f "%%=%s " v
+ else Format.fprintf f "%%(%s)=%s " k v
+ end env
+
+ (* let matchit p s =
+ let res = matchit p s in
+ Format.eprintf "matchit %S %S = %a@." p s (pp_opt print_env) res;
+ res
+
+ let _ = begin
+ assert (matchit "%(path)lib%(libname).a" "libfoo.a" <> None);
+ assert (matchit "%(path)lib%(libname).a" "path/libfoo.a" <> None);
+ assert (matchit "libfoo.a" "libfoo.a" <> None);
+ assert (matchit "lib%(libname).a" "libfoo.a" <> None);
+ assert (matchit "%(path)libfoo.a" "path/libfoo.a" <> None);
+ assert (matchit "foo%" "foobar" <> None);
+ exit 42
+ end;; *)
+
+ let subst env s =
+ String.concat "" begin
+ List.map begin fun x ->
+ match x with
+ | A atom -> atom
+ | V var -> List.assoc var env
+ end (mk s)
+ end
+end
+
+type env = MetaPath.env
+
+let matchit = MetaPath.matchit
+
+let subst = MetaPath.subst
+
+let print_env = MetaPath.print_env
diff --git a/ocamlbuild/resource.mli b/ocamlbuild/resource.mli
new file mode 100644
index 0000000000..a0a6a4b87a
--- /dev/null
+++ b/ocamlbuild/resource.mli
@@ -0,0 +1,63 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+
+open Pathname
+type env
+
+module Resources : Set.S with type elt = t
+
+module Cache :
+ sig
+ type suspension
+
+ type build_status =
+ | Bbuilt
+ | Bcannot_be_built
+ | Bnot_built_yet
+ | Bsuspension of suspension
+
+ val clean : unit -> unit
+ val init : unit -> unit
+ val resource_state : t -> build_status
+ val resource_changed : t -> unit
+ val resource_has_changed : t -> bool
+ val resource_is_built : t -> bool
+ val resource_built : t -> unit
+ val resource_is_failed : t -> bool
+ val resource_failed : t -> unit
+ val suspend_resource : t -> Command.t -> (unit -> unit) -> t list -> unit
+ val resume_resource : t -> unit
+ val resume_suspension : suspension -> unit
+ val get_optional_resource_suspension : t -> (Command.t * (unit -> unit)) option
+ val clear_resource_failed : t -> unit
+ val dependencies : t -> Resources.t
+ val add_dependency : t -> t -> unit
+ val get_digest_for : string -> string option
+ val store_digest : string -> string -> unit
+ val digest_resource : t -> string
+ val print_cache : Format.formatter -> unit -> unit
+ val print_dependencies : Format.formatter -> unit -> unit
+ val fold_dependencies : (string -> string -> 'a -> 'a) -> 'a -> 'a
+ end
+
+val compare : t -> t -> int
+val print : Format.formatter -> t -> unit
+val clean : t -> unit
+val import : string -> t
+
+val matchit : t -> t -> env option
+val subst : env -> t -> t
+val is_up_to_date : t -> bool
+val print_env : Format.formatter -> env -> unit
diff --git a/ocamlbuild/rule.ml b/ocamlbuild/rule.ml
new file mode 100644
index 0000000000..d496f8716e
--- /dev/null
+++ b/ocamlbuild/rule.ml
@@ -0,0 +1,296 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Format
+open Log
+open Outcome
+module Resources = Resource.Resources
+
+exception Exit_rule_error of string
+
+type env = Pathname.t -> Pathname.t
+type builder = Pathname.t list list -> (Pathname.t, exn) Outcome.t list
+type action = env -> builder -> Command.t
+
+type t =
+ { name : string;
+ tags : Tags.t;
+ deps : Pathname.t list;
+ prods : Pathname.t list;
+ code : env -> builder -> Command.t }
+
+exception Code_digest of string * (bool -> unit)
+
+let compare _ _ = assert false
+
+let print_rule_name f r = pp_print_string f r.name
+
+let print_resource_list = List.print Resource.print
+
+let print_rule_contents f r =
+ fprintf f "@[<v2>{@ @[<2>name =@ %S@];@ @[<2>tags =@ %a@];@ @[<2>deps =@ %a@];@ @[<2>prods = %a@];@ @[<2>code = <fun>@]@]@ }"
+ r.name Tags.print r.tags print_resource_list r.deps print_resource_list r.prods
+
+let print = print_rule_name
+
+let subst env rule =
+ let subst_resources = List.map (Resource.subst env) in
+ let finder next_finder p = next_finder (Resource.subst env p) in
+ { (rule) with name = sbprintf "%s (%a)" rule.name Resource.print_env env;
+ prods = subst_resources rule.prods;
+ deps = subst_resources rule.deps;
+ code = (fun env -> rule.code (finder env)) }
+
+exception Can_produce of t
+
+let can_produce target rule =
+ try
+ List.iter begin fun resource ->
+ match Resource.matchit resource target with
+ | Some env -> raise (Can_produce (subst env rule))
+ | None -> ()
+ end rule.prods; None
+ with Can_produce r -> Some r
+
+let tags_matches tags r = if Tags.does_match tags r.tags then Some r else None
+
+let digest_prods r =
+ List.fold_right begin fun p acc ->
+ let f = Pathname.to_string (Pathname.in_build_dir p) in
+ if sys_file_exists f then (f, Digest.file f) :: acc else acc
+ end r.prods []
+
+let digest_rule r dyndeps cmd_or_digest =
+ let buf = Buffer.create 1024 in
+ (match cmd_or_digest with
+ | Good cmd -> Buffer.add_string buf (Command.to_string_for_digest cmd)
+ | Bad(s, _) -> Buffer.add_string buf s);
+ let add_resource r = Buffer.add_string buf (Resource.Cache.digest_resource r) in
+ Buffer.add_string buf "prods:";
+ List.iter add_resource r.prods;
+ Buffer.add_string buf "deps:";
+ List.iter add_resource r.deps;
+ Buffer.add_string buf "dyndeps:";
+ Resources.iter add_resource dyndeps;
+ Digest.string (Buffer.contents buf)
+
+let print_digest f x = pp_print_string f (Digest.to_hex x)
+
+let exists2 find p rs =
+ try Some (find p rs) with Not_found -> None
+
+let all_deps_of_tags = ref []
+
+let cons deps acc =
+ List.fold_left begin fun acc dep ->
+ if List.mem dep acc then acc else dep :: acc
+ end acc deps
+
+let deps_of_tags tags =
+ List.fold_left begin fun acc (xtags, xdeps) ->
+ if Tags.does_match tags xtags then cons xdeps acc
+ else acc
+ end [] !all_deps_of_tags
+
+let set_deps_of_tags tags deps =
+ all_deps_of_tags := (tags, deps) :: !all_deps_of_tags
+
+let dep tags deps = set_deps_of_tags (Tags.of_list tags) deps
+
+let build_deps_of_tags builder tags =
+ match deps_of_tags tags with
+ | [] -> []
+ | deps -> List.map Outcome.good (builder (List.map (fun x -> [x]) deps))
+
+let build_deps_of_tags_on_cmd builder x =
+ let rec spec x =
+ match x with
+ | Command.N | Command.A _ | Command.Sh _ | Command.P _ | Command.Px _ | Command.V _ | Command.Quote _ -> ()
+ | Command.S l -> List.iter spec l
+ | Command.T tags ->
+ begin match deps_of_tags tags with
+ | [] -> ()
+ | deps -> List.iter ignore_good (builder (List.map (fun x -> [x]) deps))
+ end in
+ let rec cmd x =
+ match x with
+ | Command.Nop -> ()
+ | Command.Cmd(s) -> spec s
+ | Command.Seq(s) -> List.iter cmd s in
+ cmd x
+
+let call builder r =
+ let dyndeps = ref Resources.empty in
+ let builder rs =
+ let results = builder rs in
+ List.map begin fun res ->
+ match res with
+ | Good res' ->
+ let () = dprintf 10 "new dyndep for %S(%a): %S" r.name print_resource_list r.prods res' in
+ dyndeps := Resources.add res' !dyndeps;
+ List.iter (fun x -> Resource.Cache.add_dependency x res') r.prods;
+ res
+ | Bad _ -> res
+ end results in
+ let () = dprintf 5 "start rule %a" print r in
+ let cmd_or_digest =
+ try
+ let cmd = r.code (fun x -> x) builder in
+ build_deps_of_tags_on_cmd builder cmd;
+ Good cmd
+ with Code_digest(s, kont) -> Bad(s, kont) in
+ let dyndeps = !dyndeps in
+ let () = dprintf 10 "dyndeps: %a" Resources.print dyndeps in
+ let (reason, cached) =
+ match exists2 List.find (fun r -> not (Pathname.exists_in_build_dir r)) r.prods with
+ | Some r -> (`cache_miss_missing_prod r, false)
+ | _ ->
+ begin match exists2 List.find Resource.Cache.resource_has_changed r.deps with
+ | Some r -> (`cache_miss_changed_dep r, false)
+ | _ ->
+ begin match exists2 Resources.find Resource.Cache.resource_has_changed dyndeps with
+ | Some r -> (`cache_miss_changed_dyn_dep r, false)
+ | _ ->
+ begin match Resource.Cache.get_digest_for r.name with
+ | None -> (`cache_miss_no_digest, false)
+ | Some d ->
+ begin match cmd_or_digest with
+ | Bad("", _) ->
+ (`cache_miss_undigest, false)
+ | Bad(_, _) | Good(_) ->
+ let rule_digest = digest_rule r dyndeps cmd_or_digest in
+ if d = rule_digest then (`cache_hit, true)
+ else (`cache_miss_digest_changed(d, rule_digest), false)
+ end
+ end
+ end
+ end
+ in
+ let explain_reason l =
+ raw_dprintf (l+1) "mid rule %a: " print r;
+ match reason with
+ | `cache_miss_missing_prod r ->
+ dprintf l "cache miss: a product is not in build dir (%a)" Resource.print r
+ | `cache_miss_changed_dep r ->
+ dprintf l "cache miss: a dependency has changed (%a)" Resource.print r
+ | `cache_miss_changed_dyn_dep r ->
+ dprintf l "cache miss: a dynamic dependency has changed (%a)" Resource.print r
+ | `cache_miss_no_digest ->
+ dprintf l "cache miss: no digest found for %S (the command, a dependency, or a product)"
+ r.name
+ | `cache_hit -> dprintf (l+1) "cache hit"
+ | `cache_miss_digest_changed(old_d, new_d) ->
+ dprintf l "cache miss: the digest has changed for %S (the command, a dependency, or a product: %a <> %a)"
+ r.name print_digest old_d print_digest new_d
+ | `cache_miss_undigest ->
+ dprintf l "cache miss: cache not supported for the rule %S" r.name in
+ let prod_digests = digest_prods r in
+ (if not cached then List.iter Resource.clean r.prods);
+ (if !Options.nothing_should_be_rebuilt && not cached then
+ (explain_reason (-1);
+ let msg = sbprintf "Need to rebuild %a through the rule `%a'" print_resource_list r.prods print r in
+ raise (Exit_rule_error msg)));
+ explain_reason 3;
+ let kont = begin fun () ->
+ try
+ (match cmd_or_digest with
+ | Good cmd -> if cached then Command.execute ~pretend:true cmd
+ | Bad (_, kont) -> kont cached);
+ List.iter Resource.Cache.resource_built r.prods;
+ (if not cached then
+ let new_rule_digest = digest_rule r dyndeps cmd_or_digest in
+ let new_prod_digests = digest_prods r in
+ let () = Resource.Cache.store_digest r.name new_rule_digest in
+ List.iter begin fun p ->
+ let f = Pathname.to_string (Pathname.in_build_dir p) in
+ (try let digest = List.assoc f prod_digests in
+ let new_digest = List.assoc f new_prod_digests in
+ if digest <> new_digest then raise Not_found
+ with Not_found -> Resource.Cache.resource_changed p)
+ end r.prods);
+ dprintf 5 "end rule %a" print r
+ with exn -> (List.iter Resource.clean r.prods; raise exn)
+ end in
+ match cmd_or_digest with
+ | Good cmd when not cached ->
+ List.iter (fun x -> Resource.Cache.suspend_resource x cmd kont r.prods) r.prods
+ | Bad _ | Good _ -> kont ()
+
+let (get_rules, add_rule) =
+ let rules = ref [] in
+ (fun () -> !rules),
+ begin fun pos r ->
+ try
+ let _ = List.find (fun x -> x.name = r.name) !rules in
+ raise (Exit_rule_error (sbprintf "Rule.add_rule: already exists: (%a)" print r))
+ with Not_found ->
+ match pos with
+ | `bottom -> rules := !rules @ [r]
+ | `top -> rules := r :: !rules
+ | `after s ->
+ rules :=
+ List.fold_right begin fun x acc ->
+ if x.name = s then x :: r :: acc else x :: acc
+ end !rules []
+ | `before s ->
+ rules :=
+ List.fold_right begin fun x acc ->
+ if x.name = s then r :: x :: acc else x :: acc
+ end !rules []
+ end
+
+let rule name ?(tags=[]) ?(prods=[]) ?(deps=[]) ?prod ?dep ?(insert = `bottom) code =
+ let res_add x acc =
+ let x = Resource.import x in
+ if List.mem x acc then
+ failwith (sprintf "in rule %s, multiple occurences of the resource %s" name x)
+ else x :: acc in
+ let res_of_opt = function None -> [] | Some r -> [Resource.import r] in
+ if prods = [] && prod = None then raise (Exit_rule_error "Can't make a rule that produce nothing");
+ add_rule insert
+ { name = name;
+ tags = List.fold_right Tags.add tags Tags.empty;
+ deps = List.fold_right res_add deps (res_of_opt dep);
+ prods = List.fold_right res_add prods (res_of_opt prod);
+ code = code }
+
+let file_rule name ?tags ~prod ?deps ?dep ?insert ~cache action =
+ rule name ?tags ~prod ?dep ?deps ?insert begin fun env _ ->
+ raise (Code_digest (cache env, (fun cached ->
+ if not cached then
+ with_output_file (env prod) (action env))))
+ end
+
+let custom_rule name ?tags ?prods ?prod ?deps ?dep ?insert ~cache action =
+ rule name ?tags ?prods ?prod ?dep ?deps ?insert begin fun env _ ->
+ raise (Code_digest (cache env, fun cached -> action env ~cached))
+ end
+
+module Common_commands = struct
+ open Command
+ let mv src dest = Cmd (S [A"mv"; P src; Px dest])
+ let cp src dest = Cmd (S [A"cp"; P src; Px dest])
+ let ln_f pointed pointer = Cmd (S [A"ln"; A"-f"; P pointed; Px pointer])
+ let ln_s pointed pointer = Cmd (S[A"ln"; A"-s"; P pointed; Px pointer])
+ let rm_f x = Cmd (S [A"rm"; A"-f"; Px x])
+ let touch file = Cmd (S[A"touch"; Px file])
+ let chmod opts file = Cmd (S[A"chmod"; opts; Px file])
+ let cmp a b = Cmd (S[A"cmp"; P a; Px b])
+end
+open Common_commands
+
+let copy_rule name ?insert src dest =
+ rule name ?insert ~prod:dest ~dep:src
+ (fun env _ -> cp (env src) (env dest))
+
diff --git a/ocamlbuild/rule.mli b/ocamlbuild/rule.mli
new file mode 100644
index 0000000000..690913a8e5
--- /dev/null
+++ b/ocamlbuild/rule.mli
@@ -0,0 +1,90 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Resource
+
+type env = Pathname.t -> Pathname.t
+type builder = Pathname.t list list -> (Pathname.t, exn) Outcome.t list
+type action = env -> builder -> Command.t
+
+type t = private
+ { name : string;
+ tags : Tags.t;
+ deps : Pathname.t list;
+ prods : Pathname.t list;
+ code : env -> builder -> Command.t }
+
+val rule : string ->
+ ?tags:string list ->
+ ?prods:string list ->
+ ?deps:string list ->
+ ?prod:string ->
+ ?dep:string ->
+ ?insert:[`top | `before of string | `after of string | `bottom] ->
+ action -> unit
+
+val file_rule : string ->
+ ?tags:string list ->
+ prod:string ->
+ ?deps:string list ->
+ ?dep:string ->
+ ?insert:[`top | `before of string | `after of string | `bottom] ->
+ cache:(env -> string) ->
+ (env -> out_channel -> unit) -> unit
+
+val custom_rule : string ->
+ ?tags:string list ->
+ ?prods:string list ->
+ ?prod:string ->
+ ?deps:string list ->
+ ?dep:string ->
+ ?insert:[`top | `before of string | `after of string | `bottom] ->
+ cache:(env -> string) ->
+ (env -> cached:bool -> unit) -> unit
+
+(** [copy_rule name ?insert source destination] *)
+val copy_rule : string ->
+ ?insert:[`top | `before of string | `after of string | `bottom] ->
+ string -> string -> unit
+
+(** [dep tags deps] Will build [deps] when [tags] will be activated. *)
+val dep : string list -> string list -> unit
+
+module Common_commands : sig
+ val mv : Pathname.t -> Pathname.t -> Command.t
+ val cp : Pathname.t -> Pathname.t -> Command.t
+ val ln_f : Pathname.t -> Pathname.t -> Command.t
+ val ln_s : Pathname.t -> Pathname.t -> Command.t
+ val rm_f : Pathname.t -> Command.t
+ val touch : Pathname.t -> Command.t
+ val chmod : Command.spec -> Pathname.t -> Command.t
+ val cmp : Pathname.t -> Pathname.t -> Command.t
+end
+
+(** For system use only *)
+
+val subst : Resource.env -> t -> t
+val can_produce : Pathname.t -> t -> t option
+val tags_matches : Tags.t -> t -> t option
+val compare : t -> t -> int
+
+val print_rule_name : Format.formatter -> t -> unit
+val print_rule_contents : Format.formatter -> t -> unit
+val print : Format.formatter -> t -> unit
+
+val get_rules : unit -> t list
+
+val call : builder -> t -> unit
+
+val build_deps_of_tags : builder -> Tags.t -> Pathname.t list
diff --git a/ocamlbuild/shell.ml b/ocamlbuild/shell.ml
new file mode 100644
index 0000000000..9c056ff397
--- /dev/null
+++ b/ocamlbuild/shell.ml
@@ -0,0 +1,71 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+
+let is_simple_filename s =
+ let ls = String.length s in
+ ls <> 0 &&
+ let rec loop pos =
+ if pos >= ls then true else
+ match s.[pos] with
+ | 'a'..'z' | 'A'..'Z' | '0'..'9' | '.' | '-' | '/' | '_' | ':' | '@' | '+' | ',' -> loop (pos + 1)
+ | _ -> false in
+ loop 0
+let quote_filename_if_needed s =
+ if is_simple_filename s then s else Filename.quote s
+let chdir dir =
+ reset_filesys_cache ();
+ Sys.chdir dir
+let run args =
+ reset_readdir_cache ();
+ let cmd = String.concat " " (List.map quote_filename_if_needed args) in
+ if !*My_unix.is_degraded || Sys.os_type = "Win32" then
+ begin
+ let st = sys_command cmd in
+ if st <> 0 then
+ failwith (Printf.sprintf "Error during command `%s'.\nExit code %d.\n" cmd st)
+ else
+ ()
+ end
+ else
+ match My_unix.execute_many ~ticker:Log.update ~display:Log.display [[(cmd, ignore)]] with
+ | None -> ()
+ | Some(_, x) ->
+ failwith (Printf.sprintf "Error during command %S: %s" cmd (Printexc.to_string x))
+let rm = sys_remove
+let rm_f x =
+ if sys_file_exists x then rm x
+let mkdir dir =
+ reset_filesys_cache_for_file dir;
+ (*Sys.mkdir dir (* MISSING in ocaml *) *)
+ run ["mkdir"; dir]
+let try_mkdir dir = if not (sys_file_exists dir) then mkdir dir
+let rec mkdir_p dir =
+ if sys_file_exists dir then ()
+ else (mkdir_p (Filename.dirname dir); mkdir dir)
+let cp = copy_file (* Décret du 2007-02-01 *)
+(*
+ let cp src dest =
+ reset_filesys_cache_for_file dest;
+ run["cp";"-pf";src;dest]*)
+let readlink = My_unix.readlink
+let is_link = My_unix.is_link
+let rm_rf x =
+ reset_filesys_cache ();
+ run["rm";"-Rf";x]
+let mv src dest =
+ reset_filesys_cache_for_file src;
+ reset_filesys_cache_for_file dest;
+ run["mv"; src; dest]
+ (*Sys.rename src dest*)
diff --git a/ocamlbuild/shell.mli b/ocamlbuild/shell.mli
new file mode 100644
index 0000000000..2eb5e30ba1
--- /dev/null
+++ b/ocamlbuild/shell.mli
@@ -0,0 +1,26 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+val is_simple_filename : string -> bool
+val quote_filename_if_needed : string -> string
+val chdir : string -> unit
+val rm : string -> unit
+val rm_f : string -> unit
+val rm_rf : string -> unit
+val mkdir : string -> unit
+val try_mkdir : string -> unit
+val mkdir_p : string -> unit
+val cp : string -> string -> unit
+val mv : string -> string -> unit
+val readlink : string -> string
+val is_link : string -> bool
diff --git a/ocamlbuild/signatures.mli b/ocamlbuild/signatures.mli
new file mode 100644
index 0000000000..9c88aa6b84
--- /dev/null
+++ b/ocamlbuild/signatures.mli
@@ -0,0 +1,506 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(** This module contains all module signatures that the user
+ could use to build an ocamlbuild plugin. *)
+
+module type OrderedTypePrintable = sig
+ type t
+ val compare : t -> t -> int
+ val print : Format.formatter -> t -> unit
+end
+
+module type SET = sig
+ include Set.S
+ val find : (elt -> bool) -> t -> elt
+ val map : (elt -> elt) -> t -> t
+ val of_list : elt list -> t
+ val print : Format.formatter -> t -> unit
+end
+
+module type LIST = sig
+ (* Added functions *)
+ val print : (Format.formatter -> 'a -> 'b) -> Format.formatter -> 'a list -> unit
+ val filter_opt : ('a -> 'b option) -> 'a list -> 'b list
+ val union : 'a list -> 'a list -> 'a list
+
+ (* Original functions *)
+ include Std_signatures.LIST
+end
+
+module type STRING = sig
+ val print : Format.formatter -> string -> unit
+ val chomp : string -> string
+
+ (** [before s n] returns the substring of all characters of [s]
+ that precede position [n] (excluding the character at
+ position [n]).
+ This is the same function as {!Str.string_before}. *)
+ val before : string -> int -> string
+
+ (** [after s n] returns the substring of all characters of [s]
+ that follow position [n] (including the character at
+ position [n]).
+ This is the same function as {!Str.string_after}. *)
+ val after : string -> int -> string
+
+ val first_chars : string -> int -> string
+ (** [first_chars s n] returns the first [n] characters of [s].
+ This is the same function as {!String.before} ant {!Str.first_chars}. *)
+
+ val last_chars : string -> int -> string
+ (** [last_chars s n] returns the last [n] characters of [s].
+ This is the same function as {!Str.last_chars}. *)
+
+ val eq_sub_strings : string -> int -> string -> int -> int -> bool
+
+ (** [is_prefix u v] is v a prefix of u ? *)
+ val is_prefix : string -> string -> bool
+ (** [is_suffix u v] : is v a suffix of u ? *)
+ val is_suffix : string -> string -> bool
+
+ (** [contains_string s1 p2 s2] Search in [s1] starting from [p1] if it
+ contains the [s2] string. Returns [Some position] where [position]
+ is the begining of the string [s2] in [s1], [None] otherwise. *)
+ val contains_string : string -> int -> string -> int option
+
+ (** [subst patt repl text] *)
+ val subst : string -> string -> string -> string
+
+ (** [tr patt repl text] *)
+ val tr : char -> char -> string -> string
+
+ val rev : string -> string
+
+ (** The following are original functions from the [String] module. *)
+ include Std_signatures.STRING
+end
+
+module type TAGS = sig
+ include Set.S with type elt = string
+ val of_list : string list -> t
+ val print : Format.formatter -> t -> unit
+ val does_match : t -> t -> bool
+ module Operators : sig
+ val ( ++ ) : t -> elt -> t
+ val ( -- ) : t -> elt -> t
+ val ( +++ ) : t -> elt option -> t
+ val ( --- ) : t -> elt option -> t
+ end
+end
+
+module type PATHNAME = sig
+ type t = string
+ val concat : t -> t -> t
+ val compare : t -> t -> int
+ val equal : t -> t -> bool
+ val exists : t -> bool
+ val mk : string -> t
+ val define_context : string -> string list -> unit
+ val include_dirs_of : string -> string list
+ val copy : t -> t -> unit
+ val to_string : t -> string
+ val print : Format.formatter -> t -> unit
+ val current_dir_name : t
+ val parent_dir_name : t
+ val read : t -> string
+ val same_contents : t -> t -> bool
+ val basename : t -> t
+ val dirname : t -> t
+ val is_relative : t -> bool
+ val readlink : t -> t
+ val readdir : t -> t array
+ val is_link : t -> bool
+ val is_directory : t -> bool
+
+ val add_extension : string -> t -> t
+ val check_extension : t -> string -> bool
+
+ val get_extension : t -> string
+ val remove_extension : t -> t
+ val update_extension : string -> t -> t
+
+ val get_extensions : t -> string
+ val remove_extensions : t -> t
+ val update_extensions : string -> t -> t
+
+ val print_path_list : Format.formatter -> t list -> unit
+ val pwd : t
+ val parent : t -> t
+ (** [is_prefix x y] is [x] a pathname prefix of [y] *)
+ val is_prefix : t -> t -> bool
+ val is_implicit : t -> bool
+ module Operators : sig
+ val ( / ) : t -> t -> t
+ val ( -.- ) : t -> string -> t
+ end
+end
+
+(** Provides an abstract type for easily building complex shell commands without making
+ quotation mistakes. *)
+module type COMMAND = sig
+ type tags
+
+ (** The type [t] is basically a sequence of command specifications. This avoids having to
+ flatten lists of lists. *)
+ type t = Seq of t list | Cmd of spec | Nop
+
+ (** The type for command specifications. *)
+ and spec =
+ | N (** No operation. *)
+ | S of spec list (** A sequence. This gets flattened in the last stages *)
+ | A of string (** An atom. *)
+ | P of string (** A pathname. *)
+ | Px of string (** A pathname, that will also be given to the call_with_target hook. *)
+ | Sh of string (** A bit of raw shell code, that will not be escaped. *)
+ | T of tags (** A set of tags, that describe properties and some semantics
+ information about the command, afterward these tags will be
+ replaced by command [spec]s (flags for instance). *)
+ | V of string (** A virtual command, that will be resolved at execution using [resolve_virtuals] *)
+ | Quote of spec (** A string that should be quoted like a filename but isn't really one. *)
+
+ (*type v = [ `Seq of v list | `Cmd of vspec | `Nop ]
+ and vspec =
+ [ `N
+ | `S of vspec list
+ | `A of string
+ | `P of string (* Pathname.t *)
+ | `Px of string (* Pathname.t *)
+ | `Sh of string
+ | `Quote of vspec ]
+
+ val spec_of_vspec : vspec -> spec
+ val vspec_of_spec : spec -> vspec
+ val t_of_v : v -> t
+ val v_of_t : t -> v*)
+
+ (** Will convert a string list to a list of atoms by adding [A] constructors. *)
+ val atomize : string list -> spec
+
+ (** Will convert a string list to a list of paths by adding [P] constructors. *)
+ val atomize_paths : string list -> spec
+
+ (** Run the command. *)
+ val execute : ?quiet:bool -> ?pretend:bool -> t -> unit
+
+ (** Run the commands in the given list, if possible in parallel.
+ See the module [Executor]. *)
+ val execute_many : ?quiet:bool -> ?pretend:bool -> t list -> (bool list * exn) option
+
+ (** [setup_virtual_command_solver virtual_command solver]
+ the given solver can raise Not_found if it fails to find a valid
+ command for this virtual command. *)
+ val setup_virtual_command_solver : string -> (unit -> spec) -> unit
+
+ (** Search the given command in the command path and return its absolute
+ pathname. *)
+ val search_in_path : string -> string
+
+ (** Simplify a command by flattening the sequences and resolving the tags
+ into command-line options. *)
+ val reduce : spec -> spec
+
+ (** Print a command. *)
+ val print : Format.formatter -> t -> unit
+
+ (** Convert a command to a string. *)
+ val to_string : t -> string
+
+ (** Build a string representation of a command that can be passed to the
+ system calls. *)
+ val string_of_command_spec : spec -> string
+end
+
+(** A self-contained module implementing extended shell glob patterns who have an expressive power
+ equal to boolean combinations of regular expressions. *)
+module type GLOB = sig
+
+ (** A globber is a boolean combination of basic expressions indented to work on
+ pathnames. Known operators
+ are [or], [and] and [not], which may also be written [|], [&] and [~]. There are
+ also constants [true] and [false] (or [1] and [0]). Expression can be grouped
+ using parentheses.
+ - [true] matches anything,
+ - [false] matches nothing,
+ - {i basic} [or] {i basic} matches strings matching either one of the basic expressions,
+ - {i basic} [and] {i basic} matches strings matching both basic expressions,
+ - not {i basic} matches string that don't match the basic expression,
+ - {i basic} matches strings that match the basic expression.
+
+ A basic expression can be a constant string enclosed in double quotes, in which
+ double quotes must be preceded by backslashes, or a glob pattern enclosed between a [<] and a [>],
+ - ["]{i string}["] matches the literal string {i string},
+ - [<]{i glob}[>] matches the glob pattern {i glob}.
+
+ A glob pattern is an anchored regular expression in a shell-like syntax. Most characters stand for themselves.
+ Character ranges are given in usual shell syntax between brackets. The star [*] stands for any sequence of
+ characters. The joker '?' stands for exactly one, unspecified character. Alternation is achieved using braces [{].
+ - {i glob1}{i glob2} matches strings who have a prefix matching {i glob1} and the corresponding suffix
+ matching {i glob2}.
+ - [a] matches the string consisting of the single letter [a].
+ - [{]{i glob1},{i glob2}[}] matches strings matching {i glob1} or {i glob2}.
+ - [*] matches all strings, including the empty one.
+ - [?] matches strings of length 1.
+ - [\[]{i c1}-{i c2}{i c3}-{i c4}...[\]] matches characters in the range {i c1} to {i c2} inclusive,
+ or in the range {i c3} to {i c4} inclusive. For instance [\[a-fA-F0-9\]] matches hexadecimal digits.
+ To match the dash, put it at the end.
+ *)
+
+ (** The type representing globbers. Do not attempt to compare them, as they get on-the-fly optimizations. *)
+ type globber
+
+ (** [parse ~dir pattern] will parse the globber pattern [pattern], optionally prefixing its patterns with [dir]. *)
+ val parse : ?dir:string -> string -> globber
+
+ (** A descriptive exception raised when an invalid glob pattern description is given. *)
+ exception Parse_error of string
+
+ (** [eval g u] returns [true] if and only if the string [u] matches the given glob expression. Avoid reparsing
+ the same pattern, since the automaton implementing the pattern is optimized on the fly. The first few evaluations
+ are done using a time-inefficient but memory-efficient algorithm. It then compiles the pattern into an efficient
+ but more memory-hungry data structure. *)
+ val eval : globber -> string -> bool
+end
+
+(** Module for modulating the logging output with the logging level. *)
+module type LOG = sig
+ (** Current logging (debugging) level. *)
+ val level : int ref
+
+ (** [dprintf level fmt args...] formats the logging information [fmt]
+ with the arguments [args...] on the logging output if the logging
+ level is greater than or equal to [level]. The default level is 1.
+ More obscure debugging information should have a higher logging
+ level. Youre formats are wrapped inside these two formats
+ ["@\[<2>"] and ["@\]@."]. *)
+ val dprintf : int -> ('a, Format.formatter, unit) format -> 'a
+
+ (** Equivalent to calling [dprintf] with a level [< 0]. *)
+ val eprintf : ('a, Format.formatter, unit) format -> 'a
+
+ (** Same as dprintf but without the format wrapping. *)
+ val raw_dprintf : int -> ('a, Format.formatter, unit) format -> 'a
+end
+
+module type OUTCOME = sig
+ type ('a,'b) t =
+ | Good of 'a
+ | Bad of 'b
+
+ val wrap : ('a -> 'b) -> 'a -> ('b, exn) t
+ val ignore_good : ('a, exn) t -> unit
+ val good : ('a, exn) t -> 'a
+end
+
+module type MISC = sig
+ val opt_print :
+ (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a option -> unit
+ val the : 'a option -> 'a
+ val getenv : ?default:string -> string -> string
+ val with_input_file : ?bin:bool -> string -> (in_channel -> 'a) -> 'a
+ val with_output_file : ?bin:bool -> string -> (out_channel -> 'a) -> 'a
+ val with_temp_file : string -> string -> (string -> 'a) -> 'a
+ val read_file : string -> string
+ val copy_chan : in_channel -> out_channel -> unit
+ val copy_file : string -> string -> unit
+ val print_string_list : Format.formatter -> string list -> unit
+ val ( !* ) : 'a Lazy.t -> 'a
+
+ (** [r @:= l] is equivalent to [r := !r @ l] *)
+ val ( @:= ) : 'a list ref -> 'a list -> unit
+
+ val memo : ('a -> 'b) -> ('a -> 'b)
+end
+
+module type OPTIONS = sig
+ type command_spec
+
+ val build_dir : string ref
+ val include_dirs : string list ref
+ val exclude_dirs : string list ref
+ val nothing_should_be_rebuilt : bool ref
+ val ocamlc : command_spec ref
+ val ocamlopt : command_spec ref
+ val ocamldep : command_spec ref
+ val ocamldoc : command_spec ref
+ val ocamlyacc : command_spec ref
+ val ocamllex : command_spec ref
+ val ocamlrun : command_spec ref
+ val ocamlmklib : command_spec ref
+ val hygiene : bool ref
+ val sterilize : bool ref
+ val ignore_auto : bool ref
+ val plugin : bool ref
+ val just_plugin : bool ref
+ val native_plugin : bool ref
+ val make_links : bool ref
+ val nostdlib : bool ref
+ val program_to_execute : bool ref
+ val must_clean : bool ref
+ val internal_log_file : string option ref
+ val use_menhir : bool ref
+
+ val targets : string list ref
+ val ocaml_libs : string list ref
+ val ocaml_cflags : string list ref
+ val ocaml_lflags : string list ref
+ val ocaml_ppflags : string list ref
+ val ocaml_yaccflags : string list ref
+ val ocaml_lexflags : string list ref
+ val program_args : string list ref
+ val ignore_list : string list ref
+ val tags : string list ref
+
+ val ext_obj : string ref
+ val ext_lib : string ref
+ val ext_dll : string ref
+end
+
+module type ARCH = sig
+ type 'a arch = private
+ | Arch_dir of string * 'a * 'a arch list
+ | Arch_dir_pack of string * 'a * 'a arch list
+ | Arch_file of string * 'a
+
+ val dir : string -> unit arch list -> unit arch
+ val dir_pack : string -> unit arch list -> unit arch
+ val file : string -> unit arch
+
+ type info = private {
+ current_path : string;
+ include_dirs : string list;
+ for_pack : string;
+ }
+
+ val annotate : 'a arch -> info arch
+
+ val print : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a arch -> unit
+ val print_include_dirs : Format.formatter -> string list -> unit
+ val print_info : Format.formatter -> info -> unit
+
+ val iter_info : ('a -> unit) -> 'a arch -> unit
+ val fold_info : ('a -> 'b -> 'b) -> 'a arch -> 'b -> 'b
+
+ val iter_include_dirs : info arch -> (string -> unit) -> unit
+
+ val mk_tables :
+ info arch -> (string, string list) Hashtbl.t * (string, string) Hashtbl.t
+ val print_table :
+ (Format.formatter -> 'a -> unit) -> Format.formatter -> (string, 'a) Hashtbl.t -> unit
+end
+
+(** This module contains the functions and values that can be used by plugins. *)
+module type PLUGIN = sig
+ module Pathname : PATHNAME
+ module Tags : TAGS
+ module Command : COMMAND with type tags = Tags.t
+ module Outcome : OUTCOME
+ module String : STRING
+ module List : LIST
+ module StringSet : Set.S with type elt = String.t
+ module Options : OPTIONS with type command_spec = Command.spec
+ module Arch : ARCH
+ include MISC
+
+ val ( / ) : Pathname.t -> Pathname.t -> Pathname.t
+ val ( -.- ) : Pathname.t -> string -> Pathname.t
+
+ val ( ++ ) : Tags.t -> Tags.elt -> Tags.t
+ val ( -- ) : Tags.t -> Tags.elt -> Tags.t
+ val ( +++ ) : Tags.t -> Tags.elt option -> Tags.t
+ val ( --- ) : Tags.t -> Tags.elt option -> Tags.t
+
+ type env = Pathname.t -> Pathname.t
+ type builder = Pathname.t list list -> (Pathname.t, exn) Outcome.t list
+ type action = env -> builder -> Command.t
+
+ val rule : string ->
+ ?tags:string list ->
+ ?prods:string list ->
+ ?deps:string list ->
+ ?prod:string ->
+ ?dep:string ->
+ ?insert:[`top | `before of string | `after of string | `bottom] ->
+ action -> unit
+
+ val file_rule : string ->
+ ?tags:string list ->
+ prod:string ->
+ ?deps:string list ->
+ ?dep:string ->
+ ?insert:[`top | `before of string | `after of string | `bottom] ->
+ cache:(env -> string) ->
+ (env -> out_channel -> unit) -> unit
+
+ val custom_rule : string ->
+ ?tags:string list ->
+ ?prods:string list ->
+ ?prod:string ->
+ ?deps:string list ->
+ ?dep:string ->
+ ?insert:[`top | `before of string | `after of string | `bottom] ->
+ cache:(env -> string) ->
+ (env -> cached:bool -> unit) -> unit
+
+ (** [copy_rule name ?insert source destination] *)
+ val copy_rule : string ->
+ ?insert:[`top | `before of string | `after of string | `bottom] ->
+ string -> string -> unit
+
+ (** [dep tags deps] Will build [deps] when [tags] will be activated. *)
+ val dep : string list -> string list -> unit
+
+ val flag : string list -> Command.spec -> unit
+
+ val non_dependency : Pathname.t -> string -> unit
+
+ val use_lib : Pathname.t -> Pathname.t -> unit
+
+ val expand_module :
+ Pathname.t list -> Pathname.t -> string list -> Pathname.t list
+
+ val string_list_of_file : Pathname.t -> string list
+
+ val module_name_of_pathname : Pathname.t -> string
+
+ val mv : Pathname.t -> Pathname.t -> Command.t
+ val cp : Pathname.t -> Pathname.t -> Command.t
+ val ln_f : Pathname.t -> Pathname.t -> Command.t
+ val ln_s : Pathname.t -> Pathname.t -> Command.t
+ val rm_f : Pathname.t -> Command.t
+ val touch : Pathname.t -> Command.t
+ val chmod : Command.spec -> Pathname.t -> Command.t
+ val cmp : Pathname.t -> Pathname.t -> Command.t
+
+ (** [hide_package_contents pack_name]
+ Don't treat the given package as an open package.
+ So a module will not be replaced during linking by
+ this package even if it contains that module. *)
+ val hide_package_contents : string -> unit
+
+ val tag_file : string -> string list -> unit
+
+ val tag_any : string list -> unit
+
+ val tags_of_pathname : Pathname.t -> Tags.t
+
+ type hook =
+ | Before_hygiene
+ | After_hygiene
+ | Before_options
+ | After_options
+ | Before_rules
+ | After_rules
+
+ val dispatch : (hook -> unit) -> unit
+end
diff --git a/ocamlbuild/slurp.ml b/ocamlbuild/slurp.ml
new file mode 100644
index 0000000000..4446336e5d
--- /dev/null
+++ b/ocamlbuild/slurp.ml
@@ -0,0 +1,186 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Slurp *)
+open My_std
+open Outcome
+
+type 'a entry =
+ | Dir of string * string * My_unix.stats Lazy.t * 'a * 'a entry list Lazy.t
+ | File of string * string * My_unix.stats Lazy.t * 'a
+ | Error of exn
+ | Nothing
+
+let (/) = filename_concat
+
+let rec filter predicate = function
+ | Dir(path, name, st, attr, entries) ->
+ if predicate path name attr then
+ Dir(path, name, st, attr, lazy (List.map (filter predicate) !*entries))
+ else
+ Nothing
+ | File(path, name, _, attr) as f ->
+ if predicate path name attr then
+ f
+ else
+ Nothing
+ | Nothing -> Nothing
+ | Error _ as e -> e
+
+let real_slurp path =
+ let cwd = Sys.getcwd () in
+ let abs x = if Filename.is_implicit x || Filename.is_relative x then cwd/x else x in
+ let visited = Hashtbl.create 1024 in
+ let rec scandir path names =
+ let (file_acc, dir_acc) =
+ Array.fold_left begin fun ((file_acc, dir_acc) as acc) name ->
+ match do_entry true path name with
+ | None -> acc
+ | Some((Dir _|Error _) as entry) -> (file_acc, entry :: dir_acc)
+ | Some((File _) as entry) -> (entry :: file_acc, dir_acc)
+ | Some Nothing -> acc
+ end
+ ([], [])
+ names
+ in
+ file_acc @ dir_acc
+ and do_entry link_mode path name =
+ let fn = path/name in
+ let absfn = abs fn in
+ match
+ try
+ Good(if link_mode then My_unix.lstat absfn else My_unix.stat absfn)
+ with
+ | x -> Bad x
+ with
+ | Bad x -> Some(Error x)
+ | Good st ->
+ let key = st.My_unix.stat_key in
+ if try Hashtbl.find visited key with Not_found -> false
+ then None
+ else
+ begin
+ Hashtbl.add visited key true;
+ let res =
+ match st.My_unix.stat_file_kind with
+ | My_unix.FK_link ->
+ let fn' = My_unix.readlink absfn in
+ if sys_file_exists (abs fn') then
+ do_entry false path name
+ else
+ Some(File(path, name, lazy st, ()))
+ | My_unix.FK_dir ->
+ (match sys_readdir absfn with
+ | Good names -> Some(Dir(path, name, lazy st, (), lazy (scandir fn names)))
+ | Bad exn -> Some(Error exn))
+ | My_unix.FK_other -> None
+ | My_unix.FK_file -> Some(File(path, name, lazy st, ())) in
+ Hashtbl.replace visited key false;
+ res
+ end
+ in
+ match do_entry true "" path with
+ | None -> raise Not_found
+ | Some entry -> entry
+
+let split path =
+ let rec aux path =
+ if path = Filename.current_dir_name then []
+ else (Filename.basename path) :: aux (Filename.dirname path)
+ in List.rev (aux path)
+
+let rec join =
+ function
+ | [] -> assert false
+ | [x] -> x
+ | x :: xs -> x/(join xs)
+
+let rec add root path entries =
+ match path, entries with
+ | [], _ -> entries
+ | xpath :: xspath, (Dir(dpath, dname, dst, dattr, dentries) as d) :: entries ->
+ if xpath = dname then
+ Dir(dpath, dname, dst, dattr, lazy (add (root/xpath) xspath !*dentries)) :: entries
+ else d :: add root path entries
+ | [xpath], [] ->
+ [File(root, xpath, lazy (My_unix.stat (root/xpath)), ())]
+ | xpath :: xspath, [] ->
+ [Dir(root/(join xspath), xpath,
+ lazy (My_unix.stat (root/(join path))), (),
+ lazy (add (root/xpath) xspath []))]
+ | _, Nothing :: entries -> add root path entries
+ | _, Error _ :: _ -> entries
+ | [xpath], (File(_, fname, _, _) as f) :: entries' ->
+ if xpath = fname then entries
+ else f :: add root path entries'
+ | xpath :: xspath, (File(fpath, fname, fst, fattr) as f) :: entries' ->
+ if xpath = fname then
+ Dir(fpath, fname, fst, fattr, lazy (add (root/xpath) xspath [])) :: entries'
+ else f :: add root path entries'
+
+let slurp_with_find path =
+ let lines =
+ My_unix.run_and_open (Printf.sprintf "find %s" (Filename.quote path)) begin fun ic ->
+ let acc = ref [] in
+ try while true do acc := input_line ic :: !acc done; []
+ with End_of_file -> !acc
+ end in
+ let res =
+ List.fold_right begin fun line acc ->
+ add path (split line) acc
+ end lines [] in
+ match res with
+ | [] -> Nothing
+ | [entry] -> entry
+ | entries -> Dir(path, Filename.basename path, lazy (My_unix.stat path), (), lazy entries)
+
+let slurp x = if !*My_unix.is_degraded then slurp_with_find x else real_slurp x
+
+let rec print print_attr f entry =
+ match entry with
+ | Dir(path, name, _, attr, entries) ->
+ Format.fprintf f "@[<2>Dir(%S,@ %S,@ _,@ %a,@ %a)@]"
+ path name print_attr attr (List.print (print print_attr)) !*entries
+ | File(path, name, _, attr) ->
+ Format.fprintf f "@[<2>File(%S,@ %S,@ _,@ %a)@]" path name print_attr attr
+ | Nothing ->
+ Format.fprintf f "Nothing"
+ | Error(_) ->
+ Format.fprintf f "Error(_)"
+
+let rec fold f entry acc =
+ match entry with
+ | Dir(path, name, _, attr, contents) ->
+ f path name attr (List.fold_right (fold f) !*contents acc)
+ | File(path, name, _, attr) ->
+ f path name attr acc
+ | Nothing | Error _ -> acc
+
+let map f entry =
+ let rec self entry =
+ match entry with
+ | Dir(path, name, st, attr, contents) ->
+ Dir(path, name, st, f path name attr, lazy (List.map self !*contents))
+ | File(path, name, st, attr) ->
+ File(path, name, st, f path name attr)
+ | Nothing -> Nothing
+ | Error e -> Error e
+ in self entry
+
+let rec force =
+ function
+ | Dir(_, _, st, _, contents) ->
+ let _ = !*st in List.iter force !*contents
+ | File(_, _, st, _) ->
+ ignore !*st
+ | Nothing | Error _ -> ()
diff --git a/ocamlbuild/slurp.mli b/ocamlbuild/slurp.mli
new file mode 100644
index 0000000000..1b28cc1bc2
--- /dev/null
+++ b/ocamlbuild/slurp.mli
@@ -0,0 +1,48 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Berke Durak *)
+(* Slurp *)
+
+(** Scans a directory lazily to build a tree that can be user-decorated. *)
+
+type 'a entry =
+ Dir of string * string * My_unix.stats Lazy.t * 'a * 'a entry list Lazy.t
+ (** [Dir(path, name, lst, decoration, lentries)] is a directory named [name] whose path is [path].
+ Its stat is lazily stored in [lst] and its entries are lazily scanned in [lentries]. [decoration]
+ is of type 'a. *)
+ | File of string * string * My_unix.stats Lazy.t * 'a
+ (** [File(path, name, lst, decoration)] is a file named [name] whose path is [path].
+ Its stat is lazily stored in [lst]. [decoration] is of type 'a. *)
+ | Error of exn
+ (** [Error x] means that the exception [x] was raised while scanning or statting an entry. *)
+ | Nothing
+ (** Convenient when filtering out entries. *)
+
+(** Recursively scan the filesystem starting at the given directory. *)
+val slurp : string -> unit entry
+
+(** [filter f entry] only retains from [entry] the nodes for which
+ [f path name] returns [true]. *)
+val filter : (string -> string -> 'a -> bool) -> 'a entry -> 'a entry
+
+(** [map f entries] changes the decoration in [entries] by applying
+ [f] to them. [f] is called as [f path name decoration]. *)
+val map : (string -> string -> 'a -> 'b) -> 'a entry -> 'b entry
+
+(** [fold f entry x] iterates [f] over the entries and an accumulator
+ initially containing [x]; at each iteration, [f] gets the current
+ value of the accumulator and returns its new value. *)
+val fold : (string -> string -> 'b -> 'a -> 'a) -> 'b entry -> 'a -> 'a
+
+(** Force the evaluation of the whole entry. *)
+val force : 'a entry -> unit
diff --git a/ocamlbuild/solver.ml b/ocamlbuild/solver.ml
new file mode 100644
index 0000000000..541339de35
--- /dev/null
+++ b/ocamlbuild/solver.ml
@@ -0,0 +1,119 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Log
+open Format
+open Outcome
+
+type backtrace =
+ | Leaf of Pathname.t
+ | Choice of backtrace list
+ | Depth of Pathname.t * backtrace
+ | Target of string * backtrace
+exception Failed of backtrace
+exception Circular of Pathname.t * Pathname.t list
+
+let failed target backtrace =
+ Resource.Cache.resource_failed target;
+ raise (Failed backtrace)
+
+let rec pp_repeat f (n, s) =
+ if n > 0 then (pp_print_string f s; pp_repeat f (n - 1, s))
+
+let rec self depth on_the_go_orig target =
+ let rules = Rule.get_rules () in
+ let on_the_go = target :: on_the_go_orig in
+
+ dprintf 4 "==%a> %a" pp_repeat (depth, "==") Resource.print target;
+ if List.mem target on_the_go_orig then raise (Circular(target, on_the_go_orig));
+ match Resource.Cache.resource_state target with
+ | Resource.Cache.Bbuilt ->
+ (dprintf 5 "%a already built" Resource.print target)
+ | Resource.Cache.Bcannot_be_built ->
+ (dprintf 5 "%a already failed" Resource.print target; failed target (Leaf target))
+ | Resource.Cache.Bsuspension(s) ->
+ (dprintf 5 "%a was suspended -> resuming" Resource.print target;
+ Resource.Cache.resume_suspension s)
+ | Resource.Cache.Bnot_built_yet ->
+ if Resource.is_up_to_date target then
+ (dprintf 5 "%a exists and up to date" Resource.print target;
+ Resource.Cache.resource_built target)
+ else if Pathname.exists_in_source_dir target then
+ (dprintf 5 "%a exists in source dir -> import it" Resource.print target;
+ Pathname.import_in_build_dir target;
+ Resource.Cache.resource_built target;
+ Resource.Cache.resource_changed target)
+ else
+ (* FIXME tags of target
+ let tags = Configuration.tags_of_target target in
+ let matching_rules = List.filter_opt (Rule.tags_matches tags) rules in *)
+ let matching_rules = List.filter_opt (Rule.can_produce target) (*matching_*)rules in
+ match matching_rules with
+ | [] -> failed target (Leaf target)
+ | _ ->
+ let rec until_works rs backtraces =
+ match rs with
+ | [] -> assert false
+ | r :: rs ->
+ try
+ List.iter (force_self (depth + 1) on_the_go) r.Rule.deps;
+ Rule.call (self_firsts (depth + 1) on_the_go) r
+ with Failed backtrace ->
+ if rs = [] then failed target (Depth (target, Choice (backtrace :: backtraces)))
+ else
+ let () =
+ match backtrace with
+ | Depth (top_prod, _) -> Resource.Cache.clear_resource_failed top_prod
+ | Target _ | Choice _ | Leaf _ -> ()
+ in until_works rs (backtrace :: backtraces)
+ in until_works matching_rules []
+and self_first depth on_the_go already_failed rs =
+ match rs with
+ | [] -> Bad (Failed (Choice already_failed))
+ | r :: rs ->
+ try self depth on_the_go r; Good r
+ with Failed backtrace -> self_first depth on_the_go (backtrace :: already_failed) rs
+and self_firsts depth on_the_go rss =
+ let results = List.map (self_first depth on_the_go []) rss in
+ let cmds, konts =
+ List.fold_right begin fun res ((acc1, acc2) as acc) ->
+ match res with
+ | Bad _ -> acc
+ | Good res ->
+ match Resource.Cache.get_optional_resource_suspension res with
+ | None -> acc
+ | Some (cmd, kont) -> (cmd :: acc1, kont :: acc2)
+ end results ([], []) in
+ let count = List.length cmds in
+ let job_debug = if !Command.jobs = 1 then 10 else 5 in
+ if count > 1 then dprintf job_debug ">>> PARALLEL: %d" count;
+ let opt_exn = Command.execute_many cmds in
+ if count > 1 then dprintf job_debug "<<< PARALLEL";
+ begin match opt_exn with
+ | Some(res, exn) ->
+ List.iter2 (fun res kont -> if res then kont ()) res konts;
+ Log.finish ~how:`Error ();
+ raise exn
+ | None ->
+ List.iter (fun kont -> kont ()) konts
+ end;
+ results
+and force_self depth on_the_go x = self depth on_the_go x; Resource.Cache.resume_resource x
+
+let solve = force_self 0 []
+let solve_target name rs =
+ match self_first 0 [] [] rs with
+ | Good res -> Resource.Cache.resume_resource res; res
+ | Bad (Failed backtrace) -> raise (Failed (Target (name, backtrace)))
+ | Bad exn -> raise exn
diff --git a/ocamlbuild/solver.mli b/ocamlbuild/solver.mli
new file mode 100644
index 0000000000..5969c4d2ab
--- /dev/null
+++ b/ocamlbuild/solver.mli
@@ -0,0 +1,23 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+type backtrace = private
+ | Leaf of Pathname.t
+ | Choice of backtrace list
+ | Depth of Pathname.t * backtrace
+ | Target of string * backtrace
+exception Failed of backtrace
+exception Circular of Pathname.t * Pathname.t list
+
+val solve : Pathname.t -> unit
+val solve_target : string -> Pathname.t list -> Pathname.t
diff --git a/ocamlbuild/start.sh b/ocamlbuild/start.sh
new file mode 100755
index 0000000000..5789f81abf
--- /dev/null
+++ b/ocamlbuild/start.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+set -e
+set -x
+rm -rf _start
+mkdir _start
+cp *.ml* _start
+cd _start
+echo "let where = ref \"<start>\";;" > ocamlbuild_where.ml
+ocamlc -c tags.mli
+ocamlc -c std_signatures.mli
+ocamlc -c signatures.mli
+ocamlc -c ocamlbuild_where.mli
+ocamlc -c my_unix.mli
+ocamlc -c my_std.mli
+ocamlc -c display.mli
+ocamlc -c shell.mli
+ocamlc -c log.mli
+ocamlc -c bool.mli
+ocamlc -c glob_ast.mli
+ocamlc -c glob_lexer.mli
+ocamlc -c glob.mli
+ocamlc -c lexers.mli
+ocamlc -c slurp.mli
+ocamlc -c pathname.mli
+ocamlc -c discard_printf.mli
+ocamlc -c command.mli
+ocamlc -c resource.mli
+ocamlc -c rule.mli
+ocamlc -c hygiene.mli
+ocamlc -c options.mli
+ocamlc -c tools.mli
+ocamlc -c main.mli
+ocamlc -c ocaml_utils.mli
+ocamlc -c ocaml_tools.mli
+ocamlc -c ocaml_compiler.mli
+ocamlc -c ocaml_dependencies.mli
+ocamlc -c hooks.mli
+ocamlc -c ocamldep.mli
+ocamlc -c ocaml_specific.mli
+ocamlc -c configuration.mli
+ocamlc -c flags.mli
+ocamlc -c ocaml_arch.mli
+ocamlc -c solver.mli
+ocamlc -c report.mli
+ocamlc -c ocamlbuild_where.ml
+ocamlc -c fda.mli
+ocamlc -c fda.ml
+ocamlc -c tools.ml
+ocamlc -c plugin.mli
+ocamlc -c plugin.ml
+ocamlc -c ocaml_dependencies.ml
+ocamlc -c main.ml
+ocamlc -c ocaml_specific.ml
+ocamlc -c display.ml
+ocamlc -c command.ml
+ocamlc -c -rectypes discard_printf.ml
+ocamlc -c my_std.ml
+ocamlc -c shell.ml
+ocamlc -c my_unix.ml
+ocamlc -c log.ml
+ocamlc -c pathname.ml
+ocamlc -c options.ml
+ocamlc -c slurp.ml
+ocamlc -c ocaml_utils.ml
+ocamlc -c ocaml_tools.ml
+ocamlc -c ocaml_compiler.ml
+ocamlc -c ocamldep.ml
+ocamlc -c hooks.ml
+ocamllex lexers.mll
+ocamlc -c lexers.ml
+ocamllex glob_lexer.mll
+ocamlc -c glob_lexer.ml
+ocamlc -c bool.ml
+ocamlc -c glob_ast.ml
+ocamlc -c glob.ml
+ocamlc -c tags.ml
+ocamlc -c configuration.ml
+ocamlc -c flags.ml
+ocamlc -c hygiene.ml
+ocamlc -c ocaml_arch.ml
+ocamlc -c resource.ml
+ocamlc -c rule.ml
+ocamlc -c report.ml
+ocamlc -c solver.ml
+ocamlc -c ocamlbuildlight.mli
+ocamlc -pack discard_printf.cmo my_std.cmo bool.cmo glob_ast.cmo glob_lexer.cmo glob.cmo lexers.cmo my_unix.cmo tags.cmo display.cmo log.cmo shell.cmo slurp.cmo ocamlbuild_where.cmo command.cmo options.cmo pathname.cmo resource.cmo rule.cmo flags.cmo solver.cmo report.cmo ocaml_arch.cmo hygiene.cmo configuration.cmo tools.cmo fda.cmo plugin.cmo ocaml_utils.cmo ocamldep.cmo ocaml_dependencies.cmo ocaml_compiler.cmo ocaml_tools.cmo hooks.cmo ocaml_specific.cmo main.cmo -o ocamlbuild_pack.cmo
+ocamlc -c ocamlbuildlight.ml
+ocamlc ocamlbuild_pack.cmo ocamlbuildlight.cmo -o ../ocamlbuild.byte.start
+cd ..
+rm -rf _start
+echo ocamlbuild.byte.start: Sucessfully built.
diff --git a/ocamlbuild/std_signatures.mli b/ocamlbuild/std_signatures.mli
new file mode 100644
index 0000000000..23df4baed3
--- /dev/null
+++ b/ocamlbuild/std_signatures.mli
@@ -0,0 +1,94 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(** Some signatures from the standard library. *)
+
+module type LIST = sig
+ val length : 'a list -> int
+ val hd : 'a list -> 'a
+ val tl : 'a list -> 'a list
+ val nth : 'a list -> int -> 'a
+ val rev : 'a list -> 'a list
+ val append : 'a list -> 'a list -> 'a list
+ val rev_append : 'a list -> 'a list -> 'a list
+ val concat : 'a list list -> 'a list
+ val flatten : 'a list list -> 'a list
+ val iter : ('a -> unit) -> 'a list -> unit
+ val map : ('a -> 'b) -> 'a list -> 'b list
+ val rev_map : ('a -> 'b) -> 'a list -> 'b list
+ val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
+ val fold_right : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b
+ val iter2 : ('a -> 'b -> unit) -> 'a list -> 'b list -> unit
+ val map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list
+ val rev_map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list
+ val fold_left2 : ('a -> 'b -> 'c -> 'a) -> 'a -> 'b list -> 'c list -> 'a
+ val fold_right2 :
+ ('a -> 'b -> 'c -> 'c) -> 'a list -> 'b list -> 'c -> 'c
+ val for_all : ('a -> bool) -> 'a list -> bool
+ val exists : ('a -> bool) -> 'a list -> bool
+ val for_all2 : ('a -> 'b -> bool) -> 'a list -> 'b list -> bool
+ val exists2 : ('a -> 'b -> bool) -> 'a list -> 'b list -> bool
+ val mem : 'a -> 'a list -> bool
+ val memq : 'a -> 'a list -> bool
+ val find : ('a -> bool) -> 'a list -> 'a
+ val filter : ('a -> bool) -> 'a list -> 'a list
+ val find_all : ('a -> bool) -> 'a list -> 'a list
+ val partition : ('a -> bool) -> 'a list -> 'a list * 'a list
+ val assoc : 'a -> ('a * 'b) list -> 'b
+ val assq : 'a -> ('a * 'b) list -> 'b
+ val mem_assoc : 'a -> ('a * 'b) list -> bool
+ val mem_assq : 'a -> ('a * 'b) list -> bool
+ val remove_assoc : 'a -> ('a * 'b) list -> ('a * 'b) list
+ val remove_assq : 'a -> ('a * 'b) list -> ('a * 'b) list
+ val split : ('a * 'b) list -> 'a list * 'b list
+ val combine : 'a list -> 'b list -> ('a * 'b) list
+ val sort : ('a -> 'a -> int) -> 'a list -> 'a list
+ val stable_sort : ('a -> 'a -> int) -> 'a list -> 'a list
+ val fast_sort : ('a -> 'a -> int) -> 'a list -> 'a list
+ val merge : ('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
+end
+
+module type STRING = sig
+ external length : string -> int = "%string_length"
+ external get : string -> int -> char = "%string_safe_get"
+ external set : string -> int -> char -> unit = "%string_safe_set"
+ external create : int -> string = "caml_create_string"
+ val make : int -> char -> string
+ val copy : string -> string
+ val sub : string -> int -> int -> string
+ val fill : string -> int -> int -> char -> unit
+ val blit : string -> int -> string -> int -> int -> unit
+ val concat : string -> string list -> string
+ val iter : (char -> unit) -> string -> unit
+ val escaped : string -> string
+ val index : string -> char -> int
+ val rindex : string -> char -> int
+ val index_from : string -> int -> char -> int
+ val rindex_from : string -> int -> char -> int
+ val contains : string -> char -> bool
+ val contains_from : string -> int -> char -> bool
+ val rcontains_from : string -> int -> char -> bool
+ val uppercase : string -> string
+ val lowercase : string -> string
+ val capitalize : string -> string
+ val uncapitalize : string -> string
+ type t = string
+ val compare : t -> t -> int
+ external unsafe_get : string -> int -> char = "%string_unsafe_get"
+ external unsafe_set : string -> int -> char -> unit
+ = "%string_unsafe_set"
+ external unsafe_blit : string -> int -> string -> int -> int -> unit
+ = "caml_blit_string" "noalloc"
+ external unsafe_fill : string -> int -> int -> char -> unit
+ = "caml_fill_string" "noalloc"
+end
diff --git a/ocamlbuild/tags.ml b/ocamlbuild/tags.ml
new file mode 100644
index 0000000000..bd6190d456
--- /dev/null
+++ b/ocamlbuild/tags.ml
@@ -0,0 +1,43 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+include Set.Make(String)
+
+(**
+ does_match {foo, bar, baz} {foo} => ok
+ does_match {foo, bar, baz} {foo, boo} => ko
+ does_match {foo, bar, baz} {} => ok
+ does_match {foo, bar, baz} {foo, bar, baz} => ok
+*)
+let does_match x y = subset y x
+
+let of_list l = List.fold_right add l empty
+
+open Format
+
+let print f s =
+ let () = fprintf f "@[<0>" in
+ let _ =
+ fold begin fun elt first ->
+ if not first then fprintf f ",@,";
+ pp_print_string f elt;
+ false
+ end s true in
+ fprintf f "@]"
+
+module Operators = struct
+ let ( ++ ) x y = add y x
+ let ( -- ) x y = remove y x
+ let ( +++ ) x = function Some y -> add y x | None -> x
+ let ( --- ) x = function Some y -> remove y x | None -> x
+end
diff --git a/ocamlbuild/tags.mli b/ocamlbuild/tags.mli
new file mode 100644
index 0000000000..20892093b5
--- /dev/null
+++ b/ocamlbuild/tags.mli
@@ -0,0 +1,15 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+
+include Signatures.TAGS
diff --git a/ocamlbuild/test/good-output b/ocamlbuild/test/good-output
new file mode 100644
index 0000000000..5a9df660af
--- /dev/null
+++ b/ocamlbuild/test/good-output
@@ -0,0 +1,1022 @@
+ _____ _ ____
+|_ _|__ ___| |_|___ \
+ | |/ _ \/ __| __| __) |
+ | | __/\__ \ |_ / __/
+ |_|\___||___/\__|_____|
+
++ CMDOPTS=-- -help
++ BUILD=../../_build/ocamlbuild.native toto.byte toto.native -no-skip -classic-display
++ BUILD1=../../_build/ocamlbuild.native toto.byte toto.native -no-skip -classic-display -- -help
++ BUILD2=../../_build/ocamlbuild.native toto.byte toto.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt -- -help
++ rm -rf _build
++ cp vivi1.ml vivi.ml
++ ../../_build/ocamlbuild.native toto.byte toto.native -no-skip -classic-display -- -help
+ocamldep.opt -modules toto.ml > toto.ml.depends
+ocamldep.opt -modules tutu.mli > tutu.mli.depends
+ocamldep.opt -modules titi.ml > titi.ml.depends
+ocamldep.opt -modules tata.mli > tata.mli.depends
+ocamlc.opt -c -o tutu.cmi tutu.mli
+ocamlc.opt -c -o titi.cmo titi.ml
+ocamlc.opt -c -o tata.cmi tata.mli
+ocamlc.opt -c -o toto.cmo toto.ml
+ocamldep.opt -modules tutu.ml > tutu.ml.depends
+ocamldep.opt -pp camlp4o -modules vivi.ml > vivi.ml.depends
+ocamldep.opt -modules tyty.mli > tyty.mli.depends
+ocamlc.opt -c -pp camlp4o -o vivi.cmo vivi.ml
+ocamlc.opt -c -o tyty.cmi tyty.mli
+ocamldep.opt -modules tata.ml > tata.ml.depends
+ocamlc.opt -c -o tutu.cmo tutu.ml
+ocamlc.opt -c -o tata.cmo tata.ml
+ocamlc.opt tata.cmo titi.cmo vivi.cmo tutu.cmo toto.cmo -o toto.byte
+ocamlopt.opt -c -pp camlp4o -o vivi.cmx vivi.ml
+ocamlopt.opt -c -o tutu.cmx tutu.ml
+ocamlopt.opt -c -o titi.cmx titi.ml
+ocamlopt.opt -c -o tata.cmx tata.ml
+ocamlopt.opt -c -o toto.cmx toto.ml
+ocamlopt.opt tata.cmx titi.cmx vivi.cmx tutu.cmx toto.cmx -o toto.native
+Warning: Using -- only run the last target
+toto.native: _build/toto.native: Hello world!!!
+Tutu.tutu => 1
+Tata.tata => "TATA2"
++ ../../_build/ocamlbuild.native toto.byte toto.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt -- -help
+[cache hit] ocamldep.opt -modules toto.ml > toto.ml.depends
+[cache hit] ocamldep.opt -modules tutu.mli > tutu.mli.depends
+[cache hit] ocamlc.opt -c -o tutu.cmi tutu.mli
+[cache hit] ocamldep.opt -modules titi.ml > titi.ml.depends
+[cache hit] ocamlc.opt -c -o titi.cmo titi.ml
+[cache hit] ocamldep.opt -modules tata.mli > tata.mli.depends
+[cache hit] ocamlc.opt -c -o tata.cmi tata.mli
+[cache hit] ocamlc.opt -c -o toto.cmo toto.ml
+[cache hit] ocamldep.opt -modules tutu.ml > tutu.ml.depends
+[cache hit] ocamldep.opt -pp camlp4o -modules vivi.ml > vivi.ml.depends
+[cache hit] ocamlc.opt -c -pp camlp4o -o vivi.cmo vivi.ml
+[cache hit] ocamldep.opt -modules tyty.mli > tyty.mli.depends
+[cache hit] ocamlc.opt -c -o tyty.cmi tyty.mli
+[cache hit] ocamlc.opt -c -o tutu.cmo tutu.ml
+[cache hit] ocamldep.opt -modules tata.ml > tata.ml.depends
+[cache hit] ocamlc.opt -c -o tata.cmo tata.ml
+[cache hit] ocamlc.opt tata.cmo titi.cmo vivi.cmo tutu.cmo toto.cmo -o toto.byte
+[cache hit] ocamlopt.opt -c -pp camlp4o -o vivi.cmx vivi.ml
+[cache hit] ocamlopt.opt -c -o tutu.cmx tutu.ml
+[cache hit] ocamlopt.opt -c -o titi.cmx titi.ml
+[cache hit] ocamlopt.opt -c -o tata.cmx tata.ml
+[cache hit] ocamlopt.opt -c -o toto.cmx toto.ml
+[cache hit] ocamlopt.opt tata.cmx titi.cmx vivi.cmx tutu.cmx toto.cmx -o toto.native
+Warning: Using -- only run the last target
+toto.native: _build/toto.native: Hello world!!!
+Tutu.tutu => 1
+Tata.tata => "TATA2"
++ cp vivi2.ml vivi.ml
++ ../../_build/ocamlbuild.native toto.byte toto.native -no-skip -classic-display -- -help
+ocamldep.opt -pp camlp4o -modules vivi.ml > vivi.ml.depends
+ocamlc.opt -c -pp camlp4o -o vivi.cmo vivi.ml
+ocamlc.opt tata.cmo titi.cmo vivi.cmo tutu.cmo toto.cmo -o toto.byte
+ocamlopt.opt -c -pp camlp4o -o vivi.cmx vivi.ml
+ocamlopt.opt tata.cmx titi.cmx vivi.cmx tutu.cmx toto.cmx -o toto.native
+Warning: Using -- only run the last target
+toto.native: _build/toto.native: Hello world!!!
+Tutu.tutu => 1
+Tata.tata => "TATA2"
++ ../../_build/ocamlbuild.native toto.byte toto.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt -- -help
+[cache hit] ocamldep.opt -modules toto.ml > toto.ml.depends
+[cache hit] ocamldep.opt -modules tutu.mli > tutu.mli.depends
+[cache hit] ocamlc.opt -c -o tutu.cmi tutu.mli
+[cache hit] ocamldep.opt -modules titi.ml > titi.ml.depends
+[cache hit] ocamlc.opt -c -o titi.cmo titi.ml
+[cache hit] ocamldep.opt -modules tata.mli > tata.mli.depends
+[cache hit] ocamlc.opt -c -o tata.cmi tata.mli
+[cache hit] ocamlc.opt -c -o toto.cmo toto.ml
+[cache hit] ocamldep.opt -modules tutu.ml > tutu.ml.depends
+[cache hit] ocamldep.opt -pp camlp4o -modules vivi.ml > vivi.ml.depends
+[cache hit] ocamlc.opt -c -pp camlp4o -o vivi.cmo vivi.ml
+[cache hit] ocamldep.opt -modules tyty.mli > tyty.mli.depends
+[cache hit] ocamlc.opt -c -o tyty.cmi tyty.mli
+[cache hit] ocamlc.opt -c -o tutu.cmo tutu.ml
+[cache hit] ocamldep.opt -modules tata.ml > tata.ml.depends
+[cache hit] ocamlc.opt -c -o tata.cmo tata.ml
+[cache hit] ocamlc.opt tata.cmo titi.cmo vivi.cmo tutu.cmo toto.cmo -o toto.byte
+[cache hit] ocamlopt.opt -c -pp camlp4o -o vivi.cmx vivi.ml
+[cache hit] ocamlopt.opt -c -o tutu.cmx tutu.ml
+[cache hit] ocamlopt.opt -c -o titi.cmx titi.ml
+[cache hit] ocamlopt.opt -c -o tata.cmx tata.ml
+[cache hit] ocamlopt.opt -c -o toto.cmx toto.ml
+[cache hit] ocamlopt.opt tata.cmx titi.cmx vivi.cmx tutu.cmx toto.cmx -o toto.native
+Warning: Using -- only run the last target
+toto.native: _build/toto.native: Hello world!!!
+Tutu.tutu => 1
+Tata.tata => "TATA2"
++ cp vivi3.ml vivi.ml
++ ../../_build/ocamlbuild.native toto.byte toto.native -no-skip -classic-display -- -help
+ocamldep.opt -pp camlp4o -modules vivi.ml > vivi.ml.depends
+ocamlc.opt -c -pp camlp4o -o vivi.cmo vivi.ml
+ocamlc.opt -c -o tutu.cmo tutu.ml
+ocamlc.opt tata.cmo titi.cmo vivi.cmo tutu.cmo toto.cmo -o toto.byte
+ocamlopt.opt -c -pp camlp4o -o vivi.cmx vivi.ml
+ocamlopt.opt -c -o tutu.cmx tutu.ml
+ocamlopt.opt -c -o toto.cmx toto.ml
+ocamlopt.opt tata.cmx titi.cmx vivi.cmx tutu.cmx toto.cmx -o toto.native
+Warning: Using -- only run the last target
+toto.native: _build/toto.native: Hello world!!!
+Tutu.tutu => 2
+Tata.tata => "TATA2"
++ ../../_build/ocamlbuild.native toto.byte toto.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt -- -help
+[cache hit] ocamldep.opt -modules toto.ml > toto.ml.depends
+[cache hit] ocamldep.opt -modules tutu.mli > tutu.mli.depends
+[cache hit] ocamlc.opt -c -o tutu.cmi tutu.mli
+[cache hit] ocamldep.opt -modules titi.ml > titi.ml.depends
+[cache hit] ocamlc.opt -c -o titi.cmo titi.ml
+[cache hit] ocamldep.opt -modules tata.mli > tata.mli.depends
+[cache hit] ocamlc.opt -c -o tata.cmi tata.mli
+[cache hit] ocamlc.opt -c -o toto.cmo toto.ml
+[cache hit] ocamldep.opt -modules tutu.ml > tutu.ml.depends
+[cache hit] ocamldep.opt -pp camlp4o -modules vivi.ml > vivi.ml.depends
+[cache hit] ocamlc.opt -c -pp camlp4o -o vivi.cmo vivi.ml
+[cache hit] ocamldep.opt -modules tyty.mli > tyty.mli.depends
+[cache hit] ocamlc.opt -c -o tyty.cmi tyty.mli
+[cache hit] ocamlc.opt -c -o tutu.cmo tutu.ml
+[cache hit] ocamldep.opt -modules tata.ml > tata.ml.depends
+[cache hit] ocamlc.opt -c -o tata.cmo tata.ml
+[cache hit] ocamlc.opt tata.cmo titi.cmo vivi.cmo tutu.cmo toto.cmo -o toto.byte
+[cache hit] ocamlopt.opt -c -pp camlp4o -o vivi.cmx vivi.ml
+[cache hit] ocamlopt.opt -c -o tutu.cmx tutu.ml
+[cache hit] ocamlopt.opt -c -o titi.cmx titi.ml
+[cache hit] ocamlopt.opt -c -o tata.cmx tata.ml
+[cache hit] ocamlopt.opt -c -o toto.cmx toto.ml
+[cache hit] ocamlopt.opt tata.cmx titi.cmx vivi.cmx tutu.cmx toto.cmx -o toto.native
+Warning: Using -- only run the last target
+toto.native: _build/toto.native: Hello world!!!
+Tutu.tutu => 2
+Tata.tata => "TATA2"
+ _____ _ _____
+|_ _|__ ___| |_|___ /
+ | |/ _ \/ __| __| |_ \
+ | | __/\__ \ |_ ___) |
+ |_|\___||___/\__|____/
+
++ CMDOTPS=
++ BUILD=../../_build/ocamlbuild.native a.byte a.native proj.docdir/index.html -no-skip -classic-display
++ BUILD1=../../_build/ocamlbuild.native a.byte a.native proj.docdir/index.html -no-skip -classic-display
++ BUILD2=../../_build/ocamlbuild.native a.byte a.native proj.docdir/index.html -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
++ rm -rf _build
++ ../../_build/ocamlbuild.native a.byte a.native proj.docdir/index.html -no-skip -classic-display
+ocamldep.opt -modules a.ml > a.ml.depends
+ocamldep.opt -modules a.mli > a.mli.depends
+ocamlc.opt -c -o a.cmi a.mli
+ocamldep.opt -modules b.mli > b.mli.depends
+ocamlc.opt -c -o b.cmi b.mli
+ocamlc.opt -c -o a.cmo a.ml
+ocamldep.opt -modules b.ml > b.ml.depends
+ocamldep.opt -modules c.mli > c.mli.depends
+ocamlc.opt -c -o c.cmi c.mli
+ocamlc.opt -c -o b.cmo b.ml
+ocamldep.opt -modules c.ml > c.ml.depends
+ocamldep.opt -modules d.mli > d.mli.depends
+ocamlc.opt -c -o d.cmi d.mli
+ocamlc.opt -c -o c.cmo c.ml
+ocamldep.opt -modules d.ml > d.ml.depends
+ocamldep.opt -modules e.mli > e.mli.depends
+ocamlc.opt -c -o e.cmi e.mli
+ocamlc.opt -c -o d.cmo d.ml
+ocamldep.opt -modules e.ml > e.ml.depends
+ocamldep.opt -modules f.mli > f.mli.depends
+ocamlc.opt -c -o f.cmi f.mli
+ocamlc.opt -c -o e.cmo e.ml
+ocamldep.opt -modules f.ml > f.ml.depends
+ocamlc.opt -c -o f.cmo f.ml
+ocamlc.opt unix.cma f.cmo e.cmo d.cmo c.cmo b.cmo a.cmo -o a.byte
+ocamlopt.opt -c -o f.cmx f.ml
+ocamlopt.opt -c -o e.cmx e.ml
+ocamlopt.opt -c -o d.cmx d.ml
+ocamlopt.opt -c -o c.cmx c.ml
+ocamlopt.opt -c -o b.cmx b.ml
+ocamlopt.opt -c -o a.cmx a.ml
+ocamlopt.opt unix.cmxa f.cmx e.cmx d.cmx c.cmx b.cmx a.cmx -o a.native
+ocamldoc.opt -dump a.odoc a.mli
+ocamldoc.opt -dump b.odoc b.mli
+ocamldoc.opt -dump c.odoc c.mli
+ocamldoc.opt -dump d.odoc d.mli
+ocamldoc.opt -dump e.odoc e.mli
+ocamldoc.opt -dump f.odoc f.mli
+rm -rf proj.docdir
+mkdir -p proj.docdir
+ocamldoc.opt -load a.odoc -load b.odoc -load c.odoc -load d.odoc -load e.odoc -load f.odoc -html -d proj.docdir
++ ../../_build/ocamlbuild.native a.byte a.native proj.docdir/index.html -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
+[cache hit] ocamldep.opt -modules a.ml > a.ml.depends
+[cache hit] ocamldep.opt -modules a.mli > a.mli.depends
+[cache hit] ocamlc.opt -c -o a.cmi a.mli
+[cache hit] ocamldep.opt -modules b.mli > b.mli.depends
+[cache hit] ocamlc.opt -c -o b.cmi b.mli
+[cache hit] ocamlc.opt -c -o a.cmo a.ml
+[cache hit] ocamldep.opt -modules b.ml > b.ml.depends
+[cache hit] ocamldep.opt -modules c.mli > c.mli.depends
+[cache hit] ocamlc.opt -c -o c.cmi c.mli
+[cache hit] ocamlc.opt -c -o b.cmo b.ml
+[cache hit] ocamldep.opt -modules c.ml > c.ml.depends
+[cache hit] ocamldep.opt -modules d.mli > d.mli.depends
+[cache hit] ocamlc.opt -c -o d.cmi d.mli
+[cache hit] ocamlc.opt -c -o c.cmo c.ml
+[cache hit] ocamldep.opt -modules d.ml > d.ml.depends
+[cache hit] ocamldep.opt -modules e.mli > e.mli.depends
+[cache hit] ocamlc.opt -c -o e.cmi e.mli
+[cache hit] ocamlc.opt -c -o d.cmo d.ml
+[cache hit] ocamldep.opt -modules e.ml > e.ml.depends
+[cache hit] ocamldep.opt -modules f.mli > f.mli.depends
+[cache hit] ocamlc.opt -c -o f.cmi f.mli
+[cache hit] ocamlc.opt -c -o e.cmo e.ml
+[cache hit] ocamldep.opt -modules f.ml > f.ml.depends
+[cache hit] ocamlc.opt -c -o f.cmo f.ml
+[cache hit] ocamlc.opt unix.cma f.cmo e.cmo d.cmo c.cmo b.cmo a.cmo -o a.byte
+[cache hit] ocamlopt.opt -c -o f.cmx f.ml
+[cache hit] ocamlopt.opt -c -o e.cmx e.ml
+[cache hit] ocamlopt.opt -c -o d.cmx d.ml
+[cache hit] ocamlopt.opt -c -o c.cmx c.ml
+[cache hit] ocamlopt.opt -c -o b.cmx b.ml
+[cache hit] ocamlopt.opt -c -o a.cmx a.ml
+[cache hit] ocamlopt.opt unix.cmxa f.cmx e.cmx d.cmx c.cmx b.cmx a.cmx -o a.native
+[cache hit] ocamldoc.opt -dump a.odoc a.mli
+[cache hit] ocamldoc.opt -dump b.odoc b.mli
+[cache hit] ocamldoc.opt -dump c.odoc c.mli
+[cache hit] ocamldoc.opt -dump d.odoc d.mli
+[cache hit] ocamldoc.opt -dump e.odoc e.mli
+[cache hit] ocamldoc.opt -dump f.odoc f.mli
+[cache hit] rm -rf proj.docdir
+[cache hit] mkdir -p proj.docdir
+[cache hit] ocamldoc.opt -load a.odoc -load b.odoc -load c.odoc -load d.odoc -load e.odoc -load f.odoc -html -d proj.docdir
+ _____ _ _ _
+|_ _|__ ___| |_| || |
+ | |/ _ \/ __| __| || |_
+ | | __/\__ \ |_|__ _|
+ |_|\___||___/\__| |_|
+
++ CMDOTPS=
++ BUILD=../../_build/ocamlbuild.native -I a -I b aa.byte aa.native -no-skip -classic-display
++ BUILD1=../../_build/ocamlbuild.native -I a -I b aa.byte aa.native -no-skip -classic-display
++ BUILD2=../../_build/ocamlbuild.native -I a -I b aa.byte aa.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
++ rm -rf _build
++ ../../_build/ocamlbuild.native -I a -I b aa.byte aa.native -no-skip -classic-display
+ocamldep.opt -modules a/aa.ml > a/aa.ml.depends
+ocamldep.opt -modules a/aa.mli > a/aa.mli.depends
+ocamlc.opt -c -I a -I b -o a/aa.cmi a/aa.mli
+ocamldep.opt -modules b/bb.ml > b/bb.ml.depends
+ocamlc.opt -c -I b -I a -o b/bb.cmo b/bb.ml
+ocamlc.opt -c -I a -I b -o a/aa.cmo a/aa.ml
+ocamlc.opt str.cma b/bb.cmo a/aa.cmo -o a/aa.byte
+ocamlopt.opt -c -I b -I a -o b/bb.cmx b/bb.ml
+ocamlopt.opt -c -I a -I b -o a/aa.cmx a/aa.ml
+ocamlopt.opt str.cmxa b/bb.cmx a/aa.cmx -o a/aa.native
++ ../../_build/ocamlbuild.native -I a -I b aa.byte aa.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
+[cache hit] ocamldep.opt -modules a/aa.ml > a/aa.ml.depends
+[cache hit] ocamldep.opt -modules a/aa.mli > a/aa.mli.depends
+[cache hit] ocamlc.opt -c -I a -I b -o a/aa.cmi a/aa.mli
+[cache hit] ocamldep.opt -modules b/bb.ml > b/bb.ml.depends
+[cache hit] ocamlc.opt -c -I b -I a -o b/bb.cmo b/bb.ml
+[cache hit] ocamlc.opt -c -I a -I b -o a/aa.cmo a/aa.ml
+[cache hit] ocamlc.opt str.cma b/bb.cmo a/aa.cmo -o a/aa.byte
+[cache hit] ocamlopt.opt -c -I b -I a -o b/bb.cmx b/bb.ml
+[cache hit] ocamlopt.opt -c -I a -I b -o a/aa.cmx a/aa.ml
+[cache hit] ocamlopt.opt str.cmxa b/bb.cmx a/aa.cmx -o a/aa.native
+ _____ _ ____
+|_ _|__ ___| |_| ___|
+ | |/ _ \/ __| __|___ \
+ | | __/\__ \ |_ ___) |
+ |_|\___||___/\__|____/
+
++ CMDOPTS=
++ BUILD=../../_build/ocamlbuild.native d.byte d.native -no-skip -classic-display
++ BUILD1=../../_build/ocamlbuild.native d.byte d.native -no-skip -classic-display
++ BUILD2=../../_build/ocamlbuild.native d.byte d.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
++ rm -rf _build
++ ../../_build/ocamlbuild.native d.byte d.native -no-skip -classic-display
+ocamldep.opt -modules d.ml > d.ml.depends
+ocamldep.opt -modules a.ml > a.ml.depends
+ocamldep.opt -modules a.mli > a.mli.depends
+ocamlc.opt -c -o a.cmi a.mli
+ocamldep.opt -modules b.ml > b.ml.depends
+ocamlc.opt -c -o a.cmo a.ml
+ocamlc.opt -c -o b.cmo b.ml
+ocamlc.opt -pack a.cmo b.cmo -o c.cmo
+ocamlc.opt -c -o d.cmo d.ml
+ocamlc.opt c.cmo d.cmo -o d.byte
+ocamlopt.opt -c -for-pack C -o a.cmx a.ml
+ocamlopt.opt -c -for-pack C -o b.cmx b.ml
+mv c.cmi c.cmitmp
+ocamlopt.opt -pack a.cmx b.cmx -o c.cmx
+cmp c.cmitmp c.cmi
+ocamlopt.opt -c -o d.cmx d.ml
+ocamlopt.opt c.cmx d.cmx -o d.native
++ ../../_build/ocamlbuild.native d.byte d.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
+[cache hit] ocamldep.opt -modules d.ml > d.ml.depends
+[cache hit] ocamldep.opt -modules a.ml > a.ml.depends
+[cache hit] ocamldep.opt -modules a.mli > a.mli.depends
+[cache hit] ocamlc.opt -c -o a.cmi a.mli
+[cache hit] ocamlc.opt -c -o a.cmo a.ml
+[cache hit] ocamldep.opt -modules b.ml > b.ml.depends
+[cache hit] ocamlc.opt -c -o b.cmo b.ml
+[cache hit] ocamlc.opt -pack a.cmo b.cmo -o c.cmo
+[cache hit] ocamlc.opt -c -o d.cmo d.ml
+[cache hit] ocamlc.opt c.cmo d.cmo -o d.byte
+[cache hit] ocamlopt.opt -c -for-pack C -o a.cmx a.ml
+[cache hit] ocamlopt.opt -c -for-pack C -o b.cmx b.ml
+[cache hit] mv c.cmi c.cmitmp
+[cache hit] ocamlopt.opt -pack a.cmx b.cmx -o c.cmx
+[cache hit] cmp c.cmitmp c.cmi
+[cache hit] ocamlopt.opt -c -o d.cmx d.ml
+[cache hit] ocamlopt.opt c.cmx d.cmx -o d.native
+ _____ _ __
+|_ _|__ ___| |_ / /_
+ | |/ _ \/ __| __| '_ \
+ | | __/\__ \ |_| (_) |
+ |_|\___||___/\__|\___/
+
++ rm -rf _build
++ CMDOPTS=
++ BUILD=../../_build/ocamlbuild.native -no-skip main.byte -classic-display
++ BUILD1=../../_build/ocamlbuild.native -no-skip main.byte -classic-display
++ BUILD2=../../_build/ocamlbuild.native -no-skip main.byte -classic-display -verbose 0 -nothing-should-be-rebuilt
++ cp b.mli.v1 b.mli
++ cp d.mli.v1 d.mli
++ ../../_build/ocamlbuild.native -no-skip main.byte -classic-display
+ocamldep.opt -modules main.ml > main.ml.depends
+ocamldep.opt -modules main.mli > main.mli.depends
+ocamlc.opt -c -o main.cmi main.mli
+ocamldep.opt -modules d.mli > d.mli.depends
+ocamldep.opt -modules a.mli > a.mli.depends
+ocamlc.opt -c -o d.cmi d.mli
+ocamlc.opt -c -o a.cmi a.mli
+ocamlc.opt -c -o main.cmo main.ml
+ocamldep.opt -modules d.ml > d.ml.depends
+ocamldep.opt -modules a.ml > a.ml.depends
+ocamldep.opt -modules b.mli > b.mli.depends
+ocamlc.opt -c -o b.cmi b.mli
+ocamlc.opt -c -o d.cmo d.ml
+ocamlc.opt -c -o a.cmo a.ml
+ocamldep.opt -modules b.ml > b.ml.depends
+ocamlc.opt -c -o b.cmo b.ml
+ocamlc.opt d.cmo b.cmo a.cmo main.cmo -o main.byte
++ ../../_build/ocamlbuild.native -no-skip main.byte -classic-display -verbose 0 -nothing-should-be-rebuilt
+[cache hit] ocamldep.opt -modules main.ml > main.ml.depends
+[cache hit] ocamldep.opt -modules main.mli > main.mli.depends
+[cache hit] ocamlc.opt -c -o main.cmi main.mli
+[cache hit] ocamldep.opt -modules d.mli > d.mli.depends
+[cache hit] ocamlc.opt -c -o d.cmi d.mli
+[cache hit] ocamldep.opt -modules a.mli > a.mli.depends
+[cache hit] ocamlc.opt -c -o a.cmi a.mli
+[cache hit] ocamlc.opt -c -o main.cmo main.ml
+[cache hit] ocamldep.opt -modules d.ml > d.ml.depends
+[cache hit] ocamlc.opt -c -o d.cmo d.ml
+[cache hit] ocamldep.opt -modules a.ml > a.ml.depends
+[cache hit] ocamldep.opt -modules b.mli > b.mli.depends
+[cache hit] ocamlc.opt -c -o b.cmi b.mli
+[cache hit] ocamlc.opt -c -o a.cmo a.ml
+[cache hit] ocamldep.opt -modules b.ml > b.ml.depends
+[cache hit] ocamlc.opt -c -o b.cmo b.ml
+[cache hit] ocamlc.opt d.cmo b.cmo a.cmo main.cmo -o main.byte
++ cp b.mli.v2 b.mli
++ cp d.mli.v2 d.mli
++ ../../_build/ocamlbuild.native -no-skip main.byte -classic-display
+ocamldep.opt -modules d.mli > d.mli.depends
+ocamlc.opt -c -o d.cmi d.mli
+ocamlc.opt -c -o main.cmo main.ml
+ocamldep.opt -modules b.mli > b.mli.depends
++ ocamldep.opt -modules b.mli > b.mli.depends
+File "b.mli", line 1, characters 0-2:
+Syntax error
+Command exited with code 2.
++ cp b.mli.v1 b.mli
++ ../../_build/ocamlbuild.native -no-skip main.byte -classic-display
+ocamldep.opt -modules b.mli > b.mli.depends
+ocamlc.opt -c -o b.cmi b.mli
+ocamlc.opt -c -o d.cmo d.ml
+ocamlc.opt -c -o b.cmo b.ml
+ocamlc.opt d.cmo b.cmo a.cmo main.cmo -o main.byte
++ ../../_build/ocamlbuild.native -no-skip main.byte -classic-display -verbose 0 -nothing-should-be-rebuilt
+[cache hit] ocamldep.opt -modules main.ml > main.ml.depends
+[cache hit] ocamldep.opt -modules main.mli > main.mli.depends
+[cache hit] ocamlc.opt -c -o main.cmi main.mli
+[cache hit] ocamldep.opt -modules d.mli > d.mli.depends
+[cache hit] ocamlc.opt -c -o d.cmi d.mli
+[cache hit] ocamldep.opt -modules a.mli > a.mli.depends
+[cache hit] ocamlc.opt -c -o a.cmi a.mli
+[cache hit] ocamlc.opt -c -o main.cmo main.ml
+[cache hit] ocamldep.opt -modules d.ml > d.ml.depends
+[cache hit] ocamlc.opt -c -o d.cmo d.ml
+[cache hit] ocamldep.opt -modules a.ml > a.ml.depends
+[cache hit] ocamldep.opt -modules b.mli > b.mli.depends
+[cache hit] ocamlc.opt -c -o b.cmi b.mli
+[cache hit] ocamlc.opt -c -o a.cmo a.ml
+[cache hit] ocamldep.opt -modules b.ml > b.ml.depends
+[cache hit] ocamlc.opt -c -o b.cmo b.ml
+[cache hit] ocamlc.opt d.cmo b.cmo a.cmo main.cmo -o main.byte
++ echo PASS
+PASS
+ _____ _ _____
+|_ _|__ ___| ||___ |
+ | |/ _ \/ __| __| / /
+ | | __/\__ \ |_ / /
+ |_|\___||___/\__/_/
+
++ CMDOPTS=
++ BUILD=../../_build/ocamlbuild.native bbcc.cma main.byte bbcc.cmxa main.native -no-skip -classic-display
++ BUILD1=../../_build/ocamlbuild.native bbcc.cma main.byte bbcc.cmxa main.native -no-skip -classic-display
++ BUILD2=../../_build/ocamlbuild.native bbcc.cma main.byte bbcc.cmxa main.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
++ rm -rf _build
++ svn revert bb.ml
++ ../../_build/ocamlbuild.native bbcc.cma main.byte bbcc.cmxa main.native -no-skip -classic-display
+ocamlopt.opt -I /Users/ertai/local/lib/ocamlbuild unix.cmxa /Users/ertai/local/lib/ocamlbuild/ocamlbuildlib.cmxa myocamlbuild.ml /Users/ertai/local/lib/ocamlbuild/ocamlbuild.cmx -o myocamlbuild
+ocamldep.opt -modules bb.ml > bb.ml.depends
+ocamldep.opt -modules bb.mli > bb.mli.depends
+ocamlc.opt -c -o bb.cmi bb.mli
+ocamldep.opt -modules cc.ml > cc.ml.depends
+ocamldep.opt -modules c2.mli > c2.mli.depends
+ocamldep.opt -modules aa.ml > aa.ml.depends
+ocamlc.opt -c -o c2.cmi c2.mli
+ocamlc.opt -c -o aa.cmo aa.ml
+ocamlc.opt -c -o bb.cmo bb.ml
+ocamlc.opt -c -o cc.cmo cc.ml
+ocamlc.opt -a bb.cmo cc.cmo -o bbcc.cma
+ocamldep.opt -modules main.ml > main.ml.depends
+ocamldep.opt -modules c3.ml > c3.ml.depends
+ocamlc.opt -c -o c3.cmo c3.ml
+ocamlc.opt -c -o main.cmo main.ml
+ocamldep.opt -modules cool_plugin.ml > cool_plugin.ml.depends
+ocamlc.opt -c -o cool_plugin.cmo cool_plugin.ml
+ocamldep.opt -modules c2.ml > c2.ml.depends
+ocamlc.opt -c -o c2.cmo c2.ml
+ocamlc.opt aa.cmo c2.cmo bbcc.cma c3.cmo main.cmo cool_plugin.cmo -o main.byte
+ocamlopt.opt -c -o bb.cmx bb.ml
+ocamlopt.opt -c -o c2.cmx c2.ml
+ocamlopt.opt -c -o aa.cmx aa.ml
+ocamlopt.opt -c -o cc.cmx cc.ml
+ocamlopt.opt -a bb.cmx cc.cmx -o bbcc.cmxa
+ocamlopt.opt -c -o c3.cmx c3.ml
+ocamlopt.opt -c -o main.cmx main.ml
+ocamlopt.opt aa.cmx c2.cmx bbcc.cmxa c3.cmx main.cmx -o main.native
++ ../../_build/ocamlbuild.native bbcc.cma main.byte bbcc.cmxa main.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
+[cache hit] ocamldep.opt -modules bb.ml > bb.ml.depends
+[cache hit] ocamldep.opt -modules bb.mli > bb.mli.depends
+[cache hit] ocamlc.opt -c -o bb.cmi bb.mli
+[cache hit] ocamlc.opt -c -o bb.cmo bb.ml
+[cache hit] ocamldep.opt -modules cc.ml > cc.ml.depends
+[cache hit] ocamldep.opt -modules c2.mli > c2.mli.depends
+[cache hit] ocamlc.opt -c -o c2.cmi c2.mli
+[cache hit] ocamldep.opt -modules aa.ml > aa.ml.depends
+[cache hit] ocamlc.opt -c -o aa.cmo aa.ml
+[cache hit] ocamlc.opt -c -o cc.cmo cc.ml
+[cache hit] ocamlc.opt -a bb.cmo cc.cmo -o bbcc.cma
+[cache hit] ocamldep.opt -modules main.ml > main.ml.depends
+[cache hit] ocamldep.opt -modules c3.ml > c3.ml.depends
+[cache hit] ocamlc.opt -c -o c3.cmo c3.ml
+[cache hit] ocamlc.opt -c -o main.cmo main.ml
+[cache hit] ocamldep.opt -modules cool_plugin.ml > cool_plugin.ml.depends
+[cache hit] ocamlc.opt -c -o cool_plugin.cmo cool_plugin.ml
+[cache hit] ocamldep.opt -modules c2.ml > c2.ml.depends
+[cache hit] ocamlc.opt -c -o c2.cmo c2.ml
+[cache hit] ocamlc.opt aa.cmo c2.cmo bbcc.cma c3.cmo main.cmo cool_plugin.cmo -o main.byte
+[cache hit] ocamlopt.opt -c -o bb.cmx bb.ml
+[cache hit] ocamlopt.opt -c -o c2.cmx c2.ml
+[cache hit] ocamlopt.opt -c -o aa.cmx aa.ml
+[cache hit] ocamlopt.opt -c -o cc.cmx cc.ml
+[cache hit] ocamlopt.opt -a bb.cmx cc.cmx -o bbcc.cmxa
+[cache hit] ocamlopt.opt -c -o c3.cmx c3.ml
+[cache hit] ocamlopt.opt -c -o main.cmx main.ml
+[cache hit] ocamlopt.opt aa.cmx c2.cmx bbcc.cmxa c3.cmx main.cmx -o main.native
++ cp bb2.ml bb.ml
++ ../../_build/ocamlbuild.native bbcc.cma main.byte bbcc.cmxa main.native -no-skip -classic-display -verbose 0
+ocamldep.opt -modules bb.ml > bb.ml.depends
+[cache hit] ocamldep.opt -modules bb.mli > bb.mli.depends
+[cache hit] ocamlc.opt -c -o bb.cmi bb.mli
+[cache hit] ocamldep.opt -modules cc.ml > cc.ml.depends
+[cache hit] ocamldep.opt -modules c2.mli > c2.mli.depends
+[cache hit] ocamlc.opt -c -o c2.cmi c2.mli
+[cache hit] ocamldep.opt -modules aa.ml > aa.ml.depends
+[cache hit] ocamlc.opt -c -o aa.cmo aa.ml
+[cache hit] ocamlc.opt -c -o cc.cmo cc.ml
+ocamlc.opt -c -o bb.cmo bb.ml
+ocamlc.opt -a bb.cmo cc.cmo -o bbcc.cma
+[cache hit] ocamldep.opt -modules main.ml > main.ml.depends
+[cache hit] ocamldep.opt -modules c3.ml > c3.ml.depends
+[cache hit] ocamlc.opt -c -o c3.cmo c3.ml
+[cache hit] ocamlc.opt -c -o main.cmo main.ml
+[cache hit] ocamldep.opt -modules cool_plugin.ml > cool_plugin.ml.depends
+[cache hit] ocamlc.opt -c -o cool_plugin.cmo cool_plugin.ml
+[cache hit] ocamldep.opt -modules c2.ml > c2.ml.depends
+[cache hit] ocamlc.opt -c -o c2.cmo c2.ml
+ocamlc.opt aa.cmo c2.cmo bbcc.cma c3.cmo main.cmo cool_plugin.cmo -o main.byte
+[cache hit] ocamlopt.opt -c -o c2.cmx c2.ml
+ocamlopt.opt -c -o bb.cmx bb.ml
+[cache hit] ocamlopt.opt -c -o aa.cmx aa.ml
+ocamlopt.opt -c -o cc.cmx cc.ml
+ocamlopt.opt -a bb.cmx cc.cmx -o bbcc.cmxa
+ocamlopt.opt -c -o c3.cmx c3.ml
+ocamlopt.opt -c -o main.cmx main.ml
+ocamlopt.opt aa.cmx c2.cmx bbcc.cmxa c3.cmx main.cmx -o main.native
++ ../../_build/ocamlbuild.native bbcc.cma main.byte bbcc.cmxa main.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
+[cache hit] ocamldep.opt -modules bb.ml > bb.ml.depends
+[cache hit] ocamldep.opt -modules bb.mli > bb.mli.depends
+[cache hit] ocamlc.opt -c -o bb.cmi bb.mli
+[cache hit] ocamlc.opt -c -o bb.cmo bb.ml
+[cache hit] ocamldep.opt -modules cc.ml > cc.ml.depends
+[cache hit] ocamldep.opt -modules c2.mli > c2.mli.depends
+[cache hit] ocamlc.opt -c -o c2.cmi c2.mli
+[cache hit] ocamldep.opt -modules aa.ml > aa.ml.depends
+[cache hit] ocamlc.opt -c -o aa.cmo aa.ml
+[cache hit] ocamlc.opt -c -o cc.cmo cc.ml
+[cache hit] ocamlc.opt -a bb.cmo cc.cmo -o bbcc.cma
+[cache hit] ocamldep.opt -modules main.ml > main.ml.depends
+[cache hit] ocamldep.opt -modules c3.ml > c3.ml.depends
+[cache hit] ocamlc.opt -c -o c3.cmo c3.ml
+[cache hit] ocamlc.opt -c -o main.cmo main.ml
+[cache hit] ocamldep.opt -modules cool_plugin.ml > cool_plugin.ml.depends
+[cache hit] ocamlc.opt -c -o cool_plugin.cmo cool_plugin.ml
+[cache hit] ocamldep.opt -modules c2.ml > c2.ml.depends
+[cache hit] ocamlc.opt -c -o c2.cmo c2.ml
+[cache hit] ocamlc.opt aa.cmo c2.cmo bbcc.cma c3.cmo main.cmo cool_plugin.cmo -o main.byte
+[cache hit] ocamlopt.opt -c -o bb.cmx bb.ml
+[cache hit] ocamlopt.opt -c -o c2.cmx c2.ml
+[cache hit] ocamlopt.opt -c -o aa.cmx aa.ml
+[cache hit] ocamlopt.opt -c -o cc.cmx cc.ml
+[cache hit] ocamlopt.opt -a bb.cmx cc.cmx -o bbcc.cmxa
+[cache hit] ocamlopt.opt -c -o c3.cmx c3.ml
+[cache hit] ocamlopt.opt -c -o main.cmx main.ml
+[cache hit] ocamlopt.opt aa.cmx c2.cmx bbcc.cmxa c3.cmx main.cmx -o main.native
++ cp bb3.ml bb.ml
++ ../../_build/ocamlbuild.native bbcc.cma main.byte bbcc.cmxa main.native -no-skip -classic-display -verbose 0
+ocamldep.opt -modules bb.ml > bb.ml.depends
+[cache hit] ocamldep.opt -modules bb.mli > bb.mli.depends
+[cache hit] ocamlc.opt -c -o bb.cmi bb.mli
+[cache hit] ocamldep.opt -modules cc.ml > cc.ml.depends
+[cache hit] ocamldep.opt -modules c2.mli > c2.mli.depends
+[cache hit] ocamlc.opt -c -o c2.cmi c2.mli
+[cache hit] ocamldep.opt -modules aa.ml > aa.ml.depends
+[cache hit] ocamlc.opt -c -o aa.cmo aa.ml
+[cache hit] ocamlc.opt -c -o cc.cmo cc.ml
+ocamlc.opt -c -o bb.cmo bb.ml
+ocamlc.opt -a bb.cmo cc.cmo -o bbcc.cma
+[cache hit] ocamldep.opt -modules main.ml > main.ml.depends
+[cache hit] ocamldep.opt -modules c3.ml > c3.ml.depends
+[cache hit] ocamlc.opt -c -o c3.cmo c3.ml
+[cache hit] ocamlc.opt -c -o main.cmo main.ml
+[cache hit] ocamldep.opt -modules cool_plugin.ml > cool_plugin.ml.depends
+[cache hit] ocamlc.opt -c -o cool_plugin.cmo cool_plugin.ml
+[cache hit] ocamldep.opt -modules c2.ml > c2.ml.depends
+[cache hit] ocamlc.opt -c -o c2.cmo c2.ml
+ocamlc.opt aa.cmo c2.cmo bbcc.cma c3.cmo main.cmo cool_plugin.cmo -o main.byte
+[cache hit] ocamlopt.opt -c -o c2.cmx c2.ml
+ocamlopt.opt -c -o bb.cmx bb.ml
+[cache hit] ocamlopt.opt -c -o aa.cmx aa.ml
+[cache hit] ocamlopt.opt -c -o cc.cmx cc.ml
+ocamlopt.opt -a bb.cmx cc.cmx -o bbcc.cmxa
+[cache hit] ocamlopt.opt -c -o c3.cmx c3.ml
+[cache hit] ocamlopt.opt -c -o main.cmx main.ml
+ocamlopt.opt aa.cmx c2.cmx bbcc.cmxa c3.cmx main.cmx -o main.native
++ ../../_build/ocamlbuild.native bbcc.cma main.byte bbcc.cmxa main.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
+[cache hit] ocamldep.opt -modules bb.ml > bb.ml.depends
+[cache hit] ocamldep.opt -modules bb.mli > bb.mli.depends
+[cache hit] ocamlc.opt -c -o bb.cmi bb.mli
+[cache hit] ocamlc.opt -c -o bb.cmo bb.ml
+[cache hit] ocamldep.opt -modules cc.ml > cc.ml.depends
+[cache hit] ocamldep.opt -modules c2.mli > c2.mli.depends
+[cache hit] ocamlc.opt -c -o c2.cmi c2.mli
+[cache hit] ocamldep.opt -modules aa.ml > aa.ml.depends
+[cache hit] ocamlc.opt -c -o aa.cmo aa.ml
+[cache hit] ocamlc.opt -c -o cc.cmo cc.ml
+[cache hit] ocamlc.opt -a bb.cmo cc.cmo -o bbcc.cma
+[cache hit] ocamldep.opt -modules main.ml > main.ml.depends
+[cache hit] ocamldep.opt -modules c3.ml > c3.ml.depends
+[cache hit] ocamlc.opt -c -o c3.cmo c3.ml
+[cache hit] ocamlc.opt -c -o main.cmo main.ml
+[cache hit] ocamldep.opt -modules cool_plugin.ml > cool_plugin.ml.depends
+[cache hit] ocamlc.opt -c -o cool_plugin.cmo cool_plugin.ml
+[cache hit] ocamldep.opt -modules c2.ml > c2.ml.depends
+[cache hit] ocamlc.opt -c -o c2.cmo c2.ml
+[cache hit] ocamlc.opt aa.cmo c2.cmo bbcc.cma c3.cmo main.cmo cool_plugin.cmo -o main.byte
+[cache hit] ocamlopt.opt -c -o bb.cmx bb.ml
+[cache hit] ocamlopt.opt -c -o c2.cmx c2.ml
+[cache hit] ocamlopt.opt -c -o aa.cmx aa.ml
+[cache hit] ocamlopt.opt -c -o cc.cmx cc.ml
+[cache hit] ocamlopt.opt -a bb.cmx cc.cmx -o bbcc.cmxa
+[cache hit] ocamlopt.opt -c -o c3.cmx c3.ml
+[cache hit] ocamlopt.opt -c -o main.cmx main.ml
+[cache hit] ocamlopt.opt aa.cmx c2.cmx bbcc.cmxa c3.cmx main.cmx -o main.native
++ svn revert bb.ml
+Reverted 'bb.ml'
+ _____ _ ___
+|_ _|__ ___| |_( _ )
+ | |/ _ \/ __| __/ _ \
+ | | __/\__ \ || (_) |
+ |_|\___||___/\__\___/
+
++ CMDOPTS=
++ BUILD=../../_build/ocamlbuild.native a.byte a.native -no-skip -classic-display
++ BUILD1=../../_build/ocamlbuild.native a.byte a.native -no-skip -classic-display
++ BUILD2=../../_build/ocamlbuild.native a.byte a.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
++ rm -rf _build
++ ../../_build/ocamlbuild.native a.byte a.native -no-skip -classic-display
+ocamlopt.opt -I /Users/ertai/local/lib/ocamlbuild unix.cmxa /Users/ertai/local/lib/ocamlbuild/ocamlbuildlib.cmxa myocamlbuild.ml /Users/ertai/local/lib/ocamlbuild/ocamlbuild.cmx -o myocamlbuild
+ocamldep.opt -modules a.ml > a.ml.depends
+ocamldep.opt -modules myconfig.ml > myconfig.ml.depends
+ocamlc.opt -c -o myconfig.cmo myconfig.ml
+ocamlc.opt -c -o a.cmo a.ml
+ocamlc.opt myconfig.cmo a.cmo -o a.byte
+ocamlopt.opt -c -o myconfig.cmx myconfig.ml
+ocamlopt.opt -c -o a.cmx a.ml
+ocamlopt.opt myconfig.cmx a.cmx -o a.native
++ ../../_build/ocamlbuild.native a.byte a.native -no-skip -classic-display -verbose 0 -nothing-should-be-rebuilt
+[cache hit] ocamldep.opt -modules a.ml > a.ml.depends
+[cache hit] ocamldep.opt -modules myconfig.ml > myconfig.ml.depends
+[cache hit] ocamlc.opt -c -o myconfig.cmo myconfig.ml
+[cache hit] ocamlc.opt -c -o a.cmo a.ml
+[cache hit] ocamlc.opt myconfig.cmo a.cmo -o a.byte
+[cache hit] ocamlopt.opt -c -o myconfig.cmx myconfig.ml
+[cache hit] ocamlopt.opt -c -o a.cmx a.ml
+[cache hit] ocamlopt.opt myconfig.cmx a.cmx -o a.native
+ _____ _ ___
+|_ _|__ ___| |_ / _ \
+ | |/ _ \/ __| __| (_) |
+ | | __/\__ \ |_ \__, |
+ |_|\___||___/\__| /_/
+
+++ dirname ./test9/test.sh
++ cd ./test9/../..
++ ./_build/ocamlbuild.native -quiet -build-dir _buildtest -no-links test/test9/testglob.native
++ ./_buildtest/test/test9/testglob.native
+Globexp for "\"hello\"" OK
+Globexp for "<hello>" OK
+Globexp for "<hel*lo>" OK
+Globexp for "<a> and <b> or <c>" OK
+Globexp for "<a> titi" OK
+Glob.eval "<[a]>" "a" = true OK
+Glob.eval "<[a]>" "b" = false OK
+Glob.eval "<[a]>" "a" = true OK
+Glob.eval "<[a]>" "b" = false OK
+Glob.eval "<[a]>" "a" = true OK
+Glob.eval "<[a]>" "b" = false OK
+Glob.eval "<[a-z]>" "a" = true OK
+Glob.eval "<[a-z]>" "e" = true OK
+Glob.eval "<[a-z]>" "k" = true OK
+Glob.eval "<[a-z]>" "z" = true OK
+Glob.eval "<[a-z]>" "0" = false OK
+Glob.eval "<[a-z]>" "A" = false OK
+Glob.eval "<[a-z]>" "~" = false OK
+Glob.eval "<[a-z]>" "a" = true OK
+Glob.eval "<[a-z]>" "e" = true OK
+Glob.eval "<[a-z]>" "k" = true OK
+Glob.eval "<[a-z]>" "z" = true OK
+Glob.eval "<[a-z]>" "0" = false OK
+Glob.eval "<[a-z]>" "A" = false OK
+Glob.eval "<[a-z]>" "~" = false OK
+Glob.eval "<[a-z]>" "a" = true OK
+Glob.eval "<[a-z]>" "e" = true OK
+Glob.eval "<[a-z]>" "k" = true OK
+Glob.eval "<[a-z]>" "z" = true OK
+Glob.eval "<[a-z]>" "0" = false OK
+Glob.eval "<[a-z]>" "A" = false OK
+Glob.eval "<[a-z]>" "~" = false OK
+Glob.eval "<[a-z][0-9]>" "a0" = true OK
+Glob.eval "<[a-z][0-9]>" "b9" = true OK
+Glob.eval "<[a-z][0-9]>" "a00" = false OK
+Glob.eval "<[a-z][0-9]>" "a0a" = false OK
+Glob.eval "<[a-z][0-9]>" "b0a" = false OK
+Glob.eval "<[a-z][0-9]>" "isduis" = false OK
+Glob.eval "<[a-z][0-9]>" "" = false OK
+Glob.eval "<[a-z][0-9]>" "a0" = true OK
+Glob.eval "<[a-z][0-9]>" "b9" = true OK
+Glob.eval "<[a-z][0-9]>" "a00" = false OK
+Glob.eval "<[a-z][0-9]>" "a0a" = false OK
+Glob.eval "<[a-z][0-9]>" "b0a" = false OK
+Glob.eval "<[a-z][0-9]>" "isduis" = false OK
+Glob.eval "<[a-z][0-9]>" "" = false OK
+Glob.eval "<[a-z][0-9]>" "a0" = true OK
+Glob.eval "<[a-z][0-9]>" "b9" = true OK
+Glob.eval "<[a-z][0-9]>" "a00" = false OK
+Glob.eval "<[a-z][0-9]>" "a0a" = false OK
+Glob.eval "<[a-z][0-9]>" "b0a" = false OK
+Glob.eval "<[a-z][0-9]>" "isduis" = false OK
+Glob.eval "<[a-z][0-9]>" "" = false OK
+Glob.eval "<hello>" "hello" = true OK
+Glob.eval "<hello>" "helli" = false OK
+Glob.eval "<hello>" "hello" = true OK
+Glob.eval "<hello>" "helli" = false OK
+Glob.eval "<hello>" "hello" = true OK
+Glob.eval "<hello>" "helli" = false OK
+Glob.eval "\"hello\"" "hello" = true OK
+Glob.eval "\"hello\"" "heidi" = false OK
+Glob.eval "\"hello\"" "hello" = true OK
+Glob.eval "\"hello\"" "heidi" = false OK
+Glob.eval "\"hello\"" "hello" = true OK
+Glob.eval "\"hello\"" "heidi" = false OK
+Glob.eval "<*>" "" = true OK
+Glob.eval "<*>" "a" = true OK
+Glob.eval "<*>" "ax" = true OK
+Glob.eval "<*>" "" = true OK
+Glob.eval "<*>" "a" = true OK
+Glob.eval "<*>" "ax" = true OK
+Glob.eval "<*>" "" = true OK
+Glob.eval "<*>" "a" = true OK
+Glob.eval "<*>" "ax" = true OK
+Glob.eval "<a*b>" "ab" = true OK
+Glob.eval "<a*b>" "acb" = true OK
+Glob.eval "<a*b>" "axxxxxb" = true OK
+Glob.eval "<a*b>" "ababbababb" = true OK
+Glob.eval "<a*b>" "abx" = false OK
+Glob.eval "<a*b>" "xxxxxab" = false OK
+Glob.eval "<a*b>" "xab" = false OK
+Glob.eval "<a*b>" "ab" = true OK
+Glob.eval "<a*b>" "acb" = true OK
+Glob.eval "<a*b>" "axxxxxb" = true OK
+Glob.eval "<a*b>" "ababbababb" = true OK
+Glob.eval "<a*b>" "abx" = false OK
+Glob.eval "<a*b>" "xxxxxab" = false OK
+Glob.eval "<a*b>" "xab" = false OK
+Glob.eval "<a*b>" "ab" = true OK
+Glob.eval "<a*b>" "acb" = true OK
+Glob.eval "<a*b>" "axxxxxb" = true OK
+Glob.eval "<a*b>" "ababbababb" = true OK
+Glob.eval "<a*b>" "abx" = false OK
+Glob.eval "<a*b>" "xxxxxab" = false OK
+Glob.eval "<a*b>" "xab" = false OK
+Glob.eval "<*.ml>" "hello.ml" = true OK
+Glob.eval "<*.ml>" ".ml" = true OK
+Glob.eval "<*.ml>" "ml" = false OK
+Glob.eval "<*.ml>" "" = false OK
+Glob.eval "<*.ml>" "toto.mli" = false OK
+Glob.eval "<*.ml>" "hello.ml" = true OK
+Glob.eval "<*.ml>" ".ml" = true OK
+Glob.eval "<*.ml>" "ml" = false OK
+Glob.eval "<*.ml>" "" = false OK
+Glob.eval "<*.ml>" "toto.mli" = false OK
+Glob.eval "<*.ml>" "hello.ml" = true OK
+Glob.eval "<*.ml>" ".ml" = true OK
+Glob.eval "<*.ml>" "ml" = false OK
+Glob.eval "<*.ml>" "" = false OK
+Glob.eval "<*.ml>" "toto.mli" = false OK
+Glob.eval "<a>" "a" = true OK
+Glob.eval "<a>" "" = false OK
+Glob.eval "<a>" "aa" = false OK
+Glob.eval "<a>" "ba" = false OK
+Glob.eval "<a>" "ab" = false OK
+Glob.eval "<a>" "abaa" = false OK
+Glob.eval "<a>" "a" = true OK
+Glob.eval "<a>" "" = false OK
+Glob.eval "<a>" "aa" = false OK
+Glob.eval "<a>" "ba" = false OK
+Glob.eval "<a>" "ab" = false OK
+Glob.eval "<a>" "abaa" = false OK
+Glob.eval "<a>" "a" = true OK
+Glob.eval "<a>" "" = false OK
+Glob.eval "<a>" "aa" = false OK
+Glob.eval "<a>" "ba" = false OK
+Glob.eval "<a>" "ab" = false OK
+Glob.eval "<a>" "abaa" = false OK
+Glob.eval "<ab>" "ab" = true OK
+Glob.eval "<ab>" "" = false OK
+Glob.eval "<ab>" "abab" = false OK
+Glob.eval "<ab>" "aba" = false OK
+Glob.eval "<ab>" "abx" = false OK
+Glob.eval "<ab>" "ab" = true OK
+Glob.eval "<ab>" "" = false OK
+Glob.eval "<ab>" "abab" = false OK
+Glob.eval "<ab>" "aba" = false OK
+Glob.eval "<ab>" "abx" = false OK
+Glob.eval "<ab>" "ab" = true OK
+Glob.eval "<ab>" "" = false OK
+Glob.eval "<ab>" "abab" = false OK
+Glob.eval "<ab>" "aba" = false OK
+Glob.eval "<ab>" "abx" = false OK
+Glob.eval "<ab?c>" "abac" = true OK
+Glob.eval "<ab?c>" "abxc" = true OK
+Glob.eval "<ab?c>" "abab" = false OK
+Glob.eval "<ab?c>" "ababab" = false OK
+Glob.eval "<ab?c>" "ababa" = false OK
+Glob.eval "<ab?c>" "abac" = true OK
+Glob.eval "<ab?c>" "abxc" = true OK
+Glob.eval "<ab?c>" "abab" = false OK
+Glob.eval "<ab?c>" "ababab" = false OK
+Glob.eval "<ab?c>" "ababa" = false OK
+Glob.eval "<ab?c>" "abac" = true OK
+Glob.eval "<ab?c>" "abxc" = true OK
+Glob.eval "<ab?c>" "abab" = false OK
+Glob.eval "<ab?c>" "ababab" = false OK
+Glob.eval "<ab?c>" "ababa" = false OK
+Glob.eval "<*ab?cd*>" "123abecd345" = true OK
+Glob.eval "<*ab?cd*>" "abccd" = true OK
+Glob.eval "<*ab?cd*>" "abccd345" = true OK
+Glob.eval "<*ab?cd*>" "ababcababccdab" = true OK
+Glob.eval "<*ab?cd*>" "abcd" = false OK
+Glob.eval "<*ab?cd*>" "aaaaabcdababcd" = false OK
+Glob.eval "<*ab?cd*>" "123abecd345" = true OK
+Glob.eval "<*ab?cd*>" "abccd" = true OK
+Glob.eval "<*ab?cd*>" "abccd345" = true OK
+Glob.eval "<*ab?cd*>" "ababcababccdab" = true OK
+Glob.eval "<*ab?cd*>" "abcd" = false OK
+Glob.eval "<*ab?cd*>" "aaaaabcdababcd" = false OK
+Glob.eval "<*ab?cd*>" "123abecd345" = true OK
+Glob.eval "<*ab?cd*>" "abccd" = true OK
+Glob.eval "<*ab?cd*>" "abccd345" = true OK
+Glob.eval "<*ab?cd*>" "ababcababccdab" = true OK
+Glob.eval "<*ab?cd*>" "abcd" = false OK
+Glob.eval "<*ab?cd*>" "aaaaabcdababcd" = false OK
+Glob.eval "<*this*is*a*test*>" "this is a test" = true OK
+Glob.eval "<*this*is*a*test*>" "You know this is a test really" = true OK
+Glob.eval "<*this*is*a*test*>" "thisisatest" = true OK
+Glob.eval "<*this*is*a*test*>" "thisatest" = false OK
+Glob.eval "<*this*is*a*test*>" "this is a test" = true OK
+Glob.eval "<*this*is*a*test*>" "You know this is a test really" = true OK
+Glob.eval "<*this*is*a*test*>" "thisisatest" = true OK
+Glob.eval "<*this*is*a*test*>" "thisatest" = false OK
+Glob.eval "<*this*is*a*test*>" "this is a test" = true OK
+Glob.eval "<*this*is*a*test*>" "You know this is a test really" = true OK
+Glob.eval "<*this*is*a*test*>" "thisisatest" = true OK
+Glob.eval "<*this*is*a*test*>" "thisatest" = false OK
+Glob.eval "<b*>" "bxx" = true OK
+Glob.eval "<b*>" "bx" = true OK
+Glob.eval "<b*>" "aaab" = false OK
+Glob.eval "<b*>" "" = false OK
+Glob.eval "<b*>" "bxx" = true OK
+Glob.eval "<b*>" "bx" = true OK
+Glob.eval "<b*>" "aaab" = false OK
+Glob.eval "<b*>" "" = false OK
+Glob.eval "<b*>" "bxx" = true OK
+Glob.eval "<b*>" "bx" = true OK
+Glob.eval "<b*>" "aaab" = false OK
+Glob.eval "<b*>" "" = false OK
+Glob.eval "<*>" "" = true OK
+Glob.eval "<*>" "a" = true OK
+Glob.eval "<*>" "aaa" = true OK
+Glob.eval "<*>" "aaaaa" = true OK
+Glob.eval "<*>" "" = true OK
+Glob.eval "<*>" "a" = true OK
+Glob.eval "<*>" "aaa" = true OK
+Glob.eval "<*>" "aaaaa" = true OK
+Glob.eval "<*>" "" = true OK
+Glob.eval "<*>" "a" = true OK
+Glob.eval "<*>" "aaa" = true OK
+Glob.eval "<*>" "aaaaa" = true OK
+Glob.eval "<?>" "a" = true OK
+Glob.eval "<?>" "" = false OK
+Glob.eval "<?>" "aaa" = false OK
+Glob.eval "<?>" "aaaaa" = false OK
+Glob.eval "<?>" "a" = true OK
+Glob.eval "<?>" "" = false OK
+Glob.eval "<?>" "aaa" = false OK
+Glob.eval "<?>" "aaaaa" = false OK
+Glob.eval "<?>" "a" = true OK
+Glob.eval "<?>" "" = false OK
+Glob.eval "<?>" "aaa" = false OK
+Glob.eval "<?>" "aaaaa" = false OK
+Glob.eval "<{a,b}>" "a" = true OK
+Glob.eval "<{a,b}>" "b" = true OK
+Glob.eval "<{a,b}>" "" = false OK
+Glob.eval "<{a,b}>" "aa" = false OK
+Glob.eval "<{a,b}>" "ab" = false OK
+Glob.eval "<{a,b}>" "ba" = false OK
+Glob.eval "<{a,b}>" "bb" = false OK
+Glob.eval "<{a,b}>" "c" = false OK
+Glob.eval "<{a,b}>" "a" = true OK
+Glob.eval "<{a,b}>" "b" = true OK
+Glob.eval "<{a,b}>" "" = false OK
+Glob.eval "<{a,b}>" "aa" = false OK
+Glob.eval "<{a,b}>" "ab" = false OK
+Glob.eval "<{a,b}>" "ba" = false OK
+Glob.eval "<{a,b}>" "bb" = false OK
+Glob.eval "<{a,b}>" "c" = false OK
+Glob.eval "<{a,b}>" "a" = true OK
+Glob.eval "<{a,b}>" "b" = true OK
+Glob.eval "<{a,b}>" "" = false OK
+Glob.eval "<{a,b}>" "aa" = false OK
+Glob.eval "<{a,b}>" "ab" = false OK
+Glob.eval "<{a,b}>" "ba" = false OK
+Glob.eval "<{a,b}>" "bb" = false OK
+Glob.eval "<{a,b}>" "c" = false OK
+Glob.eval "<toto.{ml,mli}>" "toto.ml" = true OK
+Glob.eval "<toto.{ml,mli}>" "toto.mli" = true OK
+Glob.eval "<toto.{ml,mli}>" "toto." = false OK
+Glob.eval "<toto.{ml,mli}>" "toto.mll" = false OK
+Glob.eval "<toto.{ml,mli}>" "toto.ml" = true OK
+Glob.eval "<toto.{ml,mli}>" "toto.mli" = true OK
+Glob.eval "<toto.{ml,mli}>" "toto." = false OK
+Glob.eval "<toto.{ml,mli}>" "toto.mll" = false OK
+Glob.eval "<toto.{ml,mli}>" "toto.ml" = true OK
+Glob.eval "<toto.{ml,mli}>" "toto.mli" = true OK
+Glob.eval "<toto.{ml,mli}>" "toto." = false OK
+Glob.eval "<toto.{ml,mli}>" "toto.mll" = false OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "acf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "acg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "adf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "adg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "aef" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "aeg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bcf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bcg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bdf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bdg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bef" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "beg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "afg" = false OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "af" = false OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "aee" = false OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "acf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "acg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "adf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "adg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "aef" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "aeg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bcf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bcg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bdf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bdg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bef" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "beg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "afg" = false OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "af" = false OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "aee" = false OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "acf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "acg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "adf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "adg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "aef" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "aeg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bcf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bcg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bdf" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bdg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "bef" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "beg" = true OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "afg" = false OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "af" = false OK
+Glob.eval "<{a,b}{c,[de]}{f,g}>" "aee" = false OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "a.ml" = true OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "b.ml" = true OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "a.mli" = true OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "hello.ml" = false OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "a.mli.x" = false OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "a.ml" = true OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "b.ml" = true OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "a.mli" = true OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "hello.ml" = false OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "a.mli.x" = false OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "a.ml" = true OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "b.ml" = true OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "a.mli" = true OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "hello.ml" = false OK
+Glob.eval "(<*.ml> or <*.mli>) and not \"hello.ml\"" "a.mli.x" = false OK
+Glob.eval "<*>" "alpha" = true OK
+Glob.eval "<*>" "beta" = true OK
+Glob.eval "<*>" "alpha/beta" = false OK
+Glob.eval "<*>" "gamma/delta" = false OK
+Glob.eval "<*>" "alpha" = true OK
+Glob.eval "<*>" "beta" = true OK
+Glob.eval "<*>" "alpha/beta" = false OK
+Glob.eval "<*>" "gamma/delta" = false OK
+Glob.eval "<*>" "alpha" = true OK
+Glob.eval "<*>" "beta" = true OK
+Glob.eval "<*>" "alpha/beta" = false OK
+Glob.eval "<*>" "gamma/delta" = false OK
+Glob.eval "<alpha/**/beta>" "alpha/beta" = true OK
+Glob.eval "<alpha/**/beta>" "alpha/gamma/beta" = true OK
+Glob.eval "<alpha/**/beta>" "alpha/gamma/delta/beta" = true OK
+Glob.eval "<alpha/**/beta>" "alpha" = false OK
+Glob.eval "<alpha/**/beta>" "beta" = false OK
+Glob.eval "<alpha/**/beta>" "gamma/delta" = false OK
+Glob.eval "<alpha/**/beta>" "alpha/beta" = true OK
+Glob.eval "<alpha/**/beta>" "alpha/gamma/beta" = true OK
+Glob.eval "<alpha/**/beta>" "alpha/gamma/delta/beta" = true OK
+Glob.eval "<alpha/**/beta>" "alpha" = false OK
+Glob.eval "<alpha/**/beta>" "beta" = false OK
+Glob.eval "<alpha/**/beta>" "gamma/delta" = false OK
+Glob.eval "<alpha/**/beta>" "alpha/beta" = true OK
+Glob.eval "<alpha/**/beta>" "alpha/gamma/beta" = true OK
+Glob.eval "<alpha/**/beta>" "alpha/gamma/delta/beta" = true OK
+Glob.eval "<alpha/**/beta>" "alpha" = false OK
+Glob.eval "<alpha/**/beta>" "beta" = false OK
+Glob.eval "<alpha/**/beta>" "gamma/delta" = false OK
+Glob.eval "<**/*.ml>" "toto.ml" = true OK
+Glob.eval "<**/*.ml>" "toto/tata.ml" = true OK
+Glob.eval "<**/*.ml>" "alpha/gamma/delta/beta.ml" = true OK
+Glob.eval "<**/*.ml>" "toto.mli" = false OK
+Glob.eval "<**/*.ml>" "toto.ml" = true OK
+Glob.eval "<**/*.ml>" "toto/tata.ml" = true OK
+Glob.eval "<**/*.ml>" "alpha/gamma/delta/beta.ml" = true OK
+Glob.eval "<**/*.ml>" "toto.mli" = false OK
+Glob.eval "<**/*.ml>" "toto.ml" = true OK
+Glob.eval "<**/*.ml>" "toto/tata.ml" = true OK
+Glob.eval "<**/*.ml>" "alpha/gamma/delta/beta.ml" = true OK
+Glob.eval "<**/*.ml>" "toto.mli" = false OK
+Glob.eval "<toto/**>" "toto/" = true OK
+Glob.eval "<toto/**>" "toto/tata" = true OK
+Glob.eval "<toto/**>" "toto/alpha/gamma/delta/beta.ml" = true OK
+Glob.eval "<toto/**>" "toto" = true OK
+Glob.eval "<toto/**>" "toto2/tata" = false OK
+Glob.eval "<toto/**>" "tata/titi" = false OK
+Glob.eval "<toto/**>" "toto/" = true OK
+Glob.eval "<toto/**>" "toto/tata" = true OK
+Glob.eval "<toto/**>" "toto/alpha/gamma/delta/beta.ml" = true OK
+Glob.eval "<toto/**>" "toto" = true OK
+Glob.eval "<toto/**>" "toto2/tata" = false OK
+Glob.eval "<toto/**>" "tata/titi" = false OK
+Glob.eval "<toto/**>" "toto/" = true OK
+Glob.eval "<toto/**>" "toto/tata" = true OK
+Glob.eval "<toto/**>" "toto/alpha/gamma/delta/beta.ml" = true OK
+Glob.eval "<toto/**>" "toto" = true OK
+Glob.eval "<toto/**>" "toto2/tata" = false OK
+Glob.eval "<toto/**>" "tata/titi" = false OK
diff --git a/ocamlbuild/test/runtest.sh b/ocamlbuild/test/runtest.sh
new file mode 100755
index 0000000000..7bdb76be13
--- /dev/null
+++ b/ocamlbuild/test/runtest.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+set -e
+cd `dirname $0`
+
+myfiglet() {
+ figlet $@ | sed 's/ *$//'
+}
+
+if figlet ""; then
+ BANNER=myfiglet
+else
+ echo "Install figlet to have a better output, press enter to continue with echo"
+ read
+ BANNER=echo
+fi
+
+HERE=`pwd`
+
+$BANNER Test2
+./test2/test.sh $@
+$BANNER Test3
+./test3/test.sh $@
+$BANNER Test4
+./test4/test.sh $@
+$BANNER Test5
+./test5/test.sh $@
+$BANNER Test6
+./test6/test.sh $@
+$BANNER Test7
+./test7/test.sh $@
+$BANNER Test8
+./test8/test.sh $@
+$BANNER Test9
+./test9/test.sh $@
diff --git a/ocamlbuild/test/test1/foo.ml b/ocamlbuild/test/test1/foo.ml
new file mode 100644
index 0000000000..43a5106519
--- /dev/null
+++ b/ocamlbuild/test/test1/foo.ml
@@ -0,0 +1 @@
+module MA1 = A1
diff --git a/ocamlbuild/test/test10/dbdi b/ocamlbuild/test/test10/dbdi
new file mode 100644
index 0000000000..7f548108bb
--- /dev/null
+++ b/ocamlbuild/test/test10/dbdi
@@ -0,0 +1,12 @@
+#load "discard_printf.cmo";;
+#load "debug.cmo";;
+#load "unix.cma";;
+#load "str.cma";;
+#load "my_unix.cmo";;
+#load "bool.cmo";;
+#load "glob_ast.cmo";;
+#load "glob_lexer.cmo";;
+#load "glob.cmo";;
+#load "lexers.cmo";;
+#load "my_std.cmo";;
+#load "tags.cmo";;
diff --git a/ocamlbuild/test/test10/test.sh b/ocamlbuild/test/test10/test.sh
new file mode 100755
index 0000000000..1f96443c5e
--- /dev/null
+++ b/ocamlbuild/test/test10/test.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+set -e
+set -x
+cd `dirname $0`/../..
+./_build/ocamlbuild.native -quiet -build-dir _buildtest -no-links test/test9/testglob.native
+./_buildtest/test/test9/testglob.native
diff --git a/ocamlbuild/test/test2/_tags b/ocamlbuild/test/test2/_tags
new file mode 100644
index 0000000000..354ad4e694
--- /dev/null
+++ b/ocamlbuild/test/test2/_tags
@@ -0,0 +1 @@
+"vivi.ml": camlp4o
diff --git a/ocamlbuild/test/test2/tata.ml b/ocamlbuild/test/test2/tata.ml
new file mode 100644
index 0000000000..361fadd354
--- /dev/null
+++ b/ocamlbuild/test/test2/tata.ml
@@ -0,0 +1 @@
+let tata = "TATA2"
diff --git a/ocamlbuild/test/test2/tata.mli b/ocamlbuild/test/test2/tata.mli
new file mode 100644
index 0000000000..7c7175c91f
--- /dev/null
+++ b/ocamlbuild/test/test2/tata.mli
@@ -0,0 +1,2 @@
+(* a comment *)
+val tata : string
diff --git a/ocamlbuild/test/test2/test.sh b/ocamlbuild/test/test2/test.sh
new file mode 100755
index 0000000000..8bbd7c7a7c
--- /dev/null
+++ b/ocamlbuild/test/test2/test.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+cd `dirname $0`
+set -e
+set -x
+CMDOPTS="-- -help"
+BUILD="../../_build/ocamlbuild.native toto.byte toto.native -no-skip -classic-display $@"
+BUILD1="$BUILD $CMDOPTS"
+BUILD2="$BUILD -verbose 0 -nothing-should-be-rebuilt $CMDOPTS"
+rm -rf _build
+cp vivi1.ml vivi.ml
+$BUILD1
+$BUILD2
+cp vivi2.ml vivi.ml
+$BUILD1
+$BUILD2
+cp vivi3.ml vivi.ml
+$BUILD1
+$BUILD2
diff --git a/ocamlbuild/test/test2/titi.ml b/ocamlbuild/test/test2/titi.ml
new file mode 100644
index 0000000000..3abbf1d2e2
--- /dev/null
+++ b/ocamlbuild/test/test2/titi.ml
@@ -0,0 +1 @@
+let titi = []
diff --git a/ocamlbuild/test/test2/toto.ml b/ocamlbuild/test/test2/toto.ml
new file mode 100644
index 0000000000..dbb5a43d38
--- /dev/null
+++ b/ocamlbuild/test/test2/toto.ml
@@ -0,0 +1,5 @@
+let i = Tutu.tutu + 10
+let s = Tata.tata ^ ".ml"
+let l = 3 :: Titi.titi
+let () = Format.printf "toto.native: %s: Hello world!!!@." Sys.argv.(0)
+let () = Format.printf "Tutu.tutu => %d@.Tata.tata => %S@." Tutu.tutu Tata.tata
diff --git a/ocamlbuild/test/test2/tutu.ml b/ocamlbuild/test/test2/tutu.ml
new file mode 100644
index 0000000000..2e8015b701
--- /dev/null
+++ b/ocamlbuild/test/test2/tutu.ml
@@ -0,0 +1,2 @@
+let tutu = (Array.length Vivi.vivi : Tyty.t)
+let tutu' = 2.0 +. float_of_int tutu
diff --git a/ocamlbuild/test/test2/tutu.mli b/ocamlbuild/test/test2/tutu.mli
new file mode 100644
index 0000000000..26657f87cd
--- /dev/null
+++ b/ocamlbuild/test/test2/tutu.mli
@@ -0,0 +1,3 @@
+(* a comment *)
+val tutu : int
+val tutu' : float
diff --git a/ocamlbuild/test/test2/tyty.mli b/ocamlbuild/test/test2/tyty.mli
new file mode 100644
index 0000000000..975adb5316
--- /dev/null
+++ b/ocamlbuild/test/test2/tyty.mli
@@ -0,0 +1 @@
+type t = int
diff --git a/ocamlbuild/test/test2/vivi1.ml b/ocamlbuild/test/test2/vivi1.ml
new file mode 100644
index 0000000000..1c0517e011
--- /dev/null
+++ b/ocamlbuild/test/test2/vivi1.ml
@@ -0,0 +1,2 @@
+let rec p i = [< '1; '2; p (i + 1) >]
+let vivi = [|2|]
diff --git a/ocamlbuild/test/test2/vivi2.ml b/ocamlbuild/test/test2/vivi2.ml
new file mode 100644
index 0000000000..1fb48c1763
--- /dev/null
+++ b/ocamlbuild/test/test2/vivi2.ml
@@ -0,0 +1,2 @@
+let rec p i = [< '1; '2; p (i + 1) >]
+let vivi = [|3|]
diff --git a/ocamlbuild/test/test2/vivi3.ml b/ocamlbuild/test/test2/vivi3.ml
new file mode 100644
index 0000000000..7849fad651
--- /dev/null
+++ b/ocamlbuild/test/test2/vivi3.ml
@@ -0,0 +1,2 @@
+let rec p i = [< '1; '2; p (i + 1) >]
+let vivi = [|2.1; 1.1|]
diff --git a/ocamlbuild/test/test3/_tags b/ocamlbuild/test/test3/_tags
new file mode 100644
index 0000000000..4505f13fda
--- /dev/null
+++ b/ocamlbuild/test/test3/_tags
@@ -0,0 +1 @@
+"a.byte" or "a.native": use_unix
diff --git a/ocamlbuild/test/test3/a.ml b/ocamlbuild/test/test3/a.ml
new file mode 100644
index 0000000000..d4586eae7b
--- /dev/null
+++ b/ocamlbuild/test/test3/a.ml
@@ -0,0 +1 @@
+module X = B
diff --git a/ocamlbuild/test/test3/a.mli b/ocamlbuild/test/test3/a.mli
new file mode 100644
index 0000000000..c17617a6e8
--- /dev/null
+++ b/ocamlbuild/test/test3/a.mli
@@ -0,0 +1 @@
+(* Nothing *)
diff --git a/ocamlbuild/test/test3/b.ml b/ocamlbuild/test/test3/b.ml
new file mode 100644
index 0000000000..58c510c1e4
--- /dev/null
+++ b/ocamlbuild/test/test3/b.ml
@@ -0,0 +1 @@
+module X = C
diff --git a/ocamlbuild/test/test3/b.mli b/ocamlbuild/test/test3/b.mli
new file mode 100644
index 0000000000..5eea480960
--- /dev/null
+++ b/ocamlbuild/test/test3/b.mli
@@ -0,0 +1 @@
+(* nothing *)
diff --git a/ocamlbuild/test/test3/c.ml b/ocamlbuild/test/test3/c.ml
new file mode 100644
index 0000000000..06f0fd9185
--- /dev/null
+++ b/ocamlbuild/test/test3/c.ml
@@ -0,0 +1 @@
+module X = D
diff --git a/ocamlbuild/test/test3/c.mli b/ocamlbuild/test/test3/c.mli
new file mode 100644
index 0000000000..5eea480960
--- /dev/null
+++ b/ocamlbuild/test/test3/c.mli
@@ -0,0 +1 @@
+(* nothing *)
diff --git a/ocamlbuild/test/test3/d.ml b/ocamlbuild/test/test3/d.ml
new file mode 100644
index 0000000000..42ab724240
--- /dev/null
+++ b/ocamlbuild/test/test3/d.ml
@@ -0,0 +1 @@
+module X = E
diff --git a/ocamlbuild/test/test3/d.mli b/ocamlbuild/test/test3/d.mli
new file mode 100644
index 0000000000..5eea480960
--- /dev/null
+++ b/ocamlbuild/test/test3/d.mli
@@ -0,0 +1 @@
+(* nothing *)
diff --git a/ocamlbuild/test/test3/e.ml b/ocamlbuild/test/test3/e.ml
new file mode 100644
index 0000000000..863ea00c87
--- /dev/null
+++ b/ocamlbuild/test/test3/e.ml
@@ -0,0 +1 @@
+module X = F
diff --git a/ocamlbuild/test/test3/e.mli b/ocamlbuild/test/test3/e.mli
new file mode 100644
index 0000000000..5eea480960
--- /dev/null
+++ b/ocamlbuild/test/test3/e.mli
@@ -0,0 +1 @@
+(* nothing *)
diff --git a/ocamlbuild/test/test3/f.ml b/ocamlbuild/test/test3/f.ml
new file mode 100644
index 0000000000..00915fdc1b
--- /dev/null
+++ b/ocamlbuild/test/test3/f.ml
@@ -0,0 +1,2 @@
+(* nothing *)
+let _ = Unix.stat
diff --git a/ocamlbuild/test/test3/f.mli b/ocamlbuild/test/test3/f.mli
new file mode 100644
index 0000000000..5eea480960
--- /dev/null
+++ b/ocamlbuild/test/test3/f.mli
@@ -0,0 +1 @@
+(* nothing *)
diff --git a/ocamlbuild/test/test3/proj.odocl b/ocamlbuild/test/test3/proj.odocl
new file mode 100644
index 0000000000..532c720382
--- /dev/null
+++ b/ocamlbuild/test/test3/proj.odocl
@@ -0,0 +1 @@
+A B C D E F
diff --git a/ocamlbuild/test/test3/test.sh b/ocamlbuild/test/test3/test.sh
new file mode 100755
index 0000000000..396aaf2aaf
--- /dev/null
+++ b/ocamlbuild/test/test3/test.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd `dirname $0`
+set -e
+set -x
+CMDOTPS="" # -- command args
+BUILD="../../_build/ocamlbuild.native a.byte a.native proj.docdir/index.html -no-skip -classic-display $@"
+BUILD1="$BUILD $CMDOPTS"
+BUILD2="$BUILD -verbose 0 -nothing-should-be-rebuilt $CMDOPTS"
+rm -rf _build
+$BUILD1
+$BUILD2
diff --git a/ocamlbuild/test/test4/_tags b/ocamlbuild/test/test4/_tags
new file mode 100644
index 0000000000..4b6e7986ea
--- /dev/null
+++ b/ocamlbuild/test/test4/_tags
@@ -0,0 +1,2 @@
+# a comment
+"a/aa.byte" or "a/aa.native": use_str
diff --git a/ocamlbuild/test/test4/a/aa.ml b/ocamlbuild/test/test4/a/aa.ml
new file mode 100644
index 0000000000..411d29bffe
--- /dev/null
+++ b/ocamlbuild/test/test4/a/aa.ml
@@ -0,0 +1 @@
+let bar = 3 + List.length Bb.foo
diff --git a/ocamlbuild/test/test4/a/aa.mli b/ocamlbuild/test/test4/a/aa.mli
new file mode 100644
index 0000000000..20f3c52a88
--- /dev/null
+++ b/ocamlbuild/test/test4/a/aa.mli
@@ -0,0 +1 @@
+val bar : int
diff --git a/ocamlbuild/test/test4/b/bb.ml b/ocamlbuild/test/test4/b/bb.ml
new file mode 100644
index 0000000000..031031fba6
--- /dev/null
+++ b/ocamlbuild/test/test4/b/bb.ml
@@ -0,0 +1,2 @@
+let r = Str.regexp "r"
+let foo = [2.2]
diff --git a/ocamlbuild/test/test4/test.sh b/ocamlbuild/test/test4/test.sh
new file mode 100755
index 0000000000..4b2580a8de
--- /dev/null
+++ b/ocamlbuild/test/test4/test.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd `dirname $0`
+set -e
+set -x
+CMDOTPS="" # -- command args
+BUILD="../../_build/ocamlbuild.native -I a -I b aa.byte aa.native -no-skip -classic-display $@"
+BUILD1="$BUILD $CMDOPTS"
+BUILD2="$BUILD -verbose 0 -nothing-should-be-rebuilt $CMDOPTS"
+rm -rf _build
+$BUILD1
+$BUILD2
diff --git a/ocamlbuild/test/test5/_tags b/ocamlbuild/test/test5/_tags
new file mode 100644
index 0000000000..2f66a28c1d
--- /dev/null
+++ b/ocamlbuild/test/test5/_tags
@@ -0,0 +1 @@
+"a.cmx" or "b.cmx": for-pack(C)
diff --git a/ocamlbuild/test/test5/a.ml b/ocamlbuild/test/test5/a.ml
new file mode 100644
index 0000000000..2509003015
--- /dev/null
+++ b/ocamlbuild/test/test5/a.ml
@@ -0,0 +1 @@
+let a = 42
diff --git a/ocamlbuild/test/test5/a.mli b/ocamlbuild/test/test5/a.mli
new file mode 100644
index 0000000000..3f79c81490
--- /dev/null
+++ b/ocamlbuild/test/test5/a.mli
@@ -0,0 +1 @@
+val a : int
diff --git a/ocamlbuild/test/test5/b.ml b/ocamlbuild/test/test5/b.ml
new file mode 100644
index 0000000000..8db5ca3b86
--- /dev/null
+++ b/ocamlbuild/test/test5/b.ml
@@ -0,0 +1 @@
+let b = A.a + 1
diff --git a/ocamlbuild/test/test5/c.mlpack b/ocamlbuild/test/test5/c.mlpack
new file mode 100644
index 0000000000..5decc2b6a1
--- /dev/null
+++ b/ocamlbuild/test/test5/c.mlpack
@@ -0,0 +1 @@
+A B
diff --git a/ocamlbuild/test/test5/d.ml b/ocamlbuild/test/test5/d.ml
new file mode 100644
index 0000000000..a5ec43298f
--- /dev/null
+++ b/ocamlbuild/test/test5/d.ml
@@ -0,0 +1 @@
+Format.printf "C.B.b = %d@." C.B.b
diff --git a/ocamlbuild/test/test5/test.sh b/ocamlbuild/test/test5/test.sh
new file mode 100755
index 0000000000..9d78f1991c
--- /dev/null
+++ b/ocamlbuild/test/test5/test.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd `dirname $0`
+set -e
+set -x
+CMDOPTS="" # -- command args
+BUILD="../../_build/ocamlbuild.native d.byte d.native -no-skip -classic-display $@"
+BUILD1="$BUILD $CMDOPTS"
+BUILD2="$BUILD -verbose 0 -nothing-should-be-rebuilt $CMDOPTS"
+rm -rf _build
+$BUILD1
+$BUILD2
diff --git a/ocamlbuild/test/test6/a.ml b/ocamlbuild/test/test6/a.ml
new file mode 100644
index 0000000000..e09e5d02a3
--- /dev/null
+++ b/ocamlbuild/test/test6/a.ml
@@ -0,0 +1 @@
+let a = B.b
diff --git a/ocamlbuild/test/test6/a.mli b/ocamlbuild/test/test6/a.mli
new file mode 100644
index 0000000000..451c586eb3
--- /dev/null
+++ b/ocamlbuild/test/test6/a.mli
@@ -0,0 +1 @@
+val a : 'a -> 'a
diff --git a/ocamlbuild/test/test6/b.ml b/ocamlbuild/test/test6/b.ml
new file mode 100644
index 0000000000..362c8fc158
--- /dev/null
+++ b/ocamlbuild/test/test6/b.ml
@@ -0,0 +1 @@
+let b = D.d
diff --git a/ocamlbuild/test/test6/b.mli b/ocamlbuild/test/test6/b.mli
new file mode 100644
index 0000000000..685b7906be
--- /dev/null
+++ b/ocamlbuild/test/test6/b.mli
@@ -0,0 +1 @@
+val b : 'a -> 'a
diff --git a/ocamlbuild/test/test6/b.mli.v1 b/ocamlbuild/test/test6/b.mli.v1
new file mode 100644
index 0000000000..685b7906be
--- /dev/null
+++ b/ocamlbuild/test/test6/b.mli.v1
@@ -0,0 +1 @@
+val b : 'a -> 'a
diff --git a/ocamlbuild/test/test6/b.mli.v2 b/ocamlbuild/test/test6/b.mli.v2
new file mode 100644
index 0000000000..a431698375
--- /dev/null
+++ b/ocamlbuild/test/test6/b.mli.v2
@@ -0,0 +1,2 @@
+....
+val b : 'a -> 'a
diff --git a/ocamlbuild/test/test6/d.ml b/ocamlbuild/test/test6/d.ml
new file mode 100644
index 0000000000..61c7a9c62f
--- /dev/null
+++ b/ocamlbuild/test/test6/d.ml
@@ -0,0 +1,2 @@
+type t
+let d x = x
diff --git a/ocamlbuild/test/test6/d.mli b/ocamlbuild/test/test6/d.mli
new file mode 100644
index 0000000000..1db89bbe67
--- /dev/null
+++ b/ocamlbuild/test/test6/d.mli
@@ -0,0 +1 @@
+val d : 'a -> 'a
diff --git a/ocamlbuild/test/test6/d.mli.v1 b/ocamlbuild/test/test6/d.mli.v1
new file mode 100644
index 0000000000..12fea1c160
--- /dev/null
+++ b/ocamlbuild/test/test6/d.mli.v1
@@ -0,0 +1,2 @@
+type t
+val d : 'a -> 'a
diff --git a/ocamlbuild/test/test6/d.mli.v2 b/ocamlbuild/test/test6/d.mli.v2
new file mode 100644
index 0000000000..1db89bbe67
--- /dev/null
+++ b/ocamlbuild/test/test6/d.mli.v2
@@ -0,0 +1 @@
+val d : 'a -> 'a
diff --git a/ocamlbuild/test/test6/main.ml b/ocamlbuild/test/test6/main.ml
new file mode 100644
index 0000000000..61acf12831
--- /dev/null
+++ b/ocamlbuild/test/test6/main.ml
@@ -0,0 +1 @@
+A.a 2. +. D.d 1.
diff --git a/ocamlbuild/test/test6/main.mli b/ocamlbuild/test/test6/main.mli
new file mode 100644
index 0000000000..5eea480960
--- /dev/null
+++ b/ocamlbuild/test/test6/main.mli
@@ -0,0 +1 @@
+(* nothing *)
diff --git a/ocamlbuild/test/test6/test.sh b/ocamlbuild/test/test6/test.sh
new file mode 100755
index 0000000000..fedbc9c9b3
--- /dev/null
+++ b/ocamlbuild/test/test6/test.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+cd `dirname $0`
+set -x
+rm -rf _build
+CMDOPTS="" # -- command args
+BUILD="../../_build/ocamlbuild.native -no-skip main.byte -classic-display $@"
+BUILD1="$BUILD $CMDOPTS"
+BUILD2="$BUILD -verbose 0 -nothing-should-be-rebuilt $CMDOPTS"
+cp b.mli.v1 b.mli
+cp d.mli.v1 d.mli
+$BUILD1
+$BUILD2
+cp b.mli.v2 b.mli
+cp d.mli.v2 d.mli
+$BUILD1
+cp b.mli.v1 b.mli
+if $BUILD1; then
+ if $BUILD2; then
+ echo PASS
+ else
+ echo "FAIL (-nothing-should-be-rebuilt)"
+ fi
+else
+ echo FAIL
+fi
+
diff --git a/ocamlbuild/test/test7/_tags b/ocamlbuild/test/test7/_tags
new file mode 100644
index 0000000000..8501e32851
--- /dev/null
+++ b/ocamlbuild/test/test7/_tags
@@ -0,0 +1 @@
+"main.byte": my_cool_plugin
diff --git a/ocamlbuild/test/test7/aa.ml b/ocamlbuild/test/test7/aa.ml
new file mode 100644
index 0000000000..877d0af148
--- /dev/null
+++ b/ocamlbuild/test/test7/aa.ml
@@ -0,0 +1 @@
+let aa = "aa"
diff --git a/ocamlbuild/test/test7/bb.ml b/ocamlbuild/test/test7/bb.ml
new file mode 100644
index 0000000000..9ac2d5965e
--- /dev/null
+++ b/ocamlbuild/test/test7/bb.ml
@@ -0,0 +1 @@
+let bb = 43
diff --git a/ocamlbuild/test/test7/bb.mli b/ocamlbuild/test/test7/bb.mli
new file mode 100644
index 0000000000..9256de2b1f
--- /dev/null
+++ b/ocamlbuild/test/test7/bb.mli
@@ -0,0 +1 @@
+val bb : int
diff --git a/ocamlbuild/test/test7/bb2.ml b/ocamlbuild/test/test7/bb2.ml
new file mode 100644
index 0000000000..2f91b988b8
--- /dev/null
+++ b/ocamlbuild/test/test7/bb2.ml
@@ -0,0 +1,3 @@
+let bb = 43
+let f x = x + 1
+let () = incr (ref 0)
diff --git a/ocamlbuild/test/test7/bb3.ml b/ocamlbuild/test/test7/bb3.ml
new file mode 100644
index 0000000000..b7ad4b5c23
--- /dev/null
+++ b/ocamlbuild/test/test7/bb3.ml
@@ -0,0 +1,3 @@
+let bb = 43
+let f x = x + 1
+let () = incr (ref 1)
diff --git a/ocamlbuild/test/test7/bbcc.mllib b/ocamlbuild/test/test7/bbcc.mllib
new file mode 100644
index 0000000000..a97a0e6c2a
--- /dev/null
+++ b/ocamlbuild/test/test7/bbcc.mllib
@@ -0,0 +1 @@
+Bb Cc
diff --git a/ocamlbuild/test/test7/c2.ml b/ocamlbuild/test/test7/c2.ml
new file mode 100644
index 0000000000..36ff6d6fbf
--- /dev/null
+++ b/ocamlbuild/test/test7/c2.ml
@@ -0,0 +1 @@
+let c2 = 12
diff --git a/ocamlbuild/test/test7/c2.mli b/ocamlbuild/test/test7/c2.mli
new file mode 100644
index 0000000000..19fe565dfd
--- /dev/null
+++ b/ocamlbuild/test/test7/c2.mli
@@ -0,0 +1 @@
+val c2 : int
diff --git a/ocamlbuild/test/test7/c3.ml b/ocamlbuild/test/test7/c3.ml
new file mode 100644
index 0000000000..277e1ee0ad
--- /dev/null
+++ b/ocamlbuild/test/test7/c3.ml
@@ -0,0 +1 @@
+let c3 = Bb.bb + 13
diff --git a/ocamlbuild/test/test7/cc.ml b/ocamlbuild/test/test7/cc.ml
new file mode 100644
index 0000000000..b39ef21df6
--- /dev/null
+++ b/ocamlbuild/test/test7/cc.ml
@@ -0,0 +1 @@
+let cc = (String.length Aa.aa) + Bb.bb + C2.c2
diff --git a/ocamlbuild/test/test7/cool_plugin.ml b/ocamlbuild/test/test7/cool_plugin.ml
new file mode 100644
index 0000000000..3225186872
--- /dev/null
+++ b/ocamlbuild/test/test7/cool_plugin.ml
@@ -0,0 +1 @@
+print_endline "I am a cool plugin"
diff --git a/ocamlbuild/test/test7/main.ml b/ocamlbuild/test/test7/main.ml
new file mode 100644
index 0000000000..f12195969e
--- /dev/null
+++ b/ocamlbuild/test/test7/main.ml
@@ -0,0 +1 @@
+let main = String.length Aa.aa - Bb.bb - C3.c3 - Cc.cc - 1
diff --git a/ocamlbuild/test/test7/myocamlbuild.ml b/ocamlbuild/test/test7/myocamlbuild.ml
new file mode 100644
index 0000000000..12b274ff04
--- /dev/null
+++ b/ocamlbuild/test/test7/myocamlbuild.ml
@@ -0,0 +1,3 @@
+open Ocamlbuild_plugin;;
+use_lib "main" "bbcc";;
+dep ["ocaml"; "link"; "byte"; "my_cool_plugin"] ["cool_plugin.cmo"];;
diff --git a/ocamlbuild/test/test7/test.sh b/ocamlbuild/test/test7/test.sh
new file mode 100755
index 0000000000..0ccb69d98a
--- /dev/null
+++ b/ocamlbuild/test/test7/test.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+cd `dirname $0`
+set -e
+set -x
+CMDOPTS="" # -- command args
+BUILD="../../_build/ocamlbuild.native bbcc.cma main.byte bbcc.cmxa main.native -no-skip -classic-display $@"
+BUILD1="$BUILD $CMDARGS"
+BUILD2="$BUILD -verbose 0 -nothing-should-be-rebuilt $CMDARGS"
+rm -rf _build
+svn revert bb.ml
+$BUILD1
+$BUILD2
+cp bb2.ml bb.ml
+$BUILD1 -verbose 0
+$BUILD2
+cp bb3.ml bb.ml
+$BUILD1 -verbose 0
+$BUILD2
+svn revert bb.ml
diff --git a/ocamlbuild/test/test8/a.ml b/ocamlbuild/test/test8/a.ml
new file mode 100644
index 0000000000..35ac749963
--- /dev/null
+++ b/ocamlbuild/test/test8/a.ml
@@ -0,0 +1 @@
+print_endline Myconfig.version;;
diff --git a/ocamlbuild/test/test8/myocamlbuild.ml b/ocamlbuild/test/test8/myocamlbuild.ml
new file mode 100644
index 0000000000..4a8ae9d683
--- /dev/null
+++ b/ocamlbuild/test/test8/myocamlbuild.ml
@@ -0,0 +1,9 @@
+open Ocamlbuild_pack;;
+open Ocamlbuild_plugin;;
+let version = "0.1";;
+file_rule "myconfig.ml"
+ ~prod:"myconfig.ml"
+ ~cache:(fun _ -> version)
+ begin fun _ oc ->
+ Printf.fprintf oc "let version = %S;;\n%!" version
+ end;;
diff --git a/ocamlbuild/test/test8/test.sh b/ocamlbuild/test/test8/test.sh
new file mode 100755
index 0000000000..80fc7197c6
--- /dev/null
+++ b/ocamlbuild/test/test8/test.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd `dirname $0`
+set -e
+set -x
+CMDOPTS="" # -- command args
+BUILD="../../_build/ocamlbuild.native a.byte a.native -no-skip -classic-display $@"
+BUILD1="$BUILD $CMDOPTS"
+BUILD2="$BUILD -verbose 0 -nothing-should-be-rebuilt $CMDOPTS"
+rm -rf _build
+$BUILD1
+$BUILD2
diff --git a/ocamlbuild/test/test9/dbgl b/ocamlbuild/test/test9/dbgl
new file mode 100644
index 0000000000..ac61a3d555
--- /dev/null
+++ b/ocamlbuild/test/test9/dbgl
@@ -0,0 +1,10 @@
+#load "unix.cma";;
+#load "str.cma";;
+#load "discard_printf.cmo";;
+#load "debug.cmo";;
+#load "bool.cmo";;
+#load "glob_ast.cmo";;
+#load "glob_lexer.cmo";;
+#load "my_unix.cmo";;
+#use "glob.ml";;
+#install_printer print_is;;
diff --git a/ocamlbuild/test/test9/test.sh b/ocamlbuild/test/test9/test.sh
new file mode 100755
index 0000000000..0feded2082
--- /dev/null
+++ b/ocamlbuild/test/test9/test.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+set -e
+set -x
+cd `dirname $0`/../..
+./_build/ocamlbuild.native -quiet -build-dir _buildtest -no-links test/test9/testglob.native $@
+./_buildtest/test/test9/testglob.native
diff --git a/ocamlbuild/test/test9/testglob.ml b/ocamlbuild/test/test9/testglob.ml
new file mode 100644
index 0000000000..e307a769ca
--- /dev/null
+++ b/ocamlbuild/test/test9/testglob.ml
@@ -0,0 +1,91 @@
+(* Testglob *)
+
+open Bool;;
+open Glob;;
+
+let yep f x =
+ try
+ ignore (f x);
+ true
+ with
+ | _ -> false
+;;
+
+let tests1 = [
+ "\"hello\"", true;
+ "<hello>", true;
+ "<hel*lo>", true;
+ "<a> and <b> or <c>", true;
+ "<a> titi", false
+];;
+
+let tests2 = [
+ "<[a]>", ["a"], ["b"];
+ "<[a-z]>", ["a";"e";"k";"z"], ["0";"A";"~"];
+ "<[a-z][0-9]>", ["a0";"b9"], ["a00";"a0a";"b0a";"isduis";""];
+ "<hello>", ["hello"], ["helli"];
+ "\"hello\"", ["hello"], ["heidi"];
+ "<*>", ["";"a";"ax"], [];
+ "<a*b>", ["ab";"acb";"axxxxxb";"ababbababb"], ["abx";"xxxxxab";"xab"];
+ "<*.ml>", ["hello.ml";".ml"], ["ml"; ""; "toto.mli"];
+ "<a>", ["a"], ["";"aa";"ba";"ab";"abaa"];
+ "<ab>", ["ab"], ["";"abab";"aba";"abx"];
+ "<ab?c>", ["abac";"abxc"], ["abab";"ababab";"ababa"];
+ "<*ab?cd*>", ["123abecd345";"abccd";"abccd345";"ababcababccdab"], ["abcd";"aaaaabcdababcd"];
+ "<*this*is*a*test*>", ["this is a test";"You know this is a test really";"thisisatest"], ["thisatest"];
+ "<b*>", ["bxx";"bx"], ["aaab";""];
+ "<*>", ["";"a";"aaa";"aaaaa"], [];
+ "<?>", ["a"],["";"aaa";"aaaaa"];
+ "<{a,b}>", ["a";"b"],["";"aa";"ab";"ba";"bb";"c"];
+ "<toto.{ml,mli}>", ["toto.ml";"toto.mli"],["toto.";"toto.mll"];
+ "<{a,b}{c,[de]}{f,g}>", ["acf";"acg";"adf";"adg";"aef";"aeg";"bcf";"bcg";"bdf";"bdg";"bef";"beg"],
+ ["afg";"af";"aee"];
+ "(<*.ml> or <*.mli>) and not \"hello.ml\"",
+ ["a.ml"; "b.ml"; "a.mli"],
+ ["hello.ml"; "a.mli.x"];
+ "<*>", ["alpha";"beta"], ["alpha/beta";"gamma/delta"];
+ "<alpha/**/beta>", ["alpha/beta";"alpha/gamma/beta";"alpha/gamma/delta/beta"],
+ ["alpha";"beta";"gamma/delta"];
+ "<**/*.ml>", ["toto.ml";"toto/tata.ml";"alpha/gamma/delta/beta.ml"],
+ ["toto.mli"];
+ "<toto/**>", ["toto/";"toto/tata";"toto/alpha/gamma/delta/beta.ml";"toto"],
+ ["toto2/tata"; "tata/titi"]
+];;
+
+
+let _ =
+ let times = 3 in
+ List.iter
+ begin fun (str, ast) ->
+ let ast' = yep Glob.parse str in
+ if ast <> ast' then
+ begin
+ Printf.printf "Globexp parsing failed for %S.\n%!" str;
+ exit 1
+ end
+ else
+ Printf.printf "Globexp for %S OK\n%!" str
+ end
+ tests1;
+ List.iter
+ begin fun (gstr, yes, no) ->
+ let globber = Glob.parse gstr in
+ let check polarity =
+ List.iter
+ begin fun y ->
+ if Glob.eval globber y = polarity then
+ Printf.printf "Glob.eval %S %S = %b OK\n%!" gstr y polarity
+ else
+ begin
+ Printf.printf "Glob.eval %S %S = %b FAIL\n%!" gstr y (not polarity);
+ exit 1
+ end
+ end
+ in
+ for k = 1 to times do
+ check true yes;
+ check false no
+ done
+ end
+ tests2
+;;
diff --git a/ocamlbuild/tools.ml b/ocamlbuild/tools.ml
new file mode 100644
index 0000000000..ed69408f3c
--- /dev/null
+++ b/ocamlbuild/tools.ml
@@ -0,0 +1,48 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* Tools *)
+
+open My_std
+open Format
+open Log
+open Pathname.Operators
+open Tags.Operators
+open Rule
+
+let pp_l = List.print String.print
+
+let default_tags = ref Tags.empty;;
+
+let tags_of_pathname p =
+ Tags.add ("file:"^p)
+ (Tags.union (Configuration.tags_of_filename (Pathname.to_string p)) !default_tags)
+let flags_of_pathname p = Configuration.flags_of_filename (Pathname.to_string p)
+
+let opt_print elt ppf =
+ function
+ | Some x -> fprintf ppf "@[<2>Some@ %a@]" elt x
+ | None -> pp_print_string ppf "None"
+
+let path_and_context_of_string s =
+ if Pathname.is_implicit s then
+ let b = Pathname.basename s in
+ let d = Pathname.dirname s in
+ if d <> Pathname.current_dir_name then
+ let () = Pathname.define_context d [d] in
+ [s]
+ else
+ let include_dirs = Pathname.include_dirs_of d in
+ List.map (fun include_dir -> include_dir/b) include_dirs
+ else [s]
+
diff --git a/ocamlbuild/tools.mli b/ocamlbuild/tools.mli
new file mode 100644
index 0000000000..de1f0d3d85
--- /dev/null
+++ b/ocamlbuild/tools.mli
@@ -0,0 +1,20 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+(* Tools *)
+
+val tags_of_pathname : Pathname.t -> Tags.t
+val flags_of_pathname : Pathname.t -> Command.spec
+val default_tags : Tags.t ref
+val path_and_context_of_string : Pathname.t -> Pathname.t list
+val pp_l : Format.formatter -> string list -> unit