From acaf036ab7eda1ddf40ee209ce902a7d18cb27ec Mon Sep 17 00:00:00 2001 From: Christophe Troestler Date: Sat, 11 Jul 2015 12:29:51 +0200 Subject: [PATCH] Fix "A plugin example for compiling LaTeX" --- .../A_plugin_example_for_compiling_LaTeX.md | 233 +++++++++--------- 1 file changed, 117 insertions(+), 116 deletions(-) diff --git a/site/learn/tutorials/ocamlbuild/A_plugin_example_for_compiling_LaTeX.md b/site/learn/tutorials/ocamlbuild/A_plugin_example_for_compiling_LaTeX.md index 58c6daff6..d3471c5ce 100644 --- a/site/learn/tutorials/ocamlbuild/A_plugin_example_for_compiling_LaTeX.md +++ b/site/learn/tutorials/ocamlbuild/A_plugin_example_for_compiling_LaTeX.md @@ -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.