Skip to content

Commit

Permalink
Add support for generating svgs from tex files
Browse files Browse the repository at this point in the history
This can be a nice feature when a .tex file contains
a tikz figure.

This is enabled by exposing the dvisvgm binary in the
defined latex texlive toolchan.

dvisvgm is dependent on ghostscript as a dynamic lib,
which is why it has been added.

The previously referenced bazel docker image
in cirrus.yaml was not actively updated by google.
The last supported version was 3.5.
So the docker image was changed to the newly
provided image. See:

bazelbuild/continuous-integration#1060
bazelbuild/continuous-integration#1401

ghostscript is built from source using rules_foreign_cc,
which can't be entirely bootstrapped at this point.
(It can't build autoconf)

So it needs that to be installed from e.g. apt.
The bazel docker container did as far as I investigated
not allow to install packages in the container,
I could be wrong though.

Instead I created a github workflow, which depends on bazelisk.
bazelisk is a downloader for bazel. You can configure it always
run with a specific version. But sense cirrus.yaml uses latest,
we don't state any version meaning it will always download the
latest bazel.

It also enables a bazel cache which "should" speed up execution
in the ci pipeline.
  • Loading branch information
solsjo authored and Oskar Solsjö committed Sep 2, 2022
1 parent 73852bd commit 6e989a3
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 6 deletions.
4 changes: 2 additions & 2 deletions .cirrus.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
container:
image: l.gcr.io/google/bazel:latest
image: gcr.io/bazel-public/bazel:latest
task:
name: Build the example document
build_script: bazel build //example:all
build_script: bazel build //example:my_report //example:my_dvi_report
task:
name: Build all package tests
build_script: bazel build //packages:all
22 changes: 22 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Build and Deploy
on: [push]
permissions:
contents: write
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
- uses: mishas/setup-bazelisk-action@v1
- name: Mount bazel cache # Optional
uses: actions/cache@v1
with:
path: "~/.cache/bazel"
key: bazel
- name: build
shell: bash
run: >
bazelisk build //example:example_svg;
bazelisk build //...;
17 changes: 17 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ workspace(name = "bazel_latex")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
name = "platforms",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.6/platforms-0.0.6.tar.gz",
"https://github.com/bazelbuild/platforms/releases/download/0.0.6/platforms-0.0.6.tar.gz",
],
sha256 = "5308fc1d8865406a49427ba24a9ab53087f17f5266a7aabbfc28823f3916e1ca",
)

