项目作者: mmottl

项目描述 :
Easy to use Makefile for small to medium-sized OCaml-projects
高级语言: OCaml
项目地址: git://github.com/mmottl/ocaml-makefile.git
创建时间: 2014-07-06T00:30:13Z
项目社区:https://github.com/mmottl/ocaml-makefile

开源协议:Other

下载


OCamlMakefile - A Simple Generic Makefile for OCaml-Projects

Prerequisites

  • GNU-Make version 3.80 or higher

Pros

  • It is well-tested across multiple platforms and has been used in many
    projects.

  • 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 can do its job.

  • Convenience. Even fairly complex compilation processes (see example
    calc.ml) need only little information to work correctly, sometimes
    just about the minimum (filenames of sources).

Cons

  • It may not be a good choice in projects where many compilation units
    require different flags.

  • Though it can scale to medium-sized projects, large projects with,
    for example, dependencies across multiple libraries in different
    directories are not well-supported.

    This is a general shortcoming of the already somewhat dated make.
    You may want to investigate the following tools to approach larger
    projects:

Usage

It is recommended that first-time users take a look at the examples in the
distribution for a quick introduction. OCamlMakefile-projects are often so
simple that they are self-explanatory.

To create your own project, first edit a project-specific Makefile in the
appropriate directory. 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 valid on your system. For example, check
    whether the path to the standard libraries is ok, what executables shall
    be used, etc. Copy it into the directory of the project to be compiled.
    Add the following statement as last line to your Makefile:

    1. -include OCamlMakefile
  2. Put OCamlMakefile somewhere else in your system. In this case you
    will have to set the variable OCAMLMAKEFILE in your project-specific
    Makefile. This is the way in which the examples are written. Now you
    only need one version of OCamlMakefile to manage all of your projects!
    See the examples for details.

You will usually need to 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.

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

The order is important, because it matters during linking 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):

  1. -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:

  1. SOURCES = foo.ml
  2. RESULT = foo
  3. -include OCamlMakefile

Be careful with the names you put into these variables. If they are wrong,
a make clean might erase the wrong files!

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. For example:

  1. SOURCES = foo.ml
  2. RESULT = foo
  3. all: native-code-library
  4. -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:

  1. 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 the 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:

  1. byte-code (bc)
  2. byte-code-nolink (bcnl) - no linking stage
  3. byte-code-library (bcl)
  4. native-code (nc)
  5. native-code-nolink (ncnl) - no linking stage
  6. native-code-library (ncl)
  7. debug-code (dc)
  8. debug-code-nolink (dcnl) - no linking stage
  9. debug-code-library (dcl)
  10. profiling-byte-code (pbc)
  11. profiling-byte-code-library (pbcl)
  12. profiling-native-code (pnc)
  13. profiling-native-code-library (pncl)
  14. byte-code-dll (bcd)
  15. native-code-dll (ncd)
  16. pack-byte-code (pabc)
  17. pack-native-code (panc)
  18. toplevel (top)
  19. subprojs

Here is 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 link flag that
links in your C-library explicitly.

Concerning maintenance:

  • make clean removes all (all!) automatically generated files.
    So again, make sure your variables are ok!

  • make cleanup is similar to make clean but keeps 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 the 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 and %.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

To generate 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 analyzed using prof -pixie my_exec.
The resulting information is extremely detailed and allows analysis up to
the clock cycle level…

Using Preprocessors

