TeX / e-TeX

Look inside a TeX Live 2024 installation and something odd turns up: latex, pdflatex and etex are not programs at all but symbolic links to pdftex. Only Knuth’s TeX itself — the command tex — survives as a separate executable. Once that sinks in, most of the confusion around LaTeX dissolves, because it reveals the distinction the whole ecosystem rests on: an engine (the program) and a format (a preloaded body of macros) are different things. This page covers the frozen program at the bottom of the stack and the e-TeX extensions bolted on in the 1990s — the baseline everyone now runs on without noticing.

What the tex command actually runs

What tex runs is a program that packs characters and boxes into lines and paragraphs, optimises the line breaks, and writes the result to a file — and essentially nothing more. The confusion starts because the word TeX names both this program and the system of commands the program interprets. Sectioning, cross-references, bibliographies: the program itself knows about none of them.

Knuth began the first TeX in 1978, driven there by the galley proofs of the second volume of his The Art of Computer Programming, whose mathematics he found unbearable. That first version was an exploratory prototype and was rewritten from scratch in 1982; the rewrite is TeX82, and “TeX” today effectively means that lineage. The minimal set of commands Knuth built into the program itself are the primitives\def (define a command), \hbox (a horizontal box), \vbox (a vertical box), and their kin.

Writing a document in bare primitives is impractical, so in practice you use a format: a layer of macros stacked on top of them. Loading plain.tex gives you plain TeX; loading a far larger macro set gives you LaTeX. A format is not re-read on every run — it is expanded ahead of time, saved as a .fmt file, and restored in an instant at start-up. The machinery behind that — what is inside a .fmt, how fmtutil rebuilds one, how LaTeX2e relates to LaTeX3 — belongs to the “LaTeX formats” page.

Which of tex, initex and etex is a real program

Only tex. initex is a symbolic link to tex, and etex is a link to pdftex — which means that e-TeX as a separate program no longer exists in current distributions at all. This is not an opinion but something readlink will confirm on your own machine in seconds. On TeX Live 2024, tex --version answers TeX 3.141592653 (TeX Live 2024).

terminal
$ tex --version | head -1
TeX 3.141592653 (TeX Live 2024)

# Which of these are real binaries, and which are links?
$ cd $(dirname $(which tex))
$ readlink tex initex etex latex pdflatex amstex csplain
           # tex prints nothing: it is a real executable
tex        # initex   -> tex
pdftex     # etex     -> pdftex
pdftex     # latex    -> pdftex
pdftex     # pdflatex -> pdftex
pdftex     # amstex   -> pdftex
pdftex     # csplain  -> pdftex

Why is it like this? Because the e-TeX extensions were absorbed wholesale into the other engines. The doc/etex/base/README shipped with TeX Live (Karl Berry, 2024) puts it bluntly: the etex executable provided in most distributions is an incarnation of pdfTeX running in DVI mode, precisely so that the extensions beyond e-TeX are available too. By the same logic latex is not “old TeX” but pdfTeX in DVI mode — run it and the banner announces This is pdfTeX, .... Substitutions like this are possible only because engine and format are independent axes.

Plain TeX: a world with no \documentclass and no \begin{document}

Plain TeX is the standard format Knuth presented in The TeXbook. It gathers a minimal toolkit — font setup, the basic mathematical symbols, convenience macros such as \bye — into plain.tex, which ships with TeX itself. Before LaTeX, this was the only practical way to use TeX. In TeX Live 2024 the tex engine dumps this format from tex.ini and stores it as tex.fmt.

The notation differs noticeably from LaTeX. Inline maths is $...$ in both, but a horizontal box is \hbox{...}, a vertical box \vbox{...}, tabular alignment is done with \halign, a command is defined with \def, the text width is \hsize, and a document ends with \bye. There is no \documentclass and no \begin{document} — LaTeX builds those out of macros. Turn that around and it says something important: LaTeX’s conveniences are features of the format, not of the engine.

latex
% plain TeX — process with: tex hello.tex  (produces hello.dvi)
\hsize=10cm
\font\big=cmr10 at 17pt
{\big Hello, plain \TeX!}
\medskip
This paragraph is set in the default font.
Inline math works too: $E = mc^2$.
\bye

Process that with tex hello.tex and you get a DVI file — not a PDF; more on that shortly. Logo macros like \TeX and spacing macros like \medskip (a medium vertical skip) are defined by plain TeX too. Set it beside a LaTeX \documentclass document and you can see just how thin a skin plain TeX puts over the bare engine.

Literate programming and WEB: how TeX’s own source is written

TeX itself is written in WEB, Knuth’s own system and the founding practice of literate programming. A WEB source is a single document in which explanation for humans and Pascal code are woven together. Two tools then extract different derivatives from it: tangle produces compilable Pascal, and weave produces the typeset commentary — the book TeX: The Program.