http_archive(
name = "bazel_toolchains",
sha256 = "109a99384f9d08f9e75136d218ebaebc68cc810c56897aea2224c57932052d30",
Expand All @@ -22,3 +31,11 @@ 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 files without dynamically
# linking to ghostscript.
load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies")

rules_foreign_cc_dependencies()
13 changes: 12 additions & 1 deletion example/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("@bazel_latex//:latex.bzl", "latex_document")
load("@bazel_latex//:latex.bzl", "latex_document", "latex_to_svg")

latex_document(
name = "my_report",
Expand Down Expand Up @@ -26,3 +26,14 @@ latex_document(
cmd_flags = ["--bibtex-cmd=biber"],
main = "my_report.tex",
)

latex_document(
name = "my_standalone_figure",
srcs = ["@bazel_latex//packages:drawstack"],
main = "tikz.tex",
)

latex_to_svg(
name = "example_svg",
src = ":my_standalone_figure",
)
12 changes: 12 additions & 0 deletions example/tikz.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}

\draw (-2,0) -- (2,0);
\filldraw [gray] (0,0) circle (2pt);
\draw (-2,-2) .. controls (0,0) .. (2,-2);
\draw (-2,2) .. controls (-1,0) and (1,0) .. (2,2);

\end{tikzpicture}
\end{document}
94 changes: 93 additions & 1 deletion latex.bzl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
load("@rules_foreign_cc//foreign_cc:providers.bzl", "ForeignCcArtifactInfo", "ForeignCcDepsInfo")

LatexOutputInfo = provider(fields = ['format', 'file'])

def _latex_impl(ctx):
Expand Down Expand Up @@ -79,8 +81,81 @@ _latex = rule(
implementation = _latex_impl,
)

def latex_document(name, main, srcs = [], tags = [], cmd_flags = [], format="pdf"):
def _latex_to_svg_impl(ctx):
toolchain = ctx.toolchains["@bazel_latex//:latex_toolchain_type"].latexinfo

custom_dependencies = []
for deps in ctx.attr.deps:
for file in deps.files.to_list():
if file.dirname not in custom_dependencies:
custom_dependencies.append(file.dirname)
custom_dependencies = ','.join(custom_dependencies)

src = ctx.attr.src
if LatexOutputInfo in src:
input_file = src[LatexOutputInfo].file
input_format = src[LatexOutputInfo].format
else:
fail("LatexOutputInfo provider not available in src")

flags = []
if "pdf" in input_format:
flags.append("--flag=--pdf")
if ctx.attr.box:
flags.append("--flag=-b{}".format(ctx.attr.box))

artifact = ctx.attr._libgs[ForeignCcDepsInfo].artifacts.to_list()[0]
libgs_path = ctx.attr.libgs_ext.format(artifact.lib_dir_name)
libgs = ["--env=LIBGS" + ":" + ctx.files._libgs[0].dirname + libgs_path]

ctx.actions.run(
mnemonic = "DviSvgM",
use_default_shell_env = True,
executable = ctx.executable._tool,
arguments = [
"--dep-tool=" + toolchain.kpsewhich.files.to_list()[0].path,
"--tool=" + toolchain.dvisvgm.files.to_list()[0].path,
"--input=" + input_file.path,
"--output=" + ctx.outputs.out.path,
"--tool-output=" + input_file.basename.rsplit(".", 1)[0] + ".svg",
"--inputs=" + custom_dependencies,
] + flags + libgs,
inputs = depset(
direct = ctx.files.src +
ctx.files.deps +
[toolchain.dvisvgm.files.to_list()[0]] +
ctx.files._libgs,
transitive = [
toolchain.kpsewhich.files,
toolchain.dvisvgm.files,
],
),
outputs = [ctx.outputs.out],
tools = [ctx.executable._tool],
)

_latex_to_svg = rule(
attrs = {
"src": attr.label(),
"deps": attr.label_list(allow_files = True),
"box": attr.string(
default = "",
values = ["", "exact", "min"],
),
"libgs_ext": attr.string(),
"_libgs": attr.label(default="@bazel_latex//third_party:lib_ghost_script_configure"),
"_tool": attr.label(
default = Label("@bazel_latex//:tool_wrapper_py"),
executable = True,
cfg = "host",
),
},
outputs = {"out": "%{name}.svg"},
toolchains = ["@bazel_latex//:latex_toolchain_type"],
implementation = _latex_to_svg_impl,
)

def latex_document(name, main, srcs = [], tags = [], cmd_flags = [], format="pdf"):
_latex(
name = name,
srcs = srcs + ["@bazel_latex//:core_dependencies"],
Expand All @@ -107,3 +182,20 @@ def latex_document(name, main, srcs = [], tags = [], cmd_flags = [], format="pdf
args = ["None"],
tags = tags,
)

def latex_to_svg(name, src, deps = [], **kwargs):

_latex_to_svg(
name = name,
src = src,
deps = deps + [
"@bazel_latex//:core_dependencies",
"@bazel_latex//third_party:ghostscript_dependencies"
],
libgs_ext = select({
"@platforms//os:macos": "/{}/libgs.dylib",
"@platforms//os:windows": "\\{}\\libgs.dll",
"//conditions:default": "/{}/libgs.so",
}),
**kwargs
)
25 changes: 24 additions & 1 deletion repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5644,7 +5644,7 @@ def latex_repositories():
name = name,
build_file_content = """
exports_files(
["kpsewhich", "luatex", "bibtex", "biber"],
["kpsewhich", "luatex", "bibtex", "biber", "dvisvgm"],
visibility = ["//visibility:public"],
)
""",
Expand Down Expand Up @@ -5691,7 +5691,30 @@ filegroup(
strip_prefix = "latexrun-38ff6ec2815654513c91f64bdf2a5760c85da26e",
url = "https://github.com/aclements/latexrun/archive/38ff6ec2815654513c91f64bdf2a5760c85da26e.tar.gz",
)

http_archive(
name = "rules_foreign_cc",
sha256 = "2a4d07cd64b0719b39a7c12218a3e507672b82a97b98c6a89d38565894cf7c51",
strip_prefix = "rules_foreign_cc-0.9.0",
url = "https://github.com/bazelbuild/rules_foreign_cc/archive/refs/tags/0.9.0.tar.gz",
)

_ALL_CONTENT = """\
filegroup(
name = "all_srcs",
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
"""

http_archive(
name = "ghost_script_source",
sha256 = "89a4e73be3edc3e40c46892332f29b0f7ed6003b0b952697e708aed2444d9ed1",
strip_prefix = "ghostpdl-ghostpdl-9.26",
build_file_content = _ALL_CONTENT,
url = "https://github.com/ArtifexSoftware/ghostpdl/archive/refs/tags/ghostpdl-9.26.tar.gz",
)

native.register_toolchains(
"@bazel_latex//:latex_toolchain_amd64-freebsd",
"@bazel_latex//:latex_toolchain_x86_64-darwin",
Expand Down
24 changes: 24 additions & 0 deletions third_party/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
load("@rules_foreign_cc//foreign_cc:defs.bzl", "configure_make")

filegroup(
name = "ghostscript_dependencies",
srcs = [
"@texlive_texmf__texmf-dist__dvips__base",
],
visibility = ["//visibility:public"],
)

configure_make(
name = "lib_ghost_script_configure",
configure_in_place = True,
autogen = True,
install_prefix = "output",
lib_source = "@ghost_script_source//:all_srcs",
targets = ["so", "soinstall"],
out_shared_libs = select({
"@platforms//os:macos": ["libgs.dylib"],
"@platforms//os:windows": ["libgs.dll"],
"//conditions:default": ["libgs.so"],
}),
visibility = ["//visibility:public"]
)
9 changes: 8 additions & 1 deletion toolchain.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
LatexInfo = provider(
doc = "Information about how to invoke the latex compiler",
fields = ["kpsewhich", "luatex", "bibtex", "biber"],
fields = ["kpsewhich", "luatex", "bibtex", "biber", "dvisvgm"],
)

def _latex_toolchain_info_impl(ctx):
Expand All @@ -11,6 +11,7 @@ def _latex_toolchain_info_impl(ctx):
luatex = ctx.attr.luatex,
bibtex = ctx.attr.bibtex,
biber = ctx.attr.biber,
dvisvgm = ctx.attr.dvisvgm,
),
),
]
Expand All @@ -37,6 +38,11 @@ _latex_toolchain_info = rule(
cfg = "host",
executable = True,
),
"dvisvgm": attr.label(
allow_single_file = True,
cfg = "host",
executable = True,
),
},
implementation = _latex_toolchain_info_impl,
)
Expand All @@ -48,6 +54,7 @@ def latex_toolchain(platform, exec_compatible_with):
luatex = "@texlive_bin__%s//:luatex" % platform,
bibtex = "@texlive_bin__%s//:bibtex" % platform,
biber = "@texlive_bin__%s//:biber" % platform,
dvisvgm = "@texlive_bin__%s//:dvisvgm" % platform,
visibility = ["//visibility:public"],
)

Expand Down

0 comments on commit 6e989a3

Please sign in to comment.