Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Resume, Portfolio & GitHub Profile  Module 5 – LaTeX resumes: Overleaf and TeX Live

LaTeX resume builds: TeX Live, variants and CI

How to build a LaTeX resume with latexmk, make tailored variants from one source, keep your phone number and file paths out of PDFs, and check it in CI.

  • Advanced
  • 20 minutes
  • Examples run with Python 3.14.8, Node.js 24.21.0, Pyodide 314.0.7, TinyTeX 2026.10, latexmk 4.88, pandoc 3.12, veraPDF 1.30.2 and actionlint 1.7.12
  • By MySmartCoPilot
Free core, Pro depth: 7 of 20 minutes free
Free: latexmk builds on your computer what Overleaf builds online · One source, a driver per variant, and a private file · A PDF carries more than its page. With a pass: 3 in-depth parts and 3 interview answers, about 13 minutes.

What you will learn

  • Build your resume locally with TeX Live and latexmk, the build tool Overleaf also runs
  • Generate tailored variants from one LaTeX source without copying text
  • Prevent phone numbers, file paths and photo metadata from leaking into shared files and PDFs
  • Run a reproducible, checked CI build, and check a Word copy against the PDF
  • Export a tagged LaTeX resume that passes a PDF/UA-2 check when you need one

Before you start

What you’ll learn · Before you start

What you will learn

  • Build your resume locally with TeX Live and latexmk, the build tool Overleaf also runs
  • Generate tailored variants from one LaTeX source without copying text
  • Prevent phone numbers, file paths and photo metadata from leaking into shared files and PDFs
  • Run a reproducible, checked CI build, and check a Word copy against the PDF
  • Export a tagged LaTeX resume that passes a PDF/UA-2 check when you need one

Before you start

On this page

Meera applies for backend and data internships from one LaTeX source. Two short driver files make two PDFs that differ in exactly two lines, and the file that holds her phone number has never been committed anywhere.

This lesson builds that set-up on your own computer with latexmk, makes tailored variants without copying text, and keeps private details out of every file you share. You will also check what a PDF carries besides its page.

latexmk builds on your computer what Overleaf builds online

Overleaf compiles every project with latexmk, a build tool that runs pdfLaTeX, XeLaTeX or LuaLaTeX as many times as a document needs. Installed with TeX Live or TinyTeX, the same tool builds the same source on your computer, and the latex-typst track’s install lesson sets both up. The two builds compare like this:

On Overleaf On your computer
Build tool latexmk latexmk, from TeX Live or TinyTeX
Engine The compiler in the project’s settings -pdf, -xelatex or -lualatex on the command line
TeX Live year The project’s year, in its settings The year you installed
Your phone number In the project, for everyone it is shared with In a file that never leaves your computer
After the build The PDF preview and the compile log Any check you write, such as a pdftotext search

A copy that builds on your computer keeps working whatever happens to any website, and the last two rows are why this lesson builds there: a private file for your details, and checks that run on every build.

Checkpoint

Check: Building locally with latexmk

  1. One question What does latexmk do that a single pdflatex command does not?

    Choose one answer.

    Show the answer: One question

    Answer: It runs the engine as many times as the document needs, as Overleaf does for every project

    latexmk is the build tool Overleaf itself uses, and on your computer it works the same way: it reruns the engine until the output settles.

One source, a driver per variant, and a private file

A variant must never be a copy of the resume, because copies drift and a fix made in one never reaches the other. Meera keeps one source, resume.tex, and a short driver file: A short LaTeX file that declares the document class, sets the options of one variant, such as its name, and then reads the shared source. Building it gives that variant's PDF. per variant that declares the document class, names the variant and reads the source. The few lines that differ between variants sit inside etoolbox’s \ifdefstring tests, which read the name. Her phone number lives in private-contact.tex, which the source reads only if it exists:

One source, one of its drivers, and the private file

resume/resume.tex