The original target language was Pascal; in modern distributions a tool called web2c translates the WEB (by way of Pascal) into C for building. So the pdfTeX, XeTeX or LuaTeX running on your machine today still traces back, in the end, to that single literate source. That is why the name web2c keeps turning up in TeX Live’s directory layout.

A version number converging on π, and a frozen program

TeX’s version numbering is idiosyncratic. Since version 3, each update appends one more digit, so the number asymptotically approaches π. Run tex --version on the copy shipped with TeX Live 2024 and it answers TeX 3.141592653. Its companion METAFONT does the same thing towards e, the base of natural logarithms — knowing both is what makes the joke visible.

And Knuth has declared that the “absolutely final change,” to be made after his death, will set the version to exactly π — at which point all remaining bugs become features, in his own phrasing (Donald E. Knuth, “The future of TeX and METAFONT”, NTG journal MAPS, 1990; reprinted as chapter 30 of Digital Typography). This freeze was a design decision rather than a surrender. Precisely because the foundation does not move, the formats and drivers stacked on it can evolve without fear. That a .tex file from decades ago still produces the same output today is a direct consequence.

METAFONT and DVI: why TeX does not emit PDF directly

TeX has a twin companion, METAFONT (the command mf): a system that describes a typeface not as fixed shapes but as a program for drawing the glyphs. Knuth designed the entire Computer Modern family for TeX with it. The division of labour is clean — TeX decides where the characters go, METAFONT produces the shapes of the characters themselves.

And what Knuth’s TeX emits directly is not PDF but a DVI (DeVice Independent) file. A DVI holds only device-independent instructions — “put this character at this position” — which dvips then turns into PostScript, or dvipdfmx into PDF. In 1982 PDF did not exist, so this was the obvious design; read the other way, it meant the output format could change without anyone rewriting TeX itself. The big difference in today’s widely used pdfTeX, XeTeX and LuaTeX is that they have folded that step inside and can write PDF directly.

What e-TeX is: extending a frozen program without breaking it

e-TeX is an extension that adds new primitives to frozen TeX as a strict superset. Once Knuth had frozen TeX, new features had to come from other hands. Under the auspices of DANTE e.V., the German-language TeX users’ group, the NTS (New Typesetting System) project was established in 1992, and e-TeX was its first concrete result. It was implemented by Peter Breitenlohner of the Max Planck Institute for Physics in Munich (died 2015), with Philip Taylor as the project’s coordinator. The etex.1 manual page shipped with TeX Live states the aim as perpetuating and developing the spirit and philosophy of TeX while respecting Knuth’s wish that TeX should remain frozen.

“Strict superset” means that existing input runs unchanged and produces identical output. To guarantee that, e-TeX has two modes. In compatibility mode it behaves exactly like bare TeX; only in extended mode do the added primitives become available. Which one you get is decided not at run time but when the format is built: prefixing the format’s source file with a * when dumping it selects extended mode. As the next section shows, that one-character convention is what the whole of modern LaTeX rests on.

Why you are already running e-TeX without knowing it

Because the LaTeX format is dumped in extended mode. That is not a guess; it is written down in a configuration file. Open fmtutil.cnf in TeX Live 2024 and you find the line latex pdftex language.dat -translate-file=cp227.tcx *latex.ini, where the * on *latex.ini requests extended mode — and the comment header of that same file states that this * is essentially equivalent to the -etex option. By contrast the plain TeX line reads tex tex - tex.ini: engine tex, no *. Bare TeX is the only thing left without the e-TeX extensions.

The same thing can be confirmed from the LaTeX side. Near the top of the kernel file latex.ltx sits the guard \ifx\eTeXversion\undefined \errmessage{LaTeX requires e-TeX}: without the extensions, building the format stops dead. The moment this became official is documented too — LaTeX News 16 (December 2003) announced that within about two years releases would move to assuming e-TeX, and LaTeX News 26 declared that as of the January 2017 release, e-TeX is required to build the format. The line entering extended mode on the third line of a latex run is the visible trace of that decision.

terminal
# Ask each engine whether the e-TeX primitives exist.
$ cat > probe.tex <<'EOF'
\message{[eTeX=\ifx\eTeXversion\undefined none\else\number\eTeXversion\eTeXrevision\fi]}
\count300=7  % register 300 does not exist in Knuth's TeX
\end
EOF

$ tex probe.tex          # Knuth's TeX: no extensions
[eTeX=none]
! Bad register code (300).

$ pdftex probe.tex       # pdfTeX: e-TeX 2.6 built in, 32768 registers
[eTeX=2.6]

$ latex probe.tex | head -3
This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode

That last banner is this page’s subject compressed into one line. The version string 3.141592653-2.6-1.40.26 has three layers: Knuth’s TeX is 3.141592653, e-TeX is 2.6, pdfTeX is 1.40.26 — and (preloaded format=latex) names the format. One line therefore records both the engine’s ancestry and the choice of format. Get into the habit of reading the first line of the log and the classic collaboration puzzle — “same command, different result” — resolves itself in seconds.

The primitives e-TeX added

e-TeX’s additions matter most to the people who write macros. The largest is arithmetic on integers, dimensions and glue. In bare TeX you had to juggle scratch registers for every calculation; e-TeX supplies \numexpr, \dimexpr and \glueexpr, which evaluate an expression like (a+b)*c/d on the spot and, crucially, expandably — so the value appears directly inside \edef or \write.

latex
% On any e-TeX engine in extended mode (pdftex, xetex, luatex, euptex).
\count0=\numexpr (3+4)*2/7 \relax   % yields 2

% Branch safely on whether a name is defined.
\ifdefined\foo \message{foo exists}\else \message{no foo}\fi

% Test a control sequence without creating it.
\ifcsname chapter\endcsname \message{chapter is defined}\fi

% Negate a conditional directly, instead of swapping the branches.
\unless\ifnum\count0>10 \message{count0 is not greater than 10}\fi

The second pillar is conditionals and token manipulation. \ifdefined tests whether a control sequence is defined; \ifcsname...\endcsname tests the existence of one assembled from a name. What matters about both is that they have no side effects: the older \ifx trick used in bare TeX could silently turn an undefined control sequence into \relax. \unless inverts any conditional, removing the busywork of swapping the two branches, and \detokenize turns a token list into its string form — characters of category code 12.

PrimitiveWhat it does
\numexprEvaluate an integer expression in place, expandably: \numexpr (3+4)*2/7 \relax
\dimexpr / \glueexprThe same for dimensions and for glue: \dimexpr \textwidth/3 \relax
\ifdefinedTest whether a control sequence is defined, with no side effect
\ifcsnameTest the existence of a control sequence built from a name, without creating it
\unlessInvert the sense of the following conditional: \unless\ifnum ...
\protectedDefine a macro that will not expand of its own accord inside \edef or \write
\detokenize / \unexpandedTurn a token list into a string / leave a token list unexpanded
\scantokens / \readlineRe-read a string as if it were input / read an input line verbatim
\middlePlace a stretchy delimiter in the middle of \left … \right
\currentgrouplevelReport the current group depth (\interactionmode reads and sets the interaction mode)

Expansion control was strengthened too. \unexpanded leaves its contents in place without expanding them, and \protected defines a macro that will not expand of its own accord in an expansion context. The latter is the key to implementing LaTeX’s \protect correctly at a low level, so that fragile commands survive being written into an \edef or a \write. In mathematics, \middle earns its keep: write \left( … \middle| … \right) and the vertical bar in the middle grows to the same height as the brackets on either side. Bare TeX had no notion of a mid-formula delimiter at all.

Quiet but decisive is the large increase in registers. Bare TeX had only 256 each of \count, \dimen, \skip, \toks and their kin — that is exactly what tex was refusing above with ! Bad register code (300). e-TeX raised the ceiling to 32768 and allocates them as sparse arrays, so unused ones cost no memory. Today’s LaTeX documents, loading dozens of large classes and packages, do not run out of registers because of this extension.

e-TeX also brought in machinery for bidirectional typesetting — writing systems that run right to left. That part descends from Breitenlohner’s TeX--XeT and fed into the later work in XeTeX, LuaTeX and Japanese processing. And many modern packages simply could not exist without these primitives. expl3, LaTeX’s programming layer, is the obvious example: without \ifcsname and \protected that vast macro system could not have been written at all.

What knowing this layer lets you read

You can see to the bottom of error messages. Much of what LaTeX warns about is written in the vocabulary of the layer underneath. Overfull \hbox (12.3pt too wide) says that material stuck 12.3pt out of the horizontal box that is a line; knowing \hbox is a box narrows the cause to a long URL or an unbreakable word. ! Missing number, treated as zero. says TeX expected something readable as a number or a dimension and found none — usually a mistyped length.

Reading this layer and writing in it are two different things, though. Leave headings, lists, cross-references and theorem environments to LaTeX’s structural commands, and keep the low-level ones for reading why something broke or for poking narrowly at a class. Even when defining a new command, ordinary documents are better served by \newcommand or \NewDocumentCommand than by raw \def, because those check the argument count and warn about collisions with existing commands.

  • While writing prose — use LaTeX’s structural commands and keep low-level primitives rare.
  • While fixing a class or package — e-TeX tools such as \ifdefined and \numexpr are safer and more readable than older TeX tricks.
  • While reading a log — translate warnings into TeX’s vocabulary of boxes, glue and registers and the cause comes into view.
  • When you need reproducibility — the engine is frozen, so old documents keep producing the same result. What actually moves is the version of the format and of the packages, and that is what to pin.