summaryrefslogtreecommitdiff
path: root/lib/ocaml/README-OCamlMakefile
blob: 54787b967eac7e6f4a90a7cfe5c414d0d75c4803 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
---------------------------------------------------------------------------

                        Distribution of "ocaml_make"
     Copyright (C) 1999 - 2006  Markus Mottl - free to copy and modify!
                           USE AT YOUR OWN RISK!

---------------------------------------------------------------------------

                            PREREQUISITES

             *** YOU WILL NEED GNU-MAKE VERSION >3.80 ***

---------------------------------------------------------------------------

                    Contents of this distribution

Changes        - guess what? ;-)

OCamlMakefile  - Makefile for easy handling of compilation of not so easy
                 OCaml-projects.  It generates dependencies of OCaml-files
                 automatically, is able to handle "ocamllex"-,
                 "ocamlyacc"-, IDL- and C-files, knows how to run
                 preprocessors and generates native- or byte-code, as
                 executable or as library - with thread-support if you
                 want! Profiling and debugging support can be added on
                 the fly!  There is also support for installing libraries.
                 Ah, yes, and you can also create toplevels from any
                 sources: this allows you immediate interactive testing.
                 Automatic generation of documentation is easy due to
                 integration of support for OCamldoc.

README         - this file

calc/          - Directory containing a quite fully-featured example
                 of what "OCamlMakefile" can do for you. This example
                 makes use of "ocamllex", "ocamlyacc", IDL + C and
                 threads.

camlp4/        - This simple example demonstrates how to automatically
                 preprocess files with the camlp4-preprocessor.

gtk/           - Demonstration of how to use OCamlMakefile with GTK
                 and threads. Courtesy of Tim Freeman <tim@fungible.com>.

idl/           - Contains a very small example of how to use
                 "camlidl" together with "OCamlMakefile". Also intended
                 to show, how easy it is to interface OCaml and C.

threads/       - Two examples of how to use threads (originally
                 posted by Xavier Leroy some time ago). Shows the use of
                 "OCamlMakefile" in an environment of multiple compilation
                 targets.

---------------------------------------------------------------------------

                      Why should you use it?

For several reasons:

  * It is well-tested (I use it in all of my projects).

  * In contrast to most other approaches it generates dependencies
    correctly by ensuring that all automatically generated OCaml-files
    exist before dependency calculation.  This is the only way to
    guarantee that "ocamldep" works correctly.

  * It is extremely convenient (at least I think so ;-).
    Even quite complex compilation processes (see example "calc.ml")
    need very little information to work correctly - actually just about
    the minimum (file names of sources).

---------------------------------------------------------------------------

                     When you shouldn't use it...

In projects where every compilation unit needs different flags - but
in such complicated cases you will be on your own anyway. Luckily,
this doesn't happen too frequently...

---------------------------------------------------------------------------

             How to use "OCamlMakefile" in your own project
         (Take a look at the examples for a quick introduction!)

Create your project-specific "Makefile" in the appropriate directory.

Now there are two ways of making use of "OCamlMakefile":

  1) Have a look at the default settings in "OCamlMakefile" and set
     them to the values that are vaild on your system - whether the
     path to the standard libraries is ok, what executables shall be
     used, etc...

  2) Copy it into the directory of the project to be compiled.
     Add "-include OCamlMakefile" as a last line of your "Makefile".

  3) Put it somewhere else on the system. In this case you will have to
     set a variable "OCAMLMAKEFILE" in your project-specific "Makefile".
     This is the way in which the examples are written: so you need
     only one version of "OCamlMakefile" to manage all your projects!
     See the examples for details.

You should usually specify two further variables for your project:

  * SOURCES  (default: foo.ml)
  * RESULT   (default: foo)

Put all the sources necessary for a target into variable "SOURCES".
Then set "RESULT" to the name of the target. If you want to generate
libraries, you should *not* specify the suffix (".cma", ".cmxa", ".a")
- it will be added automatically if you specify that you want to build
a library.

      **      Don't forget to add the ".mli"-files, too!        **
      **  Don't forget that order of the source files matters!  **

The order is important, because it matters during linking anyway
due to potential side effects caused at program startup. This is
why OCamlMakefile does not attempt to partially order dependencies by
itself, which might confuse users even more. It just compiles and links
OCaml-sources in the order specified by the user, even if it could
determine automatically that the order cannot be correct.

The minimum of your "Makefile" looks like this (assuming that
"OCamlMakefile" is in the search path of "make"):

  -include OCamlMakefile

This will assume that you want to compile a file "foo.ml" to a binary
"foo".

