OCAML.M4(1)

πŸ’… ocaml.m4(1) β€” the girl's guide to autoconf macros

okay bestie, so like, this is ocaml.m4 from section 1 of the manual (that's the "1" in OCAML.M4(1) β€” command-line tools, iykyk), and it's literally about Autoconf macros for OCaml. Buckle up, it's gonna be a cute little ride through configure.ac land πŸŽ€

✨ NAME ✨

ocaml.m4 β€” Autoconf macros for OCaml, no cap πŸ¦‹

πŸ“‹ SUMMARY πŸ“‹

here's the whole squad, all together:

AC_PROG_OCAML
AC_PROG_FINDLIB
AC_PROG_OCAMLLEX
AC_PROG_OCAMLYACC
AC_PROG_CAMLP4
AC_CHECK_OCAML_PKG([name])
AC_CHECK_OCAML_MODULE(VARIABLE,NAME,MODULE,INCLUDE-PATHS)
AC_CHECK_OCAML_WORD_SIZE

πŸ’– DESCRIPTION πŸ’–

ocaml.m4 is a file containing standard, useful autoconf macros for detecting the OCaml, findlib, OCaml packages, and so on in your autoconf-generated ./configure scripts. it's giving very much "the helpful friend of your build system" energy 🌸

so to begin using these macros, you will need to copy the ocaml.m4 file (usually located at /usr/share/aclocal/ocaml.m4) to the autoconf macros directory in your project. Normally this is the m4/ directory in your project, but the directory can be changed using the AC_CONFIG_MACRO_DIR(DIR) directive. And if you have just created the m4/ directory, then you may also need to do:

aclocal -I m4

Then ✨ you can add any of the macros described below to your configure.ac (or configure.in). Almost every OCaml project should use AC_PROG_OCAML first and probably AC_PROG_FINDLIB right after it β€” like, they're a package deal, they come as a set 🫢

heads up boo: this manual page does not describe how to use autoconf. for that you should read the detailed autoconf info file (info autoconf). consider this page the OCaml-specific sequel, not the whole trilogy 😭

πŸ” AC_PROG_OCAML πŸ”

This macro detects which tools of the usual OCaml toolchain are available. It defines and substitutes the following variables:

OCAMLC          set to the name of the bytecode compiler
                  (eg. "ocamlc" or "ocamlc.opt"), or "no" if
                  no OCaml installation was found
OCAMLOPT        the name of the native-code compiler, eg. "ocamlopt",
                  "ocamlopt.opt" or "no"
OCAMLBEST       "byte" (if only the bytecode compiler is available)
                  or "opt" (if both bytecode and native code compilers
                  are available)
OCAMLDEP        the name of the dependency resolver, eg. "ocamldep"
OCAMLMKTOP      the name of ocamlmktop
OCAMLMKLIB      the name of ocamlmklib
OCAMLDOC        the name of ocamldoc
OCAMLBUILD      the name of ocamlbuild
OCAMLLIB        the OCaml library path (eg. /usr/lib/ocaml/)
OCAMLVERSION    the compiler version (eg. 3.11.0)

🌈 Detecting if OCaml is installed 🌈

unlike old versions of these macros, AC_PROG_OCAML does not exit if no OCaml installation is detected. so if you want to detect if OCaml is installed you have to do something like this:

AC_PROG_OCAML
if test "$OCAMLC" = "no"; then
  AC_MSG_ERROR([You must install the OCaml compiler])
fi

This behaviour and usage pattern are consistent with other macros of the AC_PROG_* family. (yes, the original really does have a stray ) in that sentence β€” iconic typo, we respect it πŸ’…)

🧚 Cross-compiling 🧚

If the configure script is invoked for cross-compiling then AC_PROG_OCAML will detect the cross-compiler versions of the OCaml compiler, eg. OCAMLC=i686-pc-mingw32-ocamlc etc. This happens automatically, and for most purposes you don't need to worry about it β€” it just works, bestie, don't stress 😌


