ocamlc is strictly a compiler. If you’re familiar with C, it’s equivalent to something like gcc.
What that means is that if I write a C program which requires me to look up header files or link against libraries in non-standard locations, I need to inform gcc of this (with -I /my/header_dir or -L /my/lib_dir -l my_lib, respectively).
If you’re using a build system such as Dune, it will take of these details for you and invoke tools such as ocamlc with the correct arguments automatically.
It’s still possible to use ocamlc directly in a somewhat automatic fashion using a tool called Findlib.
In your example, the solution is to invoke ocamlc through the ocamlfind program (part of Findlib):
$ ocamlfind ocamlc -package batteries -linkpkg main.ml -o main
The above will use Findlib to query the location of the files installed by the batteries package and pass them to ocamlc.
In answer to your second question, ;; is never (to my best knowledge) required in OCaml source code. It’s only necessary while using the toplevel (ie, the REPL) in order to terminate expressions.
Your example can be written like this:
open Batteries
let () = print_endline (dump [5; 4; 3])
So yes I’m working at top level (this assert is here to perform some quick & dirty test). Hence I understand that working at top level is not an idiomatic ocaml usage, am I right?
By the way, when OCaml people say ‘toplevel’ we mean the REPL (the interactive OCaml console, typically utop). So ;; is required by the REPL because that’s how it distinguishes the end of an input; but it’s not required in source code files.