Otherwise, your Makefile will probably contain something like this:

  SOURCES = foo.ml
  RESULT  = foo
  -include OCamlMakefile

Be careful with the names you put into these variables: if they are wrong,
a "make clean" might erase the wrong files - but I know you will not do
that ;-)

A simple "make" will generate a byte-code executable. If you want to
change this, you may add an "all"-rule that generates something else.

E.g.:

  SOURCES = foo.ml
  RESULT  = foo
  all: native-code-library
  -include OCamlMakefile

This will build a native-code library "foo.cmxa" (+ "foo.a") from file
"foo.ml".

You may even build several targets at once. To produce byte- and native-code
executables with one "make", add the following rule:

    all: byte-code native-code

You will probably want to use a different suffix for each of these targets
so that the result will not be overwritten (see optional variables below
for details).

You may also tell "make" at the command-line what kind of target to
produce (e.g. "make nc").  Here all the possibilities with shortcuts
between parenthesis:

   * byte-code                     (bc)
   * byte-code-nolink              (bcnl)   - no linking stage
   * byte-code-library             (bcl)
   * native-code                   (nc)
   * native-code-nolink            (ncnl)   - no linking stage
   * native-code-library           (ncl)
   * debug-code                    (dc)
   * debug-code-nolink             (dcnl)   - no linking stage
   * debug-code-library            (dcl)
   * profiling-byte-code           (pbc)
   * profiling-byte-code-library   (pbcl)
   * profiling-native-code         (pnc)
   * profiling-native-code-library (pncl)
   * byte-code-dll                 (bcd)
   * native-code-dll               (ncd)
   * pack-byte-code                (pabc)
   * pack-native-code              (panc)
   * toplevel interpreter          (top)
   * subprojs

Here a short note concerning building and linking byte code libraries
with C-files:

  OCaml links C-object files only when they are used in an executable.
  After compilation they should be placed in some directory that is in
  your include path if you link your library against an executable.

  It is sometimes more convenient to link all C-object files into a
  single C-library. Then you have to override the automatic link flags
  of your library using "-noautolink" and add another linkflag that
  links in your C-library explicitly.

What concerns maintainance:

  "make clean" removes all (all!) automatically generated files - so
  again: make sure your variables are ok!

  "make cleanup" is similar to "make clean" but leaves executables.

Another way to destroy some important files is by having "OCamlMakefile"
automatically generate files with the same name. Read the documentation
about the tools in the OCaml-distribution to see what kind of files are
generated. "OCamlMakefile" additionally generates ('%' is basename of
source file):

  %_idl.c  - "camlidl" generates a file "%.c" from "%.idl", but this is
             not such a good idea, because when generating native-code,
             both the file "%.c" and "%.ml" would generate files "%.o"
             which would overwrite each other. Thus, "OCamlMakefile"
             renames "%.c" to "%_idl.c" to work around this problem.

The dependencies are stored in three different subdirectories (dot dirs):

  ._d    - contains dependencies for .ml-files
  ._bcdi - contains byte code dependencies for .mli-files
  ._ncdi - contains native code dependencies for .mli-files

The endings of the dependency files are: "%.d" for those generated from
"%.ml"-files, "%.di" for ones derived from "%.mli"-files.

---------------------------------------------------------------------------

                                 Debugging

  This is easy: if you discover a bug, just do a "make clean; make dc"
  to recompile your project with debugging information. Then you can
  immediately apply "ocamldebug" to the executable.

---------------------------------------------------------------------------

                                 Profiling

  For generating code that can be profiled with "ocamlprof" (byte code)
  or "gprof" (native code), compile your project with one of the profiling
  targets (see targets above). E.g.:

    * "make pbc" will build byte code that can be profiled with
      "ocamlprof".

    * "make pnc" will build native code that can be profiled with
      "gprof".

  Please note that it is not currently possible to profile byte code with
  threads. OCamlMakefile will force an error if you try to do this.

  A short hint for DEC Alpha-users (under Digital Unix): you may also
  compile your sources to native code without any further profiling
  options/targets. Then call "pixie my_exec", "my_exec" being your
  executable. This will produce (among other files) an executable
  "my_exec.pixie". Call it and it will produce profiling information which
  can be analysed using "prof -pixie my_exec". The resulting information
  is extremely detailed and allows analysis up to the clock cycle level...