πŸ”Ž AC_PROG_FINDLIB πŸ”Ž

This macro checks for the presence of the ocamlfind program (part of findlib). It defines and substitutes OCAMLFIND to the name of the ocamlfind program, or no if not found.

lowkey important: this macro does not fail if ocamlfind is not found. if you want to force the user to install findlib, you should do:
AC_PROG_FINDLIB
if test "$OCAMLFIND" = "no"; then
  AC_MSG_ERROR([You must install OCaml findlib (the ocamlfind command)])
fi

See also AC_CHECK_OCAML_PKG β€” they're literally besties πŸ‘‘


🧡 AC_PROG_OCAMLLEX 🧡

This checks for the ocamllex program and sets OCAMLLEX to the name of the program (eg. ocamllex or ocamllex.opt), or no if not found. lexing queen behaviour ✨

πŸ‰ AC_PROG_OCAMLYACC πŸ‰

This checks for the ocamlyacc program and sets OCAMLYACC to the name of the program, or no if not found.

πŸ¦‹ AC_PROG_CAMLP4 πŸ¦‹

This checks for camlp4, and checks that the version matches the compiler version found previously. It sets CAMLP4 to the name of the basic camlp4 program, or no if not found.

The macro also checks for other tools of the camlp4 suite like camlp4o, camlp4orf, etc. For each of them, a fully capitalized variable is set to the tool name (or no if not found); all variables are substituted for when filling .in files. The full list of tools and respective variable names is as follows β€” yes, it's a whole friend group:

camlp4        CAMLP4
camlp4boot    CAMLP4BOOT
camlp4o       CAMLP4O
camlp4of      CAMLP4OF
camlp4oof     CAMLP4OOF
camlp4orf     CAMLP4ORF
camlp4prof    CAMLP4PROF
camlp4r       CAMLP4R
camlp4rf      CAMLP4RF

πŸ“¦ AC_CHECK_OCAML_PKG πŸ“¦

This is the main macro that can be used to detect the presence of OCaml findlib packages. This macro uses ocamlfind to look up findlib packages (and thus requires that findlib itself has been installed, and that the package has been properly packaged with a META file etc.). If you want to find an OCaml findlib package which hasn't been installed with findlib then you should try using AC_CHECK_OCAML_MODULE instead. different tool, different vibe πŸ”₯

AC_CHECK_OCAML_PKG([name])

checks for an OCaml findlib package with the given name. If found, it defines and substitutes the variable OCAML_PKG_name where the name part is substituted for the package name by replacing all dashes with underscores.

For example,

AC_CHECK_OCAML_PKG([xml-light])

will set OCAML_PKG_xml_light to either xml-light or no. dashes β†’ underscores, that's the whole trick πŸŽ€

To have the configure script fail if a package is not installed, do:

AC_CHECK_OCAML_PKG([foo])
if test "$OCAML_PKG_foo" = "no"; then
  AC_MSG_ERROR([Please install OCaml findlib module 'foo'.])
fi

In your Makefile.in, use the substitution variable in conjunction with ocamlfind, eg:

.ml.cmo:
  $(OCAMLFIND) ocamlc -package @OCAML_PKG_foo@ -c $< -o $@

Note that also in the substitution variable dashes are replaced with underscores. consistency is key, periodt πŸ’…

🎁 Checking for alternative findlib package names 🎁

In the (unlikely) case where the same library corresponds to different findlib package names on different systems, you can improve portability by checking for the alternative names passing a second argument to AC_CHECK_OCAML_PKG:

AC_CHECK_OCAML_PKG(PKGNAME,ALTERNATIVE-NAMES)

The behaviour is the same as before if PKGNAME is found. Otherwise all names in ALTERNATIVE-NAMES are tested in turn as findlib package names. If one is found, it is set as the value set by the macro and substituted in .in files; otherwise no is set.