Because any kind of program that reads from standard input and prints to
standard output can be used as a 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.:

  1. (*pp cat *)
  2. (* ... 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, for example, you were an advocate of the “revised syntax”, which is
supported by the camlp4 preprocessor, you could simply write:

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

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:

  1. htdoc - generates HTML-documentation
  2. ladoc - generates Latex-documentation
  3. psdoc - generates PostScript-documentation
  4. pdfdoc - generates PDF-documentation
  5. doc - generates all supported forms of documentation
  6. 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.:

  1. define PROJ_p1
  2. SOURCES=foo.ml main.ml
  3. RESULT="p1"
  4. OCAMLFLAGS="-unsafe"
  5. endef
  6. export PROJ_p1
  7. define PROJ_p2
  8. ...
  9. endef
  10. export PROJ_p2

You may also export common settings used by all projects directly, e.g.:

  1. export THREADS = y

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

  1. ifndef SUBPROJS
  2. export SUBPROJS = p1 p2
  3. 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.

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

  1. 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 OCamlMakefile variables

  1. * LIB_PACK_NAME - packs all modules of a library into a module whose
  2. name is given in variable LIB_PACK_NAME.
  3. * RES_CLIB_SUF - when building a library that contains C-stubs, this
  4. variable controls the suffix appended to the name of
  5. the C-library (default: _stubs).
  6. * THREADS - say THREADS = yes if you need thread support compiled in,
  7. otherwise leave it away.
  8. * VMTHREADS - say VMTHREADS = yes if you want to force VM-level
  9. scheduling of threads (byte-code only).
  10. * ANNOTATE - say ANNOTATE = yes to generate type annotation files
  11. (.annot) to support displaying of type information
  12. in editors.
  13. * USE_CAMLP4 - say USE_CAMLP4 = yes in your Makefile if you
  14. want to include the camlp4 directory during the build
  15. process, otherwise leave it away.
  16. * INCDIRS - directories that should be searched for .cmi- and
  17. .cmo-files. You need not write -I ... - just the
  18. plain names.
  19. * LIBDIRS - directories that should be searched for libraries
  20. Also just put the plain paths into this variable
  21. * EXTLIBDIRS - Same as LIBDIRS, but paths in this variable are
  22. also added to the binary via the -R-flag so that
  23. dynamic libraries in non-standard places can be found.
  24. * RESULTDEPS - Targets on which results (executables or libraries)
  25. should additionally depend.
  26. * PACKS - adds packages under control of findlib.
  27. * PREDS - specifies findlib-predicates.
  28. * LIBS - OCaml-libraries that should be linked (just plain names).
  29. E.g. if you want to link the Str-library, just write
  30. str (without quotes). The new OCaml-compiler handles
  31. libraries in such a way that they "remember" whether
  32. they have to be linked against a C-library and it gets
  33. linked in automatically. If there is a slash in the
  34. library name (such as ./str or lib/foo) then make is
  35. told that the generated files depend on the library.
  36. This helps to ensure that changes to your libraries
  37. are taken into account, which is important if you are
  38. regenerating your libraries frequently.
  39. * CLIBS - C-libraries that should be linked (just plain names).
  40. * PRE_TARGETS - set this to a list of target files that you want
  41. to have built before dependency calculation actually
  42. takes place. E.g. use this to automatically compile
  43. modules needed by camlp4, which have to be available
  44. before other modules can be parsed at all.
  45. ** WARNING **: the files mentioned in this variable
  46. will be removed when make clean is executed!
  47. * LIBINSTALL_FILES - the files of a library that should be installed
  48. using findlib. Default:
  49. $(RESULT).mli $(RESULT).cmi $(RESULT).cma
  50. $(RESULT).cmxa $(RESULT).a lib$(RESULT).a
  51. * OCAML_LIB_INSTALL - target directory for rawinstall/rawuninstall.
  52. (default: $(OCAMLLIBPATH)/contrib)
  53. * DOC_FILES - names of files from which documentation is generated.
  54. (default: all .mli-files in your $(SOURCES)).
  55. * DOC_DIR - name of directory where documentation should be stored.
  56. * OCAMLFLAGS - flags passed to the compilers
  57. * OCAMLBCFLAGS - flags passed to the byte code compiler only
  58. * OCAMLNCFLAGS - flags passed to the native code compiler only
  59. * OCAMLLDFLAGS - flags passed to the OCaml-linker
  60. * OCAMLBLDFLAGS - flags passed to the OCaml-linker when linking byte code
  61. * OCAMLNLDFLAGS - flags passed to the OCaml-linker when linking
  62. native code
  63. * OCAMLMKLIB_FLAGS - flags passed to the OCaml library tool
  64. * OCAMLCPFLAGS - profiling flags passed to ocamlcp (default: a)
  65. * PPFLAGS - additional flags passed to the preprocessor
  66. (default: none)
  67. * LFLAGS - flags passed to ocamllex
  68. * YFLAGS - flags passed to ocamlyacc
  69. * IDLFLAGS - flags passed to camlidl
  70. * OCAMLDOCFLAGS - flags passed to ocamldoc
  71. * OCAMLFIND_INSTFLAGS - flags passed to ocamlfind during installation
  72. (default: none)
  73. * DVIPSFLAGS - flags passed to dvips
  74. (when generating documentation in PostScript).
  75. * STATIC - set this variable if you want to force creation
  76. of static libraries
  77. * CC - the C-compiler to be used
  78. * CXX - the C++-compiler to be used
  79. * CFLAGS - additional flags passed to the C-compiler.
  80. The flag -DNATIVE_CODE will be passed automatically if
  81. you choose to build native code. This allows you to
  82. compile your C-files conditionally. But please note:
  83. You should do a make clean or remove the object files
  84. manually or touch the %.c-files: otherwise, they may
  85. not be correctly recompiled between different builds.
  86. * CXXFLAGS - additional flags passed to the C++-compiler.
  87. * CPPFLAGS - additional flags passed to the C-preprocessor.
  88. * CFRAMEWORKS - Objective-C framework to pass to linker on MacOS X.
  89. * LDFLAGS - additional flags passed to the C-linker
  90. * RPATH_FLAG - flag passed through to the C-linker to set a path for
  91. dynamic libraries. May need to be set by user on
  92. exotic platforms. (default: -R).
  93. * ELF_RPATH_FLAG - this flag is used to set the rpath on ELF-platforms.
  94. (default: -R)
  95. * ELF_RPATH - if this flag is yes, then the RPATH_FLAG will be
  96. passed by -Wl to the linker as normal on ELF-platforms.
  97. * OCAMLLIBPATH - path to the OCaml-standard-libraries
  98. (first default: $(OCAMLC) -where)
  99. (second default: /usr/local/lib/ocaml)
  100. * OCAML_DEFAULT_DIRS - additional path in which the user can supply
  101. default directories to his own collection
  102. of libraries. The idea is to pass this as an
  103. environment variable so that the Makefiles do not
  104. have to contain this path all the time.
  105. * OCAMLFIND - ocamlfind from findlib (default: ocamlfind)
  106. * OCAML - OCaml interpreter (default: ocaml)
  107. * OCAMLC - byte-code compiler (default: ocamlc)
  108. * OCAMLOPT - native-code compiler (default: ocamlopt)
  109. * OCAMLMKTOP - top-level compiler (default: ocamlmktop)
  110. * OCAMLCP - profiling byte-code compiler (default: ocamlcp)
  111. * OCAMLDEP - dependency generator (default: ocamldep)
  112. * OCAMLLEX - scanner generator (default: ocamllex)
  113. Applies to .mll files.
  114. * OCAMLYACC - parser generator (default: ocamlyacc)
  115. Applies to .mly files. A good alternative to the default is
  116. "menhir" if installed.
  117. * OCAMLMKLIB - tool to create libraries (default: ocamlmklib)
  118. * CAMLIDL - IDL-code generator (default: camlidl)
  119. * CAMLIDLDLL - IDL-utility (default: camlidldll)
  120. * CAMLP4 - camlp4 preprocessor (default: camlp4)
  121. * OCAMLDOC - OCamldoc-command (default: ocamldoc)
  122. * LATEX - Latex-processor (default: latex)
  123. * DVIPS - dvips-command (default: dvips)
  124. * PS2PDF - PostScript-to-PDF converter (default: ps2pdf)
  125. * CAMELEON_REPORT - report tool of Cameleon (default: report)
  126. * CAMELEON_REPORT_FLAGS - flags for the report tool of Cameleon
  127. * CAMELEON_ZOGGY - zoggy tool of Cameleon
  128. (default: camlp4o pa_zog.cma pr_o.cmo)
  129. * CAMELEON_ZOGGY_FLAGS - flags for the zoggy tool of Cameleon
  130. * OCAML_GLADECC - Glade compiler for OCaml (default: lablgladecc2)
  131. * OCAML_GLADECC_FLAGS - flags for the Glade compiler
  132. * OXRIDL - OXRIDL-generator (default: oxridl)
  133. * NOIDLHEADER - set to yes to prohibit OCamlMakefile from using
  134. the default camlidl-flag -header.
  135. * NO_CUSTOM - Prevent linking in custom mode.
  136. * QUIET - unsetting this variable (e.g. make QUIET=)
  137. will print all executed commands, including intermediate
  138. ones. This allows more comfortable debugging when
  139. things go wrong during a build.
  140. * REALLY_QUIET - when set this flag turns off output from some commands.
  141. * OCAMLMAKEFILE - location of (= path to) this OCamlMakefile.
  142. Because it calls itself recursively, it has to know
  143. where it is. (default: OCamlMakefile = local directory)
  144. * BCSUFFIX - Suffix for all byte-code files. E.g.:
  145. RESULT = foo
  146. BCSUFFIX = _bc
  147. This will produce byte-code executables/libraries with
  148. basename foo_bc.
  149. * NCSUFFIX - Similar to BCSUFFIX, but for native-code files.
  150. * TOPSUFFIX - Suffix added to toplevel interpreters (default: .top)
  151. * SUBPROJS - variable containing the names of subprojects to be
  152. compiled.
  153. * SUBTARGET - target to be built for all projects in variable
  154. SUBPROJS.

Optional variables for Windows users

  1. * MINGW - variable to detect the MINGW-environment
  2. * MSVC - variable to detect the MSVC-compiler

Contact Information and Contributing

Please submit bugs reports, feature requests, contributions and similar to
the GitHub issue tracker.

Up-to-date information is available at: https://mmottl.github.io/ocaml-makefile