---------------------------------------------------------------------------

                             Using Preprocessors

  Because one could employ any kind of program that reads from standard
  input and prints to standard output as preprocessor, there cannot be any
  default way to handle all of them correctly without further knowledge.

  Therefore you have to cooperate a bit with OCamlMakefile to let
  preprocessing happen automatically. Basically, this only requires
  that you put a comment into the first line of files that should be
  preprocessed, e.g.:

    (*pp cat *)
    ... rest of program ...

  OCamlMakefile looks at the first line of your files, and if it finds
  a comment that starts with "(*pp", then it will assume that the
  rest of the comment tells it how to correctly call the appropriate
  preprocessor. In this case the program "cat" will be called, which will,
  of course, just output the source text again without changing it.

  If you are, for example, an advocate of the new "revised syntax",
  which is supported by the camlp4 preprocessor, you could simply write:

    (*pp camlp4r *)
    ... rest of program in revised syntax ...

  Simple, isn't it?

  If you want to write your own syntax extensions, just take a look at the
  example in the directory "camlp4": it implements the "repeat ... until"
  extension as described in the camlp4-tutorial.

---------------------------------------------------------------------------

                     Library (Un-)Installation Support

  OCamlMakefile contains two targets using "ocamlfind" for this purpose:

    * libinstall
    * libuninstall

  These two targets require the existence of the variable
  "LIBINSTALL_FILES", which should be set to all the files that you
  want to install in the library directory (usually %.mli, %.cmi, %.cma,
  %.cmxa, %.a and possibly further C-libraries). The target "libinstall"
  has the dependency "all" to force compilation of the library so make
  sure you define target "all" in your Makefile appropriately.

  The targets inform the user about the configured install path and ask
  for confirmation to (un)install there. If you want to use them, it
  is often a good idea to just alias them in your Makefile to "install"
  and "uninstall" respectively.

  Two other targets allow installation of files into a particular
  directory (without using ocamlfind):

    * rawinstall
    * rawuninstall

---------------------------------------------------------------------------

                            Building toplevels

  There is just one target for this:

    * top

  The generated file can be used immediately for interactive sessions -
  even with scanners, parsers, C-files, etc.!

---------------------------------------------------------------------------

                         Generating documentation

  The following targets are supported:

   * htdoc      - generates HTML-documentation
   * ladoc      - generates Latex-documentation
   * psdoc      - generates PostScript-documentation
   * pdfdoc     - generates PDF-documentation
   * doc        - generates all supported forms of documentation
   * clean-doc  - generates all supported forms of documentation

  All of them generate a sub-directory "doc". More precisely, for HTML it
  is "doc/$(RESULT)/html" and for Latex, PostScript and PDF the directory
  "doc/$(RESULT)/latex". See the OCamldoc-manual for details and the
  optional variables below for settings you can control.

---------------------------------------------------------------------------

                           Handling subprojects

  You can have several targets in the same directory and manage them
  from within an single Makefile.

  Give each subproject a name, e.g. "p1", "p2", etc. Then you export
  settings specific to each project by using variables of the form
  "PROJ_p1", "PROJ_p2", etc.  E.g.:

    define PROJ_p1
      SOURCES="foo.ml main.ml"
      RESULT="p1"
      OCAMLFLAGS="-unsafe"
    endef
    export PROJ_p1

    define PROJ_p2
      ...
    endef
    export PROJ_p2

  You may also export common settings used by all projects directly, e.g.
  "export THREADS = y".

  Now it is a good idea to define, which projects should be affected by
  commands by default.  E.g.:

    ifndef SUBPROJS
      export SUBPROJS = p1 p2
    endif

  This will automatically generate a given target for all those
  subprojects if this variable has not been defined in the shell
  environment or in the command line of the make-invocation by the user.
  E.g., "make dc" will generate debug code for all subprojects.

  Then you need to define a default action for your subprojects if "make"
  has been called without arguments:

    all: bc

  This will build byte code by default for all subprojects.

  Finally, you'll have to define a catch-all target that uses the target
  provided by the user for all subprojects. Just add (assuming that
  OCAMLMAKEFILE has been defined appropriately):

    %:
            @make -f $(OCAMLMAKEFILE) subprojs SUBTARGET=$@

  See the "threads"-directory in the distribution for a short example!