% Meera Iyer's resume: one source for every variant. A driver file declares the class, names the variant in
% \ResumeVariant and reads this file; the lines that differ between variants are the \ifdefstring blocks.
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[margin=18mm]{geometry}
\usepackage{etoolbox}
\usepackage[hidelinks]{hyperref}
\hypersetup{pdftitle={Meera Iyer: resume (\ResumeVariant)}, pdfauthor={Meera Iyer}}
% The phone number lives in private-contact.tex, which is never committed or shared; without it the PDF says so.
\IfFileExists{private-contact.tex}{\input{private-contact.tex}}{\newcommand{\Phone}{phone on request}}
\pagestyle{empty}
\raggedright
\hyphenpenalty=10000
\exhyphenpenalty=10000
\setlength{\parindent}{0pt}
\newcommand{\Section}[1]{\par\bigskip{\large\bfseries #1}\par\smallskip\hrule\medskip}
\newcommand{\Entry}[3]{\textbf{#1}, #2, #3\par}
\newenvironment{Bullets}{\begin{itemize}\setlength{\itemsep}{1pt}}{\end{itemize}}
\begin{document}
{\LARGE\bfseries Meera Iyer}\par\medskip
\ifdefstring{\ResumeVariant}{data}{Data analyst intern}{Backend developer intern} \textperiodcentered{} Pune
\textperiodcentered{} \Phone{} \textperiodcentered{} \href{mailto:meera.iyer@example.com}{meera.iyer@example.com}
\textperiodcentered{} \href{https://github.com/meera-iyer-example}{github.com/meera-iyer-example}\par
\Section{Education}
B.Tech.\ Computer Science, Example Institute of Technology, 2023--2027 (expected) \textperiodcentered{} CGPA 8.4/10\par
\Section{Experience}
\Entry{Software Engineering Intern}{Example Payments, Bengaluru}{2026}
\begin{Bullets}
  \item Built a retry queue in Python for failed payout webhooks, cutting manual reconciliation from 3 hours to
        20 minutes a week.
  \ifdefstring{\ResumeVariant}{data}{%
  \item Wrote the SQL behind a weekly report of failed payouts by bank, read by the operations team.}{%
  \item Wrote 46 unit tests for the configuration loader and a workflow that runs them on every pull request.}
\end{Bullets}
\Section{Projects}
\Entry{Canteen queue tracker}{Flask, SQLite}{2025}
\begin{Bullets}
  \item One of three students; built the token queue and its tests. The average lunch-hour wait fell from 14 to 6
        minutes over four weeks.
\end{Bullets}
\Section{Skills}
Python, SQL, PostgreSQL, Flask, SQLite, Docker, Git, Linux
\end{document}

backend driver · resume/meera-iyer-backend-resume.tex

% The backend variant of the resume. It declares the class because Overleaf's main document
% must have a \documentclass declaration.
\documentclass[a4paper,10pt]{article}
\newcommand{\ResumeVariant}{backend}
\input{resume}

resume/private-contact.tex

% Never committed or shared: .gitignore lists this file.
\newcommand{\Phone}{+91 01234 56789}

Each driver declares the class because Overleaf’s main document must have a \documentclass declaration, and on Overleaf the driver is the file you choose as the main document. Step through one build:

Interactive · stage by stage One source, two drivers, two PDFs Step through the backend variant's build. Each file does one job, and only one of them holds the phone number.
One source, two drivers, two PDFs, step 6 of 6. Showing A driver file, resume.tex, private-contact.tex, latexmk -pdf, Two PDFs. In focus: Two PDFs.missing: on requestA driver filethe class and the variantresume.texevery line of both variantsprivate-contact.texthe phone, never committedlatexmk -pdfruns pdfLaTeX as neededTwo PDFsone title per variant

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The driver. meera-iyer-backend-resume.tex declares the document class, sets the variant to backend and reads resume.tex. Because it declares the class, it can be the main document on Overleaf, which requires that declaration.
  2. The shared source. resume.tex holds every line of both variants. The two lines that differ sit inside etoolbox's \ifdefstring tests, which read the variant the driver set.
  3. The private file. If private-contact.tex is in the folder, resume.tex reads the phone number from it. The file is listed in .gitignore, so it never reaches the repository.
  4. Without the private file. On a computer that never had the file, such as a fresh clone or a CI runner given no copy of it, the same source prints "phone on request" instead.
  5. latexmk builds it. latexmk runs pdfLaTeX as many times as the document needs, the same build tool that Overleaf uses for its projects.
  6. Two PDFs. The backend and data PDFs differ in exactly two lines, and each carries its variant in its PDF title. Every other line is the same, word for word.

The program builds both variants with latexmk, compares their text, and builds again without the private file:

Two variants from one source, and a build without the private file Python · variants_session.py
import difflib

from session import files, run, shell

# Two variants of one resume with latexmk: each driver file names its variant and reads resume.tex, and
# private-contact.tex adds the phone number. Then the same build without the private file, as on a computer or a
# CI runner that never had it.
files("resume/resume.tex", "resume/meera-iyer-backend-resume.tex", "resume/meera-iyer-data-resume.tex",
      "resume/private-contact.tex", "resume/gitignore.txt=.gitignore")
run("""
latexmk -pdf -interaction=nonstopmode -halt-on-error meera-iyer-backend-resume.tex meera-iyer-data-resume.tex
""", keep=[r"^Latexmk: applying rule", r"^Output written", r"^Latexmk: All targets"])
run("""
pdfinfo meera-iyer-backend-resume.pdf | grep -E '^(Title|Pages):'
pdfinfo meera-iyer-data-resume.pdf | grep -E '^(Title|Pages):'
""")


def lines(pdf):
    """The lines of a PDF's text as poppler extracts them, with each wrapped line joined to the one it continues."""
    out = []
    for line in shell(f"pdftotext {pdf} -")[1].splitlines():
        if not line.strip():
            continue
        if out and (line[0].islower() or line[0].isdigit() or out[-1].endswith("·")):
            out[-1] += " " + line
        else:
            out.append(line)
    return out


backend, data = lines("meera-iyer-backend-resume.pdf"), lines("meera-iyer-data-resume.pdf")
print("# The lines in which the two texts differ:")
same = 0
for op, a, b, c, d in difflib.SequenceMatcher(None, backend, data, autojunk=False).get_opcodes():
    if op == "equal":
        same += b - a
        continue
    for line in backend[a:b]:
        print(f"#   backend: {line}")
    for line in data[c:d]:
        print(f"#   data:    {line}")
print(f"# The other {same} lines are the same in both, in the same order.")
print()
run("mv private-contact.tex ~/private-contact.tex")
run("latexmk -g -pdf -interaction=nonstopmode -halt-on-error meera-iyer-backend-resume.tex", keep=[r"^Output written"])
run("""
pdftotext meera-iyer-backend-resume.pdf - | head -2
cat .gitignore
""")

Output

$ latexmk -pdf -interaction=nonstopmode -halt-on-error meera-iyer-backend-resume.tex meera-iyer-data-resume.tex
Latexmk: applying rule 'pdflatex'...
Output written on meera-iyer-backend-resume.pdf (1 page, 87253 bytes).
Latexmk: applying rule 'pdflatex'...
Output written on meera-iyer-backend-resume.pdf (1 page, 87253 bytes).
Latexmk: All targets (meera-iyer-backend-resume.pdf) are up-to-date
Latexmk: applying rule 'pdflatex'...
Output written on meera-iyer-data-resume.pdf (1 page, 86708 bytes).
Latexmk: applying rule 'pdflatex'...
Output written on meera-iyer-data-resume.pdf (1 page, 86708 bytes).
Latexmk: All targets (meera-iyer-data-resume.pdf) are up-to-date
[… 133 lines left out]
$ pdfinfo meera-iyer-backend-resume.pdf | grep -E '^(Title|Pages):'
Title:           Meera Iyer: resume (backend)
Pages:           1
$ pdfinfo meera-iyer-data-resume.pdf | grep -E '^(Title|Pages):'
Title:           Meera Iyer: resume (data)
Pages:           1
# The lines in which the two texts differ:
#   backend: Backend developer intern · Pune · +91 01234 56789 · meera.iyer@example.com · github.com/meera-iyer-example
#   data:    Data analyst intern · Pune · +91 01234 56789 · meera.iyer@example.com · github.com/meera-iyer-example
#   backend: • Wrote 46 unit tests for the configuration loader and a workflow that runs them on every pull request.
#   data:    • Wrote the SQL behind a weekly report of failed payouts by bank, read by the operations team.
# The other 11 lines are the same in both, in the same order.

$ mv private-contact.tex ~/private-contact.tex
$ latexmk -g -pdf -interaction=nonstopmode -halt-on-error meera-iyer-backend-resume.tex
Output written on meera-iyer-backend-resume.pdf (1 page, 86837 bytes).
[… 35 lines left out]
$ pdftotext meera-iyer-backend-resume.pdf - | head -2
Meera Iyer
Backend developer intern · Pune · phone on request · meera.iyer@example.com ·
$ cat .gitignore
# Copied into the project as .gitignore by the sessions: these files never reach the repository.
private-contact.tex
*.pdf
*.aux
*.log
*.fls
*.fdb_latexmk
*.out

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 variants_session.py

The two texts differ in exactly the two marked lines, each PDF carries its variant in its title, and without the private file the page says “phone on request”. A variant only chooses among true lines, as the tailoring lesson requires; it never adds a claim.

Key idea

Keep one source and a driver per variant, put the lines that differ inside tests of the variant’s name, and keep your phone number in a file that is read if present and never committed.

Checkpoint

Check: One source, drivers and a private file

  1. Question 1 of 2 Why does each of Meera's driver files declare \documentclass, instead of leaving it in resume.tex?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Overleaf's main document must have a \documentclass declaration

    A driver declares the class, names the variant and reads the shared source; on Overleaf you choose it as the main document.

  2. Question 2 of 2 What did the backend PDF say in place of the phone number when private-contact.tex was missing?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: phone on request

    The private file is read if present; without it, on a fresh clone or a CI runner, the same source prints "phone on request".

A PDF carries more than its page

Before a PDF leaves your computer, check what travels inside it. pdfTeX records the name of an included PDF file, path and all. A phone photo keeps the location where it was taken. A build records the moment it ran, so two builds of one source are two different files, unless the SOURCE_DATE_EPOCH variable gives pdfTeX a fixed time to record instead. A Word copy converted from LaTeX can lose parts of the resume, and a PDF made for screen readers needs tags that some packages cannot yet produce. Each has a check:

What travels The check
An included file’s path Search the PDF’s objects for PTEX.FileName
A photo’s camera details Read the embedded image’s metadata
The time of the build Build twice and compare the files
A Word copy’s text Compare it with the PDF’s text
Tags for screen readers Validate the PDF with veraPDF

Checkpoint

Check: What a PDF carries besides its page

  1. One question Which of these can a resume PDF carry besides what its page shows?

    Choose every answer that is right.

    Show the answer: One question

    Answer:

    • The path of a PDF file it includes
    • The moment it was built
    • The location where a photo in it was taken

    A PDF can carry an included file's path, a photo's details and the time of its build; each has a check before you share.

Paths, photos and the public variant: what a PDF carries, measured Pro: opens with a Pro, Premium or Ultimate pass

A resume PDF can carry details its page never shows. This part finds three of them in one header, removes each at its source, and settles which variant may ever be published.

In this part:

  • A path, a photo’s location and a missing title, measured
  • A last look at the PDF, in four commands
  • Publish only the variant without your phone number

1 runnable example (Python) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

A reproducible build in CI, pinned and checked Pro: opens with a Pro, Premium or Ultimate pass

A resume built by a workflow on every push needs the same care as any other software build. This part makes the build reproducible, checks a workflow against a weak first attempt, and shows why an unknown template is compiled with care.

In this part:

  • The same source, the same PDF: a fixed build time, measured
  • A workflow pinned and checked, against a weak first attempt
  • Compile only templates you trust

4 runnable examples (Python, resume-weak.yml, resume.yml) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

A Word copy and a tagged PDF, measured Pro: opens with a Pro, Premium or Ultimate pass

Some applications ask for Word, and some readers need a PDF their software can follow. This part measures what a conversion loses and makes a tagged resume pass a PDF/UA-2 check.

In this part:

  • What pandoc kept and lost of a LaTeX resume
  • A tagged PDF/UA-2 resume in TeX Live 2026, with two fixes

2 runnable examples (Python) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Practise: check the files you are about to commit

Write the check that stops a private file, a phone number or an absolute path from reaching the repository:

Exercise · Medium · Python

Check the files you are about to commit

Before a resume repository is pushed, check what it would carry. Write tracked_problems(files) in tracked.py. files maps each path that would be committed to its text. Return a list of problems, as strings:

  • "<path>: the private file is tracked" for a file whose name is private-contact.tex;
  • "<path>:<line>: a phone number" for each line of a .tex file with a run of at least 10 digits, where single spaces or hyphens may sit between them and a + may come first, as in +91 01234 56789;
  • "<path>:<line>: an absolute path" for each line of a .tex file whose \includegraphics or \input names a file starting with /, with ~, or with a drive letter such as C:\;
  • "no PDF title", once and last, when no .tex file sets pdftitle.

List the problems of each file in line order, files in the order of their paths sorted, then the title problem. A .tex line that starts with % is a comment: check it too, because a comment is committed like any other line.

Starter code · tracked.py

import re


def tracked_problems(files):
    """What a resume repository would carry that it should not: the private file, phone numbers, absolute paths."""
    # Replace this comment and the line below with the rules of the prompt.
    return []
The sample tests · test_tracked.py
from tracked import tracked_problems

RESUME = "\\usepackage[hidelinks]{hyperref}\n\\hypersetup{pdftitle={Meera Iyer: resume (\\ResumeVariant)}}\n"
DRIVER = "\\documentclass[a4paper,10pt]{article}\n\\newcommand{\\ResumeVariant}{backend}\n\\input{resume}\n"


def test_a_clean_repository():
    """finds nothing in the lesson's resume.tex and driver"""
    assert tracked_problems({"resume.tex": RESUME, "meera-iyer-backend-resume.tex": DRIVER}) == []


def test_the_private_file_tracked():
    """reports the private file, and the phone number in it"""
    files = {"resume.tex": RESUME, "private-contact.tex": "\\newcommand{\\Phone}{+91 01234 56789}\n"}
    assert tracked_problems(files) == [
        "private-contact.tex: the private file is tracked",
        "private-contact.tex:1: a phone number",
    ]


def test_a_phone_in_a_comment():
    """reports a phone number in a comment, which is committed like any line"""
    files = {"resume.tex": RESUME + "% call me: 012-345-678-90\n"}
    assert tracked_problems(files) == ["resume.tex:3: a phone number"]


def test_absolute_paths():
    """reports absolute paths in \\includegraphics and \\input, and not a relative one"""
    header = "\\includegraphics[height=10mm]{/Users/meera/Desktop/logo.pdf}\n\\input{~/private/contact}\n\\includegraphics{logo.pdf}\n"
    assert tracked_problems({"header.tex": header, "resume.tex": RESUME}) == [
        "header.tex:1: an absolute path",
        "header.tex:2: an absolute path",
    ]


def test_no_title_and_short_numbers():
    """reports a missing PDF title once, last, and ignores numbers shorter than 10 digits"""
    files = {"b.tex": "CGPA 8.4/10, 2023--2027\n", "a.tex": "\\includegraphics{C:\\Users\\meera\\logo.png}\n"}
    assert tracked_problems(files) == ["a.tex:1: an absolute path", "no PDF title"]
A hint

Sort the paths, then for each .tex file walk through enumerate(text.splitlines(), start=1). A phone number is easiest to find by taking out spaces and hyphens between digits first, or with a pattern such as \+?\d(?:[ -]?\d){9,}. For paths, look at what follows \includegraphics[…]{ or \input{.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Then test yourself on local builds, variants and what a PDF carries; each round starts with your weakest:

Practice that adapts to you

Practise this lesson

3 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 3 Your template needs XeLaTeX. Which command builds it locally the way latexmk builds it on Overleaf?

    Choose one answer.

    Show the answer: Question 1 of 3

    Answer: latexmk -xelatex resume.tex

    Match latexmk's engine option to the template: -pdf for pdfLaTeX, -xelatex or -lualatex for the others.

  2. Question 2 of 3 A friend keeps a backend.tex and a data.tex, each a full copy of the resume. What goes wrong first?

    Choose one answer.

    Show the answer: Question 2 of 3

    Answer: A fix made in one copy never reaches the other, so the two drift apart

    Keep one source and short drivers; then the variants differ only in the lines that test the variant's name.

  3. Question 3 of 3 How do you tell whether two builds of your resume are the same file?

    Choose one answer.

    Show the answer: Question 3 of 3

    Answer: Build twice and compare the files byte for byte

    Two builds are the same file only if their bytes are; a build that records its time gives a different file each time.

Interview questions

Warm-up (fresher to mid-level): How do you keep two versions of a LaTeX resume in step?

With one source and a driver file per version. The driver names the version and reads the source, and the few lines that differ sit inside tests of that name, so a fix in the source reaches both PDFs. Private details live in a file that is read if present and never committed.

Three questions of this module’s bank go further:

  1. Fresher to mid

    You find that private-contact.tex, with your phone number, was committed to your public resume repository three weeks ago, and the repository has two forks. What do you do now, what can and cannot be undone, and how do you stop it happening again?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    A friend opens your resume PDF in a text editor and finds /Users/yourname/Desktop/college-logo.pdf inside it, though no such text is on the page. Where did it come from, what else might the PDF carry, and how do you fix it?

    Model answer, Pro. First step and follow-ups

  3. Fresher to mid

    A portal accepts only Word files. You convert your LaTeX resume with pandoc, and it reports no error. How do you make sure the Word copy says what your PDF says, and what do you do if it does not?

    Model answer, Pro. First step and follow-ups

Flashcards · 7 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. What is latexmk, and why can it build an Overleaf resume on your own computer?

    A build tool that runs pdfLaTeX, XeLaTeX or LuaLaTeX as many times as a document needs. Overleaf compiles with it, and the same tool from TeX Live or TinyTeX builds the same source locally.

  2. What does a build on your own computer give you that an online build does not?

    A private file for your details that never leaves your machine, and checks of your own, such as a pdftotext search, that run on every build. The copy also keeps working whatever happens to any website.

  3. Why should a resume variant never be a copy of the resume?

    Copies drift, and a fix made in one never reaches the other. Keep one source and a short driver file per variant that names it, with the few lines that differ inside tests of that name.

  4. Why does each driver file declare the document class?

    On Overleaf the driver is the file you pick as the main document, and Overleaf's main document must contain a documentclass declaration.

  5. How do you keep your phone number on your own PDF but out of the repository?

    Put it in a separate file that the source reads only if it exists, and never commit that file. A build without it prints a fallback such as “phone on request”.

  6. Which details can a PDF carry besides what its page shows?

    The path of an included PDF file, which pdfTeX records; a photo's location and camera details; and the moment of the build, so two builds of one source differ unless SOURCE_DATE_EPOCH fixes the time.

  7. How do you check what a PDF carries before you share it?

    Search its objects for PTEX.FileName, read the metadata of any embedded image, build twice and compare the files, set the text of a Word copy beside the PDF's text, and validate the tags for screen readers with veraPDF.

Key takeaways

  • latexmk builds on your computer what Overleaf builds online, from the same source.
  • One source, a driver per variant and a private file keep variants in step and the phone number out of the repository.
  • A PDF can carry an included file’s path, a photo’s location and the time of its build; check each before you share.

Terms in this lesson

driver file
A short LaTeX file that declares the document class, sets the options of one variant, such as its name, and then reads the shared source. Building it gives that variant's PDF.
reproducible build
A build that turns the same source into the same file, byte for byte, every time it runs. For pdfTeX, that needs a fixed build time from SOURCE_DATE_EPOCH.
tagged PDF
A PDF that stores the structure of its content, such as headings, paragraphs and lists, so that screen readers and other software can follow it in order.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.