From 418c90a02d13a2dd05bd604250ff8da889e1ef86 Mon Sep 17 00:00:00 2001 From: Alberto Sartori Date: Tue, 6 Dec 2022 10:52:47 +0100 Subject: add latexmk rule... ...the main improvement wrt to standalone rule is the usage of latexmk, which automatically runs latex the right number of times, and, if needed, can call bibtex as well. Co-authored-by: Oliver Reiche --- README.md | 5 ++ latex/EXPRESSIONS | 211 +++++++++++++++++++++++++++++++++++++++++++ latex/RULES | 261 ++++++++++++++++++++---------------------------------- 3 files changed, 314 insertions(+), 163 deletions(-) create mode 100644 latex/EXPRESSIONS diff --git a/README.md b/README.md index 83c2fae..5e52412 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,11 @@ A collection of rules related to typesetting. a single `eps` file by replacing the definition of `stage` and `drawbb`. While not strictly related to latex, usually used for "animated" diagrams in slides. + - `["latex", "latexmk"]` Simple rule to call `latexmk`, given a + collection of source files and the entry point. The main + difference with respect to `standalone` is given by the usage of + `latexmk` itself, which runs `latex` the needed number of times + eventually calling `bibtex` as well. - Pandoc - `["pandoc", "standalone"]` Generate a single output file from a given list of files in order and a template. diff --git a/latex/EXPRESSIONS b/latex/EXPRESSIONS new file mode 100644 index 0000000..640f587 --- /dev/null +++ b/latex/EXPRESSIONS @@ -0,0 +1,211 @@ +{ "call latex": + { "vars": + [ "srcs" + , "main" + , "deps" + , "stage" + , "env" + , "executable" + , "runner" + , "runner type" + , "opts" + , "output file extension" + ] + , "expression": + { "type": "let*" + , "bindings": + [ [ "stage" + , { "type": "join" + , "separator": "/" + , "$1": {"type": "var", "name": "stage"} + } + ] + , [ "srcs" + , { "type": "disjoint_map_union" + , "msg": "Sources may not conflict" + , "$1": + { "type": "foreach" + , "var": "x" + , "range": {"type": "var", "name": "srcs"} + , "body": + { "type": "map_union" + , "$1": + [ {"type": "DEP_RUNFILES", "dep": {"type": "var", "name": "x"}} + , { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "x"} + } + ] + } + } + } + ] + , [ "main" + , { "type": "assert_non_empty" + , "msg": "Entry-point main cannot be empty" + , "$1": {"type": "join", "$1": {"type": "var", "name": "main"}} + } + ] + , [ "_" + , { "type": "if" + , "cond": + { "type": "==" + , "$1": + { "type": "lookup" + , "map": {"type": "var", "name": "srcs"} + , "key": + { "type": "join" + , "$1": [{"type": "var", "name": "main"}, ".tex"] + } + } + , "$2": null + } + , "then": + { "type": "fail" + , "msg": + [ "main not the base name of a .tex file in srcs" + , "main has value" + , {"type": "var", "name": "main"} + , "srcs have file names" + , {"type": "keys", "$1": {"type": "var", "name": "srcs"}} + ] + } + } + ] + , [ "main" + , { "type": "if" + , "cond": + {"type": "==", "$1": {"type": "var", "name": "stage"}, "$2": ""} + , "then": {"type": "var", "name": "main"} + , "else": + { "type": "join" + , "separator": "/" + , "$1": + [ {"type": "var", "name": "stage"} + , {"type": "var", "name": "main"} + ] + } + } + ] + , [ "srcs" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": {"type": "var", "name": "srcs"} + } + ] + , [ "deps" + , { "type": "disjoint_map_union" + , "msg": "Dependencies may not conflict" + , "$1": + { "type": "foreach" + , "var": "x" + , "range": {"type": "var", "name": "deps"} + , "body": + {"type": "DEP_RUNFILES", "dep": {"type": "var", "name": "x"}} + } + } + ] + , [ "tex inputs" + , { "type": "to_subdir" + , "subdir": "work" + , "$1": + { "type": "disjoint_map_union" + , "msg": "Staging conflict between staged sources and deps" + , "$1": + [ {"type": "var", "name": "deps"} + , {"type": "var", "name": "srcs"} + ] + } + } + ] + , [ "env" + , { "type": "map_union" + , "$1": + [ { "type": "singleton_map" + , "key": "PATH" + , "value": "/bin:/usr/bin:/usr/local/bin" + } + , { "type": "singleton_map" + , "key": "SOURCE_DATE_EPOCH" + , "value": "0" + } + , {"type": "var", "name": "env"} + ] + } + ] + , [ "cmd" + , { "type": "if" + , "cond": + { "type": "==" + , "$1": {"type": "var", "name": "runner type"} + , "$2": "latexmk" + } + , "then": + { "type": "++" + , "$1": + [ ["sh", "runner"] + , [{"type": "var", "name": "executable"}] + , [{"type": "var", "name": "main"}] + , { "type": "if" + , "cond": {"type": "var", "name": "opts"} + , "then": {"type": "var", "name": "opts"} + , "else": ["-pdf"] + } + ] + } + , "else": + [ "./runner" + , {"type": "var", "name": "executable"} + , {"type": "var", "name": "main"} + ] + } + ] + , [ "output file" + , { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "tex inputs"} + , {"type": "var", "name": "runner"} + ] + } + , "outs": + [ { "type": "join" + , "$1": + [ "work/" + , {"type": "var", "name": "main"} + , { "type": "join" + , "separator": "" + , "$1": {"type": "var", "name": "output file extension"} + } + ] + } + ] + , "cmd": {"type": "var", "name": "cmd"} + , "env": {"type": "var", "name": "env"} + } + ] + , [ "output file" + , { "type": "map_union" + , "$1": + { "type": "foreach_map" + , "var_key": "name" + , "var_val": "file" + , "range": {"type": "var", "name": "output file"} + , "body": + { "type": "singleton_map" + , "key": + {"type": "basename", "$1": {"type": "var", "name": "name"}} + , "value": {"type": "var", "name": "file"} + } + } + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "output file"} + , "runfiles": {"type": "var", "name": "output file"} + } + } + } +} diff --git a/latex/RULES b/latex/RULES index 89683a9..ec4c9cd 100644 --- a/latex/RULES +++ b/latex/RULES @@ -20,7 +20,7 @@ , "of a .tex file in \"srcs\"; the \"stage\" is prepended automatically." ] } - , "config_fields": ["env", "latex"] + , "config_vars": ["env", "latex"] , "config_doc": { "latex": ["Name of the latex command, defaults to \"pdflatex\"."] , "env": @@ -29,180 +29,31 @@ ] } , "implicit": {"runner": ["latex_runner.sh"]} - , "imports": {"singleton": ["./", "..", "stage_singleton_field"]} + , "imports": + { "singleton": ["./", "..", "stage_singleton_field"] + , "call latex": "call latex" + } , "expression": { "type": "let*" , "bindings": - [ [ "stage" - , { "type": "join" - , "separator": "/" - , "$1": {"type": "FIELD", "name": "stage"} - } - ] - , [ "srcs" - , { "type": "disjoint_map_union" - , "msg": "Sources may not conflict" - , "$1": - { "type": "foreach" - , "var": "x" - , "range": {"type": "FIELD", "name": "srcs"} - , "body": - { "type": "map_union" - , "$1": - [ {"type": "DEP_RUNFILES", "dep": {"type": "var", "name": "x"}} - , { "type": "DEP_ARTIFACTS" - , "dep": {"type": "var", "name": "x"} - } - ] - } - } - } - ] - , [ "main" - , { "type": "assert_non_empty" - , "msg": "Entry-point main cannot be empty" - , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "main"}} - } - ] - , [ "_" - , { "type": "if" - , "cond": - { "type": "==" - , "$1": - { "type": "lookup" - , "map": {"type": "var", "name": "srcs"} - , "key": - { "type": "join" - , "$1": [{"type": "var", "name": "main"}, ".tex"] - } - } - , "$2": null - } - , "then": - { "type": "fail" - , "msg": - [ "main not the base name of a .tex file in srcs" - , "main has value" - , {"type": "var", "name": "main"} - , "srcs have file names" - , {"type": "keys", "$1": {"type": "var", "name": "srcs"}} - ] - } - } - ] - , [ "main" - , { "type": "if" - , "cond": - {"type": "==", "$1": {"type": "var", "name": "stage"}, "$2": ""} - , "then": {"type": "var", "name": "main"} - , "else": - { "type": "join" - , "separator": "/" - , "$1": - [ {"type": "var", "name": "stage"} - , {"type": "var", "name": "main"} - ] - } - } - ] - , [ "srcs" - , { "type": "to_subdir" - , "subdir": {"type": "var", "name": "stage"} - , "$1": {"type": "var", "name": "srcs"} - } - ] - , [ "deps" - , { "type": "disjoint_map_union" - , "msg": "Dependencies may not conflict" - , "$1": - { "type": "foreach" - , "var": "x" - , "range": {"type": "FIELD", "name": "deps"} - , "body": - {"type": "DEP_RUNFILES", "dep": {"type": "var", "name": "x"}} - } - } - ] - , [ "tex inputs" - , { "type": "to_subdir" - , "subdir": "work" - , "$1": - { "type": "disjoint_map_union" - , "msg": "Staging conflict between staged sources and deps" - , "$1": - [ {"type": "var", "name": "deps"} - , {"type": "var", "name": "srcs"} - ] - } - } - ] + [ ["srcs", {"type": "FIELD", "name": "srcs"}] + , ["main", {"type": "FIELD", "name": "main"}] + , ["deps", {"type": "FIELD", "name": "deps"}] + , ["stage", {"type": "FIELD", "name": "stage"}] + , ["output file extension", [".pdf"]] , [ "env" - , { "type": "map_union" - , "$1": - [ { "type": "singleton_map" - , "key": "PATH" - , "value": "/bin:/usr/bin:/usr/local/bin" - } - , { "type": "singleton_map" - , "key": "SOURCE_DATE_EPOCH" - , "value": "0" - } - , {"type": "var", "name": "env", "default": {"type": "empty_map"}} - ] - } + , {"type": "var", "name": "env", "default": {"type": "empty_map"}} ] + , ["executable", {"type": "var", "name": "latex", "default": "pdflatex"}] , [ "runner" , { "type": "let*" , "bindings": [["fieldname", "runner"], ["location", "runner"]] , "body": {"type": "CALL_EXPRESSION", "name": "singleton"} } ] - , [ "cmd" - , [ "./runner" - , {"type": "var", "name": "latex", "default": "pdflatex"} - , {"type": "var", "name": "main"} - ] - ] - , [ "pdf" - , { "type": "ACTION" - , "inputs": - { "type": "map_union" - , "$1": - [ {"type": "var", "name": "tex inputs"} - , {"type": "var", "name": "runner"} - ] - } - , "outs": - [ { "type": "join" - , "$1": ["work/", {"type": "var", "name": "main"}, ".pdf"] - } - ] - , "cmd": {"type": "var", "name": "cmd"} - , "env": {"type": "var", "name": "env"} - } - ] - , [ "pdf" - , { "type": "map_union" - , "$1": - { "type": "foreach_map" - , "var_key": "name" - , "var_val": "file" - , "range": {"type": "var", "name": "pdf"} - , "body": - { "type": "singleton_map" - , "key": - {"type": "basename", "$1": {"type": "var", "name": "name"}} - , "value": {"type": "var", "name": "file"} - } - } - } - ] + , ["runner type", "standalone"] ] - , "body": - { "type": "RESULT" - , "artifacts": {"type": "var", "name": "pdf"} - , "runfiles": {"type": "var", "name": "pdf"} - } + , "body": {"type": "CALL_EXPRESSION", "name": "call latex"} } } , "verbatim": @@ -311,4 +162,88 @@ } } } +, "latexmk": + { "doc": + [ "A latexmk run" + , "" + , "Call latexmk passing main as the entry point. A correct staging" + , "of the needed files has to be given through the runfiles of \"deps\"." + ] + , "target_fields": ["deps", "srcs"] + , "string_fields": ["main", "stage", "opts", "output extension"] + , "field_doc": + { "srcs": ["The files needed for the latexmk run."] + , "stage": + [ "The directory the \"srcs\" logically reside in." + , "Entries are joined with \"/\"." + ] + , "deps": + ["Runfiles needed for the run of the standalone latex invocation"] + , "main": + [ "The entry point for the latex run; should be the base name" + , "of a .tex file in \"srcs\"; the \"stage\" is prepended automatically." + ] + , "opts": + ["The latexmk options to be used.", "If omitted, \"-pdf\" is assumed"] + , "output extension": + [ "The extension of the output to be produced (e.g., \".ps\", \".pdf\")." + , "If omitted, \".pdf\" is assumed." + ] + } + , "config_vars": ["env", "latexmk"] + , "config_doc": + { "env": + [ "Any override to the default environment which sets only" + , "PATH and SOURCE_DATE_EPOCH" + ] + , "latexmk": ["Name of the latexmk command, defaults to \"latexmk\"."] + } + , "imports": {"call latex": "call latex"} + , "expression": + { "type": "let*" + , "bindings": + [ ["srcs", {"type": "FIELD", "name": "srcs"}] + , ["main", {"type": "FIELD", "name": "main"}] + , ["deps", {"type": "FIELD", "name": "deps"}] + , ["stage", {"type": "FIELD", "name": "stage"}] + , [ "output file extension" + , { "type": "if" + , "cond": {"type": "FIELD", "name": "output extension"} + , "then": {"type": "FIELD", "name": "output extension"} + , "else": [".pdf"] + } + ] + , [ "env" + , {"type": "var", "name": "env", "default": {"type": "empty_map"}} + ] + , [ "executable" + , {"type": "var", "name": "latexmk", "default": "latexmk"} + ] + , ["opts", {"type": "FIELD", "name": "opts"}] + , [ "runner" + , { "type": "singleton_map" + , "key": "runner" + , "value": + { "type": "BLOB" + , "data": + { "type": "join" + , "separator": "\n" + , "$1": + [ "set -e" + , "LATEXMK=\"$1\"" + , "shift" + , "MAIN=\"$1\"" + , "shift" + , "cd work" + , "\"$LATEXMK\" -output-directory=\"$(dirname \"$MAIN\")\" \"$@\" \"$MAIN\" > log 2>&1 || (cat log && exit 1)" + ] + } + } + } + ] + , ["runner type", "latexmk"] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "call latex"} + } + } } -- cgit v1.2.3