careful bestie: the variable name is determined by PKGNAME, while the value depends on the actual alternative name found. name β‰  value here, they're doing their own thing πŸ™ˆ

For example, to detect the camlzip findlib package, either called zip or camlzip, and to store the found value in the OCAML_PKG_zip variable you can do in your configure.ac:

AC_CHECK_OCAML_PKG(zip,camlzip)

and have a portable Makefile.in build line such as:

.ml.cmo:
  $(OCAMLFIND) ocamlc -package @OCAML_PKG_zip@ -c $< -o $@

🧐 AC_CHECK_OCAML_MODULE(VARIABLE,NAME,MODULE,INCLUDE-PATHS) 🧐

AC_CHECK_OCAML_MODULE is the hairier alternative to AC_CHECK_OCAML_PKG. You should always use AC_CHECK_OCAML_PKG and ocamlfind/findlib if possible. like, always, bestie β€” this one's the backup plan 😭

The parameters are:

  • VARIABLE β€” This is the environment variable that is set. It will either be set to the include path, or to no if the module was not found.
  • NAME β€” This is the name of the module we are looking for. This parameter is just used for printing messages, and does not affect how the module is found. purely cosmetic, a little decoration ✨
  • MODULE β€” This should be an OCaml module name, representing the module name being looked up. You can put sub-modules here, eg. CalendarLib.Date
  • INCLUDE-PATHS β€” This is the default list of include directories to search, eg. +calendar

For example, the following code will check for the OCaml Calendar module, and will distinguish between version 1 and version 2 of this module (which have incompatible APIs):

AC_CHECK_OCAML_PKG(calendar)
AC_CHECK_OCAML_MODULE(is_calendar2,calendar,[CalendarLib.Date],[+calendar])

After the above code has run, variables OCAML_PKG_calendar and is_calendar2 will be set as follows:

OCAML_PKG_calendar  is_calendar2  Result

yes                 +calendar     Calendar v2 is installed
yes                 no            Calendar v1 is installed
no                  no            No Calendar module installed

so yeah, the include path is the version tell here. iykyk 🌟


πŸ“ AC_CHECK_OCAML_WORD_SIZE πŸ“

This checks the word size of the OCaml compiler, and sets OCAML_WORD_SIZE to either 32 or 64. that's it. two numbers. honestly iconic for how simple it is πŸ’€


πŸ‘€ SEE ALSO πŸ‘€

πŸ“ FILES πŸ“

  • /usr/share/aclocal/ocaml.m4

πŸ‘‘ AUTHORS πŸ‘‘

Various people have contributed to these macros over many years β€” a whole group chat of legends, fr fr:

  • Olivier Andrieu
  • Jean-Christophe Filliatre
  • Richard W.M. Jones
  • Georges Mariano
  • Jim Meyering
  • Stefano Zacchiroli

πŸ“œ LICENSE πŸ“œ

(kept verbatim, because legal text is the one thing we do not remix πŸ’œ)

 Copyright X 2009      Richard W.M. Jones
 Copyright X 2009      Stefano Zacchiroli
 Copyright X 2000-2005 Olivier Andrieu
 Copyright X 2000-2005 Jean-Christophe Filliatre
 Copyright X 2000-2005 Georges Mariano

 All rights reserved.

 Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.
 * The names of the contributors may not be used to endorse or promote
 products derived from this software without specific prior written
 permission.

 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

πŸ› REPORTING BUGS πŸ›

Please report bugs to the authors at the project page: <http://forge.ocamlcore.org/projects/ocaml-autoconf/>, using the forge bug tracker <http://forge.ocamlcore.org/tracker/?group_id=69>. they're lovely, go tell them, don't suffer in silence bestie 🫢


and that's the whole page!! 🌈

this lil' cutie is from ocaml-autoconf-1.0, dated 2022-01-25 β€” yes, older than your favourite TikTok sound, but she still slays πŸ’– go forth and ./configure βœ¨πŸŽ€

πŸ“¦ where this page comes from