---------------------------------------------------------------------------

         Optional variables that may be passed to "OCamlMakefile"

  * LIB_PACK_NAME - packs all modules of a library into a module whose
                    name is given in variable "LIB_PACK_NAME".

  * RES_CLIB_SUF  - when building a library that contains C-stubs, this
                    variable controls the suffix appended to the name
                    of the C-library (default: "_stubs").

  * THREADS       - say "THREADS = yes" if you need thread support compiled in,
                    otherwise leave it away.

  * VMTHREADS     - say "VMTHREADS = yes" if you want to force VM-level
                    scheduling of threads (byte-code only).

  * ANNOTATE      - say "ANNOTATE = yes" to generate type annotation files
                    (.annot) to support displaying of type information
                    in editors.

  * USE_CAMLP4    - say "USE_CAMLP4 = yes" in your "Makefile" if you
                    want to include the camlp4 directory during the
                    build process, otherwise leave it away.

  * INCDIRS       - directories that should be searched for ".cmi"- and
                    ".cmo"-files.  You need not write "-I ..." - just the
                    plain names.
  * LIBDIRS       - directories that should be searched for libraries
                    Also just put the plain paths into this variable
  * EXTLIBDIRS    - Same as "LIBDIRS", but paths in this variable are
                    also added to the binary via the "-R"-flag so that
                    dynamic libraries in non-standard places can be found.
  * RESULTDEPS    - Targets on which results (executables or libraries)
                    should additionally depend.

  * PACKS         - adds packages under control of "findlib".

  * PREDS         - specifies "findlib"-predicates.

  * LIBS          - OCaml-libraries that should be linked (just plain names).
                    E.g. if you want to link the Str-library, just write
                    "str" (without quotes).
                    The new OCaml-compiler handles libraries in such
                    a way that they "remember" whether they have to
                    be linked against a C-library and it gets linked
                    in automatically.
                    If there is a slash in the library name (such as
                    "./str" or "lib/foo") then make is told that the
                    generated files depend on the library.  This
                    helps to ensure that changes to your libraries are
                    taken into account, which is important if you are
                    regenerating your libraries frequently.
  * CLIBS         - C-libraries that should be linked (just plain names).

  * PRE_TARGETS   - set this to a list of target files that you want
                    to have buildt before dependency calculation actually
                    takes place. E.g. use this to automatically compile
                    modules needed by camlp4, which have to be available
                    before other modules can be parsed at all.

                    ** WARNING **: the files mentioned in this variable
                    will be removed when "make clean" is executed!

  * LIBINSTALL_FILES - the files of a library that should be installed
                       using "findlib". Default:

                         $(RESULT).mli $(RESULT).cmi $(RESULT).cma
                         $(RESULT).cmxa $(RESULT).a lib$(RESULT).a

  * OCAML_LIB_INSTALL - target directory for "rawinstall/rawuninstall".
                        (default: $(OCAMLLIBPATH)/contrib)

  * DOC_FILES     - names of files from which documentation is generated.
                    (default: all .mli-files in your $(SOURCES)).

  * DOC_DIR       - name of directory where documentation should be stored.

  * OCAMLFLAGS    - flags passed to the compilers
  * OCAMLBCFLAGS  - flags passed to the byte code compiler only
  * OCAMLNCFLAGS  - flags passed to the native code compiler only

  * OCAMLLDFLAGS  - flags passed to the OCaml-linker
  * OCAMLBLDFLAGS - flags passed to the OCaml-linker when linking byte code
  * OCAMLNLDFLAGS - flags passed to the OCaml-linker when linking
                    native code

  * OCAMLMKLIB_FLAGS - flags passed to the OCaml library tool

  * OCAMLCPFLAGS  - profiling flags passed to "ocamlcp" (default: "a")

  * PPFLAGS       - additional flags passed to the preprocessor (default: none)

  * LFLAGS        - flags passed to "ocamllex"
  * YFLAGS        - flags passed to "ocamlyacc"
  * IDLFLAGS      - flags passed to "camlidl"

  * OCAMLDOCFLAGS - flags passed to "ocamldoc"

  * OCAMLFIND_INSTFLAGS - flags passed to "ocamlfind" during installation
                          (default: none)

  * DVIPSFLAGS    - flags passed to dvips
                    (when generating documentation in PostScript).

  * STATIC        - set this variable if you want to force creation
                    of static libraries

  * CC            - the C-compiler to be used
  * CXX           - the C++-compiler to be used

  * CFLAGS        - additional flags passed to the C-compiler.
                    The flag "-DNATIVE_CODE" will be passed automatically
                    if you choose to build native code. This allows you
                    to compile your C-files conditionally. But please
                    note: You should do a "make clean" or remove the
                    object files manually or touch the %.c-files:
                    otherwise, they may not be correctly recompiled
                    between different builds.

  * CXXFLAGS      - additional flags passed to the C++-compiler.

  * CPPFLAGS      - additional flags passed to the C-preprocessor.

  * CFRAMEWORKS   - Objective-C framework to pass to linker on MacOS X.

  * LDFLAGS       - additional flags passed to the C-linker

  * RPATH_FLAG    - flag passed through to the C-linker to set a path for
                    dynamic libraries.  May need to be set by user on
                    exotic platforms.  (default: "-R").

  * ELF_RPATH_FLAG - this flag is used to set the rpath on ELF-platforms.
                     (default: "-R")

  * ELF_RPATH     - if this flag is "yes", then the RPATH_FLAG will be
                    passed by "-Wl" to the linker as normal on
                    ELF-platforms.

  * OCAMLLIBPATH  - path to the OCaml-standard-libraries
                    (first default: `$(OCAMLC) -where`)
                    (second default: "/usr/local/lib/ocaml")

  * OCAML_DEFAULT_DIRS - additional path in which the user can supply
                         default directories to his own collection of
                         libraries.  The idea is to pass this as an environment
                         variable so that the Makefiles do not have to contain
                         this path all the time.

  * OCAMLFIND     - ocamlfind from findlib       (default: "ocamlfind")
  * OCAMLC        - byte-code compiler           (default: "ocamlc")
  * OCAMLOPT      - native-code compiler         (default: "ocamlopt")
  * OCAMLMKTOP    - top-level compiler           (default: "ocamlmktop")
  * OCAMLCP       - profiling byte-code compiler (default: "ocamlcp")
  * OCAMLDEP      - dependency generator         (default: "ocamldep")
  * OCAMLLEX      - scanner generator            (default: "ocamllex")
  * OCAMLYACC     - parser generator             (default: "ocamlyacc")
  * OCAMLMKLIB    - tool to create libraries     (default: "ocamlmklib")
  * CAMLIDL       - IDL-code generator           (default: "camlidl")
  * CAMLIDLDLL    - IDL-utility                  (default: "camlidldll")
  * CAMLP4        - camlp4 preprocessor          (default: "camlp4")
  * OCAMLDOC      - OCamldoc-command             (default: "ocamldoc")

  * LATEX         - Latex-processor              (default: "latex")
  * DVIPS         - dvips-command                (default: "dvips")
  * PS2PDF        - PostScript-to-PDF converter  (default: "ps2pdf")

  * CAMELEON_REPORT - report tool of Cameleon  (default: "report")
  * CAMELEON_REPORT_FLAGS - flags for the report tool of Cameleon

  * CAMELEON_ZOGGY - zoggy tool of Cameleon
                     (default: "camlp4o pa_zog.cma pr_o.cmo")
  * CAMELEON_ZOGGY_FLAGS - flags for the zoggy tool of Cameleon

  * OCAML_GLADECC - Glade compiler for OCaml     (default: "lablgladecc2")
  * OCAML_GLADECC_FLAGS - flags for the Glade compiler

  * OXRIDL        - OXRIDL-generator  (default: "oxridl")

  * NOIDLHEADER   - set to "yes" to prohibit "OCamlMakefile" from using
                    the default camlidl-flag "-header".

  * NO_CUSTOM     - Prevent linking in custom mode.

  * QUIET         - unsetting this variable (e.g. "make QUIET=")
                    will print all executed commands, including
                    intermediate ones. This allows more comfortable
                    debugging when things go wrong during a build.

  * REALLY_QUIET  - when set this flag turns off output from some commands.

  * OCAMLMAKEFILE - location of (=path to) this "OCamlMakefile".
                    Because it calles itself recursively, it has to
                    know where it is. (default: "OCamlMakefile" =
                    local directory)

  * BCSUFFIX      - Suffix for all byte-code files. E.g.:

                      RESULT   = foo
                      BCSUFFIX = _bc

                    This will produce byte-code executables/libraries
                    with basename "foo_bc".

  * NCSUFFIX      - Similar to "BCSUFFIX", but for native-code files.
  * TOPSUFFIX     - Suffix added to toplevel interpreters (default: ".top")

  * SUBPROJS      - variable containing the names of subprojects to be
                    compiled.

  * SUBTARGET     - target to be built for all projects in variable
                    SUBPROJS.

---------------------------------------------------------------------------

                    Optional variables for Windows users

  * MINGW         - variable to detect the MINGW-environment
  * MSVC          - variable to detect the MSVC-compiler

---------------------------------------------------------------------------

Up-to-date information (newest release of distribution) can always be
found at:

  http://www.ocaml.info/home/ocaml_sources.html

---------------------------------------------------------------------------

Enjoy!

New York, 2007-04-22
Markus Mottl

e-mail: markus.mottl@gmail.com
WWW:    http://www.ocaml.info