This repository provides Bazel rules for LaTeX, inspired by Klaus Aehlig's blog post on the matter.
Instead of depending on the host system's copy of LaTeX, these rules download a modular copy of TeXLive from GitHub. By using fine-grained dependencies, you will only download portions of TeXLive that are actually used in your documents.
As the output of the LaTeX tools is unnecessarily verbose, the main build rules invoke LaTeX using latexrun. Errors and warnings are formatted similar to those generated by Clang.
BibLaTeX is supported by biber and bibtex. Both are obtained from the TeX Live distribution. Latexrun defaults to bibtex. Please specify the command flag mentioned below to build with biber instead.
Add the following to WORKSPACE
:
http_archive(
name = "bazel_latex",
sha256 = "<checksum>",
strip_prefix = "bazel-latex-<release>",
url = "https://github.com/ProdriveTechnologies/bazel-latex/archive/v<release>.tar.gz",
patches = ["some_patch.patch"], % Optional
)
load("@bazel_latex//:repositories.bzl", "latex_repositories")
latex_repositories()
# Needed for building ghostscript
# Which is needed by dvisvgm,
# dvisvgm is part of the texlive toolchain,
# but cannot produce correct svg from pdf files without dynamically
# linking to ghostscript.
load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies")
rules_foreign_cc_dependencies()
# mac os shared lib was cumbersome to build via foreign rules so as a temporary
# solution we provide it as a precompiled artifact.
# Consider making it available via bazel_latex binaries repo instead
http_archive(
name = "ghostscript_macos",
build_file_content = """
filegroup(
name = "libgs_macos",
srcs = glob(["*/*"]),
target_compatible_with = ["@platforms//os:osx"],
visibility = ["//visibility:public"],
)
""",
sha256 = "56b480ebdf34000eac4a29e108ce6384858941d892fd69e604d90585aaae4c94",
urls = [
"https://github.com/solsjo/rules_latex_deps/releases/download/v0.9.4/rules_latex_deps_macos-latest.zip",
],
)
Add to your MODULE.bazel
file:
bazel_dep(name = "bazel_latex")
git_override(
module_name = "bazel_latex",
remote = "https://github.com/ProdriveTechnologies/bazel-latex.git",
commit = "227b02f346c1dd0098d32b5bcb1ef874dd367e2a",
)
And add the following load()
directive to your BUILD
files:
load("@bazel_latex//:latex.bzl", "latex_document")
You can then use latex_document()
in BUILD
file to declare documents that
need to be built.
load("@bazel_latex//:latex.bzl", "latex_document", "latex_to_svg")
latex_document(
name = "my_report",
srcs = glob([
"chapters/*.tex",
]) + [
"@bazel_latex//packages:biblatex",
"references.bib",
"//example/example_class:example_class",
],
bib_tool = "biber", # Is the default
format = "pdf", # Is the default
main = "my_report.tex",
)
latex_to_svg(
name = "my_svg_report",
src = ":my_report",
libgs = select({
"@platforms//os:osx": "@ghostscript_macos//:libgs_macos",
"//conditions:default": "@bazel_latex//third_party:libgs",
}),
)
latex_document(
name = "my_dvi_report",
srcs = glob([
"chapters/*.tex",
]) + [
"@bazel_latex//packages:biblatex",
"references.bib",
"//example/example_class:example_class",
],
format = "dvi",
main = "my_report.tex",
)
# svgs generated from dvis are 'searchable'.
# This is not yet the case for svg generated from pdfs.
latex_to_svg(
name = "my_dvi_svg_report",
src = ":my_dvi_report",
)
Note: For OS X, ghostscript for OS X might not be binary compatible with your version of OS X, as it is provided as a precompiled artifact.
Note: For OS X, latex_to_svg makes use of python to find the absolute path of ghostscript. In using python it also assumes that python3 on OS X is located at /usr/local/bin. This is unfortunate, but can be fixed in a later release.
Utilize cmd_flags
to provide optional command line arguments.
Commonly reused sources (e.g., templates) can be placed in
filegroup()
blocks, so that they don't need to be repeated. Those filegroup()
could
be located not just in the single BUILD
file, but in any of sub directories.
For example, if you want to include company specific template files which are
located in //company_dir
directory as company_style
, then declare them as
like following in company_dir/BUILD
file, and include the dependency, like
//company_dir:company_style
, in latex_repositories
.
filegroup(
name = "company_style",
srcs = glob([
...
]),
)
A PDF can be built by running:
bazel build //example:my_report
It can be viewed using your system's PDF viewer by running:
bazel run //example:my_report_view
If you want to get the output from the PDF viewer you can run:
bazel run //example:my_report_view_output
By default, latex_document()
only provides a version of TeXLive that
is complete enough to build the most basic documents. Whenever you use
\usepackage{}
in your documents, you must also add a corresponding
dependency to your latex_document()
. This will cause Bazel to download
and expose those packages for you. Below is an example of how a document
can be built that depends on the Hyperref package.
latex_document(
name = "hello",
srcs = ["@bazel_latex//packages:hyperref"],
main = "hello.tex",
)
This repository provides bindings for most commonly used packages. Please open a pull request if additional bindings are needed.
If the desired package to use is not available through bazel-latex, but is
available in TeX Live, then it is possible to patch BUILD.bazel
in
/packages
to add support for the desired package locally.
Therefore, clone bazel-latex locally, and make the desired changes to the
packages build file. Then, put the output of the diff in some_patch.patch
,
and update your WORKSPACE
accordingly as shown below.
http_archive(
name = "bazel_latex",
sha256 = "<checksum>",
strip_prefix = "bazel-latex-<release>",
url = "https://github.com/ProdriveTechnologies/bazel-latex/archive/v<release>.tar.gz",
patches = ["some_patch.patch"],
)
If this solution does not suffice, please feel free to open a PR to add the
corresponding package to Bazel LaTeX. In that case, also see CONTRIBUTING.md
.
An example is available in the corresponding folder. The example can be executed by running:
bazel run //example:my_report_view
These rules have been tested to work on (using bazel 3.2.0):
These rules are known not to work on: