11

I am trying to create a library that I can use in other OCaml projects, and I'm totally lost.

I'm currently using ocamlbuild which is great for spitting out executables, but I don't know how to get a library out of it.

I've discovered the -a option in ocamlopt and ocamlc but I'm not really sure how to use it. The documentation I've found (for example, here), seems to assume some preexisting knowledge. I don't even know what a .a file is. After I run that, which of the outputted files do I need to build a project that depends on this library? Do I need the mli files so that the application knows the signatures of the library code, or is that included in the output somehow? Also, it would be nice to be able to package all the files together, something similar to a .jar file for Java.

In any case, I would love for ocamlbuild to do all of this for me, since if I have to invoke ocamlopt -a I will have to either manually specify dependencies or hack a script around ocamldep -- something that ocamlbuild was supposed to fix. However, I don't know how to tell it to build a library.

I'm willing to use oasis or OPAM or something if it's necessary, but I would like to learn how to do this using just the basic tools first.

Nat Mote
  • 4,068
  • 18
  • 30
  • 2
    Try making a file with extension `.mllib`, say `libname.mllib` containing the list of all the modules you'd like to put in your library, and then do `ocamlbuild libname.cma` to get your library compiled. – didierc May 29 '14 at 15:22

2 Answers2

4

OCamlbuild has some built-in functionality for building libraries, so you can get started with just ocamlbuild foo.cma foo.cmxa (assuming foo.ml is your entry point). This will invoke ocamlopt -a and ocamlc -a for you, handling all the dependency plumbing and leaving the generated files inside _build.

That should be enough to let you compile a library and link it from another program. Since this is just a test you can simply point at the aforementioned _build with -I when compiling the program that uses the library. For real use a library should be packaged - when you get to that point you'll want to look into ocamlfind, oasis, etc.

Have a look at the ocaml.org tutorial on compiling OCaml projects. Additionally the official manual for the bytecode and native code compilers contains useful detail on producing and using the various types of files.

gsg
  • 9,167
  • 1
  • 21
  • 23
  • 1
    When I try to run ```ocamlbuild util.cmxa```, it errors out: ```+ /usr/bin/ocamlopt.opt -a unix.cmxa str.cmxa src/simple_set.cmx src/util.cmx -o src/util.cmxa``` ```Option -a cannot be used with .cmxa input files.``` – Nat Mote May 30 '14 at 20:28
  • I get the same thing as @NatMote above. `opam show ocamlbuild` says I'm using 0.14.0. – solstice333 Feb 03 '20 at 06:29
  • If you get `Option -a cannot be used with .cmxa input files`, the workaround seems to add the `-use-ocamlfind` option. Alternatively, you can create an ocamlbuild plugin and set the `Options.use_ocamlfind` bool ref to `true` on the `Before_options` hook. See https://github.com/ocaml/ocamlbuild/blob/master/manual/manual.adoc#17-findlib-based-packages for more information – solstice333 Feb 04 '20 at 12:25
0

The documentation for ocamlbuild archives seems to cover this pretty well.

In any case, here's one way to do ocaml libraries. Let's say you have a directory called foo containing your .ml, .mli, and .mllib files. Let's say it contained bar.ml, bar.mli, baz.ml, and baz.mli. To distribute all this as one library, you'd also have a foo.mllib in that directory, whose contents are

Bar
Baz

Then to compile, do

$ ocamlbuild -use-ocamlfind foo.cma foo.cmxa

Here is an example.

Then to use your library foo, let's say you had a sibling directory called main, and main contains main.ml, _tags, myocamlbuild.ml.

myocamlbuild.ml should have the following contents:

open Ocamlbuild_plugin
open Command

let () =
   dispatch (
      function
      | After_rules ->
         ocaml_lib 
            ~extern:true 
            ~dir:"/path/to/foo/_build" 
            "foo"
      | _ -> ()
   )

_tags should have the following contents:

<main.{ml,native,byte}>: use_foo

Compile main.ml with

$ ocamlbuild -use-ocamlfind main.byte main.native

run with

$ ./main.byte
$ ./main.native

More information here as well: https://ocaml.org/learn/tutorials/ocamlbuild/Using_an_external_library.html

solstice333
  • 3,399
  • 1
  • 31
  • 28