Making ocamlbuild pass both .ml and .mli files to ocamldoc

ocaml, ocamlbuild, ocamldoc

Solution

As I needed to hack something to do a similar stuff, maybe it'll help if I post it here as answer (at least until OCamlbuild features that). So, here is the relevant part of my `myocamlbuild.ml`:

open Ocamlbuild_plugin;;

dispatch begin function
  | After_rules ->
     (* Using both .ml and .mli files to build documentation: *)
     rule "ocaml: ml & mli -> odoc"
       ~insert:`top
       ~tags:["ocaml"; "doc"; "doc_use_interf_n_implem"]
       ~prod:"%.odoc"
       (* "%.cmo" so that cmis of ml dependencies are already built: *)
       ~deps:["%.ml"; "%.mli"; "%.cmo"]
       begin fun env build ->
         let mli = env "%.mli" and ml = env "%.ml" and odoc = env "%.odoc" in
         let tags =
           (Tags.union (tags_of_pathname mli) (tags_of_pathname ml))
           ++"doc_use_interf_n_implem"++"ocaml"++"doc" in
         let include_dirs = Pathname.include_dirs_of (Pathname.dirname ml) in
         let include_flags =
           List.fold_right (fun p acc -> A"-I" :: A p :: acc) include_dirs [] in
         Cmd (S [!Options.ocamldoc; A"-dump"; Px odoc;
                 T (tags++"doc"++"pp"); S (include_flags);
                 A"-intf"; P mli; A"-impl"; P ml])
       end;

    (* Specifying merge options with tags: *)
    pflag ["ocaml"; "doc"; "doc_use_interf_n_implem"] "merge"
      (fun s -> S[A"-m"; A s]);
end

Then adding the tag `doc_use_interf_n_implem` to `.ml` and/or `.mli` files for which the documentation should be generated from both implementation and interface should do the trick.

With the code above, adding merging options can also be done by adding tags like for instance `merge(A)` (to merge all).

Note this is a hack that may break stuffs in complex projects. Notably, I did not test it with `camlp[45]`-processed files, nor with OCamlbuild versions other that 4.00.1.

Problem

I want to include source code in my generated docs. This works when I invoke `ocamldoc` on the command-line like this: `ocamldoc -I _build -html -keep-code -colorize-code *.{ml,mli} -d .docdir`. However, I'm having troubles integrating this with `ocamlbuild`. I'm using the following code in `myocamlbuild.ml`: ``` open Ocamlbuild_plugin;; dispatch begin function | After_options -> Options.ocamldoc := S[A"ocamldoc"; A"-keep-code"; A"-colorize-code"] | _ -> () end ``` But this only includes the source for files with no corresponding interface file - contrary to what is said here, it looks like `ocamlbuild` refuses to pass `.ml` files to `ocamldoc` when there is an `.mli` file present. Is there a way to coax ocamlbuild into doing what I want?

Original source