Skip to content

Commit

Permalink
Fix "A plugin example for compiling LaTeX"
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris00 committed Jul 11, 2015
1 parent cf1d14a commit acaf036
Showing 1 changed file with 117 additions and 116 deletions.
233 changes: 117 additions & 116 deletions site/learn/tutorials/ocamlbuild/A_plugin_example_for_compiling_LaTeX.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,132 +2,133 @@

# A plugin example for compiling LaTeX
Besides the example below, another plugin for LaTeX can be found
[here](http://darcs.ocamlcore.org/ocamlunix/myocamlbuild.ml) it handles
pdfLaTeX, MakeIndex, HeVeA \(both monolithic html and html by chapter via
HaChA\) and Pgf/TikZ picture extraction to PNG for the html versions.
[here](https://github.com/ocaml/ocamlunix/blob/master/myocamlbuild.ml#L14)
it handles
pdfLaTeX, MakeIndex, HeVeA (both monolithic html and html by chapter via
HaChA) and Pgf/TikZ picture extraction to PNG for the html versions.
However as the plugin below it assumes that LaTeX will converge in two
iterations for the PDF and the master tex file chapter dependencies must
be explicitly stated.

See the example below using beautiful syntax highlighting
[here](http://gallium.inria.fr/~pouillar/ocamlbuild/plugin_example.html).

```ocaml
open Ocamlbuild_plugin
open Command
let pdflatex = ref (A"pdflatex")
let ocamlweb = ref (A"ocamlweb")
let () =
dispatch begin function
(* Here one can change the default value of options, they can still
be updated by a command line option. *)
| Before_options ->
(* This will put all warnings to \texttt{ocaml\{c,opt\}} by default. *)
Options.ocaml_cflags := ["-w";"A"]
(* Here one can change the final value of options. *)
| After_options ->
(* This avoids the creation of symbolic links to the build directory. *)
Options.make_links := false
(* This hook is called before the hygiene phase.
This phase also serve as collecting all the information about the
source tree. *)
| Before_hygiene ->
(* Here you can dynamically tag some files or directories. *)
(* This is done here by checking the [SOME_COND] variable which is
impossible in the \tags file. *)
if getenv "SOME_COND" ~default:"false" = "true" then
(* By setting foo_dir as not_hygienic one say that the foo directory
can contains non hygienic files (such as \texttt{.cmi},
\texttt{.cmo}\ldots). *)
tag_file "foo_dir" ["not_hygienic"]
(* One can also do things after the hygiene step. *)
| After_hygiene -> ()
(* One can setup rules before the standard ones but that's not recommended. *)
| Before_rules -> ()
(* Here one can add or override new rules *)
| After_rules ->
(* Rules can be declared by a call of the form
[rule name ~prod ~dep action].
The first argument is the name of the rule.
[~prod:string] specifies the product of the rule.
Note that [~prods:string list] also exists.
[~dep] and [~deps] are for dependencies *)
rule "LaTeX to PDF conversion rule"
~prod:"%.pdf"
~dep:"%.tex"
begin fun env _build ->
(* The action is a function that receive two arguments:
[env] is a conversion function that substitutes `%'
occurrences according to the targets to which the rule
applies. [_build] can be called to build new things
(dynamic dependencies). *)
let tex = env "%.tex" and _pdf = env "%.pdf" in
(* Here we say: ``We compile the file tex form LaTeX to
PDF''. Note that in fact that is a set of tags, thus
the order does not matter. But you got the idea. *)
let tags = tags_of_pathname tex++"compile"++"LaTeX"++"pdf" in
(* Here we produce the command to run.
[S] is for giving a sequence of command pieces.
[A] is for atoms.
[P] is for pathnames.
[Px] is a special pathname that should be the main product
of the rule (for display purposes).
[T] is for tags.
The other constructors are given in the documentation of the
[Command] module in [Signatures.COMMAND]. *)
let cmd = Cmd(S[!pdflatex; T tags; P tex; Sh"< /dev/null"]) in
(* Hoping that LaTeX will converge in two iterations *)
Seq[cmd; cmd]
end;
(* Here we make an extension of any rule that produces a command
containing these tags. *)
flag ["compile"; "LaTeX"; "pdf"; "safe"] (A"-halt-on-error");
(* Here we give an exception: the file ``manual.tex'' is tagged
``safe''. With this tag we add the -halt-on-error flag during
the LaTeX compilation. *)
tag_file "manual.tex" ["safe"];
(* The generic LaTeX rule could look at the file searching for
some \verb'\input{}' command, but LaTeX is so complex that it
will be hard to make this solution complete. Here we manually
inject some dependencies at one particular point. *)
(* The [dep] function takes tags and pathnames. This will build
pathnames if a command contains these tags. Note that every
file [some_file_name] is tagged [file:some_file_name]. *)
dep ["compile"; "LaTeX"; "pdf"; "file:manual.tex"]
["ocamlweb.sty"; "myocamlbuild.tex"];
rule "OCaml to LaTeX conversion rule (using ocamlweb)"
~prod:"%.tex"
~dep:"%.ml"
begin fun env _build ->
let tex = env "%.tex" and ml = env "%.ml" in
let tags = tags_of_pathname ml++"ocamlweb"++"LaTeX" in
Cmd(S[!ocamlweb; T tags; P ml; A"-o"; Px tex])
end;
end
```
open Ocamlbuild_plugin;;
open Command;;

let pdflatex = ref (A"pdflatex");;
let ocamlweb = ref (A"ocamlweb");;
dispatch begin function
(*c Here one can change the default value of options, they can still be updated by a command line option. *)
| Before_options ->
(*c This will put all warnings to \texttt{ocaml\{c,opt\}} by default. *)
Options.ocaml_cflags := ["-w";"A"]
(*c Here one can change the final value of options. *)
| After_options ->
(*c This avoids the creation of symbolic links to the build directory. *)
Options.make_links := false
(*c This hook is called before the hygiene phase.
This phase also serve as collecting all the information about the
source tree. *)
| Before_hygiene ->
(*c Here you can dynamically tag some files or directories. *)
(*c This is done here by checking the [SOME_COND] variable which is
impossible in the \tags file. *)
if getenv "SOME_COND" ~default:"false" = "true" then
(*c By setting foo\_dir as not\_hygienic one say that the foo directory
can contains non hygienic files (such as \texttt{.cmi}, \texttt{.cmo}\ldots). *)
tag_file "foo_dir" ["not_hygienic"]
(*c One can also do things after the hygiene step. *)
| After_hygiene -> ()
(*c One can setup rules before the standard ones but that's not recommended. *)
| Before_rules -> ()
(*c Here one can add or override new rules *)
| After_rules ->
(*c Rules can be declared by a call of the form
[rule name ~prod ~dep action].
The first argument is the name of the rule.
[~prod:string] specifies the product of the rule.
Note that [~prods:string list] also exists.
[~dep] and [~deps] are for dependencies *)
rule "LaTeX to PDF conversion rule"
~prod:"%.pdf"
~dep:"%.tex"
begin fun env _build ->
(*c The action is a function that receive two arguments:
[env] is a conversion function that substitutes `\%' occurrences
according to the targets to which the rule applies.
[_build] can be called to build new things (dynamic dependencies). *)
let tex = env "%.tex" and _pdf = env "%.pdf" in
(*c Here we say: ``We compile the file tex form \LaTeX\xspace to PDF''.
Note that in fact that is a set of tags, thus the order does not
matter. But you got the idea. *)
let tags = tags_of_pathname tex++"compile"++"LaTeX"++"pdf" in
(*c Here we produce the command to run.
[S] is for giving a sequence of command pieces.
[A] is for atoms.
[P] is for pathnames.
[Px] is a special pathname that should be the main product of the
rule (for display purposes).
[T] is for tags.
The other constructors are given in the documentation of the
[Command] module in [Signatures.COMMAND]. *)
let cmd = Cmd(S[!pdflatex; T tags; P tex; Sh"< /dev/null"]) in
(*c Hoping that \LaTeX will converge in two iterations *)
Seq[cmd; cmd]
end;
(*c Here we make an extension of any rule that produces a command
containing these tags. *)
flag ["compile"; "LaTeX"; "pdf"; "safe"] (A"-halt-on-error");
(*c Here we give an exception: the file ``manual.tex'' is tagged ``safe''.\ocweol
With this tag we add the -halt-on-error flag during the \LaTeX
compilation. *)
tag_file "manual.tex" ["safe"];
(*c The generic \LaTeX rule could look at the file searching for some
\verb'\input{}' command, but \LaTeX is so complex that it will
be hard to make this solution complete.
Here we manually inject some dependencies at one particular point. *)
(*c The [dep] function takes tags and pathnames. This will build pathnames
if a command contains these tags. Note that every file [some_file_name] is
tagged [file:some_file_name]. *)
dep ["compile"; "LaTeX"; "pdf"; "file:manual.tex"]
["ocamlweb.sty"; "myocamlbuild.tex"];
rule "OCaml to LaTeX conversion rule (using ocamlweb)"
~prod:"%.tex"
~dep:"%.ml"
begin fun env _build ->
let tex = env "%.tex" and ml = env "%.ml" in
let tags = tags_of_pathname ml++"ocamlweb"++"LaTeX" in
Cmd(S[!ocamlweb; T tags; P ml; A"-o"; Px tex])
end;
end;;
```
## Notes


- The \(relative and absolute\) dependencies of a tex file can be found
by running latex with -recorder and parse the resulting .fls file.
- The (relative and absolute) dependencies of a tex file can be found
by running latex with `-recorder` and parse the resulting `.fls` file.
Unfortunately as this does execute the tex code this takes too much
time to sort out the deps.

0 comments on commit acaf036

Please sign in to comment.