mirror of
https://github.com/hanzoai/papers.git
synced 2026-10-22 17:20:17 +00:00
Hanzo CI/CD / test (linux-amd64) (push) Skipped
Hanzo CI/CD / test (linux-arm64) (push) Skipped
Hanzo CI/CD / test-advisory (push) Skipped
ci / papers (push) Failing after 27s
Build LaTeX Papers / build-pdfs (push) Failing after 1m1s
Hanzo CI/CD / test-amd64 (push) Successful in 1m44s
Hanzo CI/CD / cicd (push) Successful in 4m59s
CI/CD / cicd (push) Successful in 6m46s
enso/ now lives in hanzo-inc/enso under papers/enso/, and kai/ in hanzo-inc/kai under papers/kai/, each with its history. The index, the site's paper list and its built kai.pdf drop them.
163 lines
7.6 KiB
Makefile
163 lines
7.6 KiB
Makefile
# Makefile for Hanzo Papers
|
|
# Compiles every standalone .tex paper in the repo to a PDF under pdfs/.
|
|
#
|
|
# Usage:
|
|
# make -k all # Build every paper, report all failures
|
|
# make pdfs/hanzo-aso.pdf # Build one paper
|
|
# make list # Every paper, one path per line
|
|
# make clean # Remove aux files
|
|
# make clean-all # Remove aux + PDFs
|
|
#
|
|
# A paper that does not compile fails. Every recipe line here used to end in
|
|
# `|| true` and the rule printed "FAIL" instead of exiting, so `make all`
|
|
# returned 0 over any number of broken papers — the gate in
|
|
# .hanzo/workflows/ci.yml was green for as long as it existed. Use -k to build
|
|
# the rest after one breaks; that is what -k is for, and it is the only reason
|
|
# the old rule had to swallow the status.
|
|
#
|
|
# Docker (no local TeX install needed):
|
|
# docker run --rm -v "$$PWD:/workdir" -w /workdir texlive/texlive:latest make -k all
|
|
|
|
# A paper is any .tex with a \documentclass, wherever it lives. This is the one
|
|
# definition of the paper set; scripts/gen-index.sh reads it from here rather
|
|
# than restating it. Excluded: sections/ and shared/ hold fragments with no
|
|
# \documentclass of their own, site/ is the website, pdfs/ is output, and
|
|
# defense/logo-convert.tex is a helper that rasterises the logo through inkscape.
|
|
#
|
|
# The previous discovery was three wildcards over the root, zen/ and defense/,
|
|
# which is 150 of the 219 papers in the repo. The other 69 live in per-paper
|
|
# directories and were compiled by nothing.
|
|
ALL_TEX := $(shell grep -rl '^\\documentclass' --include='*.tex' . \
|
|
| sed 's|^\./||' \
|
|
| grep -v -e '^sections/' -e '/sections/' -e '^shared/' -e '^site/' \
|
|
-e '^pdfs/' -e 'node_modules/' -e '^defense/logo-convert\.tex$$' \
|
|
| sort)
|
|
|
|
# Map to output PDFs under pdfs/
|
|
ALL_PDFS := $(patsubst %.tex,pdfs/%.pdf,$(ALL_TEX))
|
|
|
|
# A recipe that exits nonzero leaves no PDF behind, so a stale artifact can
|
|
# never stand in for a build that did not happen.
|
|
.DELETE_ON_ERROR:
|
|
|
|
# Default: build everything
|
|
.PHONY: all
|
|
all: $(ALL_PDFS)
|
|
@echo ""
|
|
@echo "=== Build complete ==="
|
|
@echo "Papers compiled: $(words $(ALL_PDFS))"
|
|
|
|
# One paper, one rule, wherever it lives. latexmk decides how many passes are
|
|
# needed and runs bibtex; its exit status is the answer to "did this paper
|
|
# compile?", which is the whole gate.
|
|
#
|
|
# -halt-on-error stop at the first error rather than nonstopmode's "carry on
|
|
# and emit a PDF anyway" — a broken paper leaves no PDF
|
|
# -bibtex run bibtex whenever a paper declares a bibliography, so
|
|
# naming a .bib that does not exist fails instead of being
|
|
# quietly skipped (latexmk's default)
|
|
# -Werror an undefined citation or cross-reference is a defect in a
|
|
# paper, not a note in a log nobody reads
|
|
# -cd compile each paper from its own directory, so a paper's
|
|
# relative paths mean the same thing to make as they do to a
|
|
# human opening the file: zen/ finds references.bib, defense/
|
|
# finds hanzo-defense.sty, the root finds shared/
|
|
# -outdir absolute, because -cd moved us: PDF and aux land together
|
|
# under pdfs/, never at the repo root
|
|
#
|
|
# A paper is more than its .tex. A figure, a section fragment, a generated
|
|
# table, a .bib, a local .sty or the shared preamble all change the PDF, so all
|
|
# of them have to change the build. Without them `make` answers "up to date"
|
|
# over a stale PDF after a figure edit, which is the same silent success the old
|
|
# `|| true` produced.
|
|
# Secondary expansion is what makes $* usable in a pattern rule's prerequisites.
|
|
# The sibling-.tex line is skipped for a paper that lives at the repository
|
|
# root, where it would make all 150 of them depend on each other.
|
|
#
|
|
# latexmk keeps its own dependency record and skips a paper whose inputs have
|
|
# not changed in content, leaving the PDF's timestamp behind a prerequisite
|
|
# whose mtime moved but whose bytes did not. The touch after a successful run
|
|
# records what latexmk just established, so make and latexmk agree on what is
|
|
# current instead of one of them re-asking forever.
|
|
.SECONDEXPANSION:
|
|
pdfs/%.pdf: %.tex \
|
|
$$(wildcard $$(dir $$*)figures/*.tex) \
|
|
$$(wildcard $$(dir $$*)sections/*.tex) \
|
|
$$(wildcard $$(dir $$*)tables/*.tex) \
|
|
$$(if $$(filter ./,$$(dir $$*)),,$$(wildcard $$(dir $$*)*.tex)) \
|
|
$$(wildcard $$(dir $$*)*.bib) \
|
|
$$(wildcard $$(dir $$*)*.sty) \
|
|
$$(wildcard shared/*)
|
|
@mkdir -p $(dir $@)
|
|
@echo "Compiling $< ..."
|
|
@latexmk -pdf -halt-on-error -bibtex -Werror -interaction=nonstopmode -quiet \
|
|
-cd -outdir=$(CURDIR)/$(dir $@) $< > $(dir $@)$(*F).latexmk 2>&1 \
|
|
|| { echo " FAIL $<"; \
|
|
grep -A5 '^!' $(dir $@)$(*F).log; \
|
|
sed -n '/^Latexmk: Summary/,/^----/p' $(dir $@)$(*F).latexmk; \
|
|
false; }
|
|
@touch $@
|
|
@echo " OK $@"
|
|
|
|
# An arXiv upload is a paper's sources, which arXiv compiles without running
|
|
# bibtex, from one flat directory. So it is the paper directory's tracked TeX,
|
|
# the shared files it names with the ../shared/ prefix dropped, and the .bbl
|
|
# latexmk wrote. The upload is then compiled alone, without bibtex, the way
|
|
# arXiv will; one that needs anything outside itself fails here, not after
|
|
# submission. For a paper in its own directory: make arxiv/attestation/attestation.tar.gz
|
|
arxiv/%.tar.gz: pdfs/%.pdf
|
|
@rm -rf arxiv/$* arxiv/$*.check && mkdir -p arxiv/$*
|
|
@cd $(dir $*) && git ls-files -- '*.tex' '*.sty' '*.cls' '*.bst' '*.pdf' '*.png' '*.jpg' \
|
|
| tar -cf - -T - | tar -xf - -C $(CURDIR)/arxiv/$*
|
|
@for n in $$(grep -rhoE '\.\./shared/[A-Za-z0-9_-]+' arxiv/$* | sort -u | sed 's|.*/||'); do \
|
|
cp shared/$$n.* arxiv/$*/; done
|
|
@find arxiv/$* -name '*.tex' -exec sed -i.orig 's|\.\./shared/||g' {} + && find arxiv/$* -name '*.orig' -delete
|
|
@cp pdfs/$*.bbl arxiv/$*/
|
|
@cp -R arxiv/$* arxiv/$*.check && cd arxiv/$*.check \
|
|
&& latexmk -pdf -bibtex- -halt-on-error -interaction=nonstopmode -quiet $(notdir $*).tex > /dev/null 2>&1 \
|
|
|| { echo " FAIL arxiv/$*: the upload does not compile alone"; false; }
|
|
@rm -rf arxiv/$*.check && tar -czf $@ -C arxiv/$* .
|
|
@echo " OK $@ ($$(tar -tzf $@ | wc -l | tr -d ' ') files)"
|
|
|
|
# Clean auxiliary files (keep PDFs). The second sweep clears what the previous
|
|
# rule left at the repo root; latexmk writes beside the PDF and never there.
|
|
.PHONY: clean
|
|
clean:
|
|
@mkdir -p pdfs
|
|
@find pdfs -type f ! -name '*.pdf' -delete
|
|
@find . -maxdepth 1 \( -name '*.aux' -o -name '*.log' -o -name '*.out' \
|
|
-o -name '*.toc' -o -name '*.bbl' -o -name '*.blg' \
|
|
-o -name '*.fls' -o -name '*.fdb_latexmk' \) -delete
|
|
@echo "Cleaned."
|
|
|
|
# Clean everything
|
|
.PHONY: clean-all
|
|
clean-all:
|
|
@echo "Removing all generated files..."
|
|
@rm -rf pdfs
|
|
@echo "Done"
|
|
|
|
# Every paper, one per line. scripts/gen-index.sh reads this.
|
|
.PHONY: list
|
|
list:
|
|
@printf '%s\n' $(ALL_TEX)
|
|
|
|
.PHONY: help
|
|
help:
|
|
@echo "Hanzo Papers Makefile"
|
|
@echo ""
|
|
@echo "Targets:"
|
|
@echo " make -k all - Compile all $(words $(ALL_TEX)) papers, report every failure"
|
|
@echo " make pdfs/<name>.pdf - Compile a specific paper"
|
|
@echo " make arxiv/<dir>/<name>.tar.gz - arXiv upload of a paper in its own directory"
|
|
@echo " make list - List all discovered papers"
|
|
@echo " make clean - Remove auxiliary files"
|
|
@echo " make clean-all - Remove all generated files"
|
|
@echo ""
|
|
@echo "Docker:"
|
|
@echo " docker run --rm -v \"\$$PWD:/workdir\" -w /workdir texlive/texlive:latest make -k all"
|
|
|
|
.PHONY: index
|
|
index:
|
|
@scripts/gen-index.sh
|