Executables Last updated May 4, 2022

$ ocamlopt -o program module1.ml module2.ml

OBazl does not support this method of building executables directly from source files; instead, it requires that each module be built separately. By default, OBazl rules use the optimized native toolchain (i.e. ocamlopt.opt); this is controlled by build setting rules, which can be modified on the Bazel command line (not shown here).

BUILD.bazel
load(
    "@rules_ocaml//build:rules.bzl",
    "ocaml_executable",
    "ocaml_module",
)
ocaml_executable(
    name = "program",
    deps = [":Module1", ":Module2"]
)
ocaml_module(
    name   = "Module1",
    struct = "module1.ml"
)
ocaml_module(
    name   = "Module2",
    struct = "module2.ml"
)

OCaml does not define a "main" entry point for exectables. When an Ocaml executable is run, the top-level definitions in each module will be evaluated, in link order. This is very flexible, but it introduces the risk of successful but incorrect builds. This can happen if modules are listed in the wrong order, or if a module is omitted. As a convenience, OBazl defines a 'main' attribute that the developer can use to indicate which module should be come last in linking order. Finalization routines to run after the main routine has executed can be expressed by putting them in separate modules that depend on the main module. OBazl will automatically link the modules in the correct order.

With an external dep:

$ ocamlopt -o program unix.cmxa module1.ml module2.ml

BUILD.bazel
load(
    "@rules_ocaml//ocaml:rules.bzl",
    "ocaml_executable",
    "ocaml_module",
)
ocaml_executable(
    name = "program",
    main = ":Module2",
    deps = [":Module1"]
)
ocaml_module(
    name   = "Module1",
    struct = "module1.ml"
    deps = ["@ocaml//unix"]
)
ocaml_module(
    name   = "Module2",
    struct = "module2.ml"
)

Real-World OCaml, first example. Uses Dune, assumes opam libs base and stdlib have been installed:

opam install base utop
opam install core async yojson core_extended \
     core_bench cohttp-async async_graphics \
     cryptokit menhir
dune
(executable
 (name      sum)
 (libraries base stdio))

OBazl:

BUILD.bazel
load(
    "@rules_ocaml//ocaml:rules.bzl",
    "ocaml_executable",
    "ocaml_module",
)

ocaml_executable(
    name = "sum",
    main = ":Sum",
)

ocaml_module(
    name   = "Sum",
    struct = "sum.ml",
    deps = [
        "@base//:base"
        "@stdio//:stdio"
    ],
)