Compilaciones automatizadas

«Rerun to get cross-references right.» LaTeX es uno de los pocos sistemas de composición tipográfica en los que ejecutar el compilador una sola vez no basta para obtener el resultado correcto. Las referencias cruzadas, el índice y las citas solo se escriben en archivos en la primera pasada, así que una herramienta de compilación automatizada como latexmk repite las idas y vueltas hasta que la salida se estabiliza. Esta página parte de por qué hacen falta varias compilaciones y después recorre latexmk -pdf, el modo -pvc que recompila cada vez que se guarda, las limpiezas -c y -C, el archivo de configuración latexmkrc y las alternativas: arara, llmk y make.

Por qué LaTeX necesita más de una compilación

La respuesta es sencilla: LaTeX lee el documento una sola vez, de principio a fin. Cuando compone el índice en la página uno, todavía no sabe en qué página caerá la sección 7. Por eso anota lo que va averiguando —el número de sección y de página de cada etiqueta, las líneas del índice, las claves de cita— en archivos auxiliares como .aux, .toc, .lof y .lot, y los vuelve a leer al empezar la pasada siguiente. La salida se compone, pues, siempre con lo que descubrió la pasada anterior. Justo por eso el primer PDF muestra un índice vacío y ?? en lugar de las referencias.

Aquí se esconde un mecanismo ingenioso: LaTeX no cuenta cuántas pasadas faltan. Al llegar a \end{document} compara el valor que acaba de calcular para cada etiqueta con el que leyó del .aux de la pasada anterior, uno a uno, y si uno solo difiere imprime LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right. Dicho al revés: que ese aviso desaparezca es la señal de que el archivo .aux ha dejado de cambiar, es decir, de que el documento ha alcanzado un punto fijo. Que un documento esté terminado no lo decide el aspecto de las páginas, sino la coincidencia de esos archivos auxiliares.

text
% doc.aux -- what one run leaves behind for the next one to read
\@writefile{toc}{\contentsline {section}{\numberline {1}One}{1}{}}
\newlabel{sec:one}{{1}{1}{}{}{}}

% doc.log -- the first run, before the .aux settles
LaTeX Warning: Reference `sec:two' on page 1 undefined on input line 5.
LaTeX Warning: There were undefined references.
LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.

Añadir una bibliografía alarga aún más ese ir y venir. Las claves que pide \cite se anotan en el .aux en la primera pasada; bibtex o biber lee ese archivo y produce un .bbl; la segunda pasada incorpora el .bbl; y hace falta una tercera para corregir las referencias cuyos números se han desplazado. Esa es toda la historia detrás del conocido conjuro latex → bibtex → latex → latex. Un índice inserta además makeindex en la misma cadena. Mientras se haga a mano, hay que volver a decidir cada vez hasta dónde retroceder.

latexmk: un solo comando para todo el bucle

Basta escribir una línea: latexmk -pdf document.tex. A partir de ahí latexmk vigila los cambios del archivo .aux, ejecuta pdflatex tantas veces como haga falta, llama a bibtex/biber y a makeindex en el orden adecuado por el camino y se detiene en cuanto desaparecen los avisos. La herramienta tiene una genealogía peculiar: empezó como un pequeño script llamado go, escrito por David J. Musliner. Evan McLean lo convirtió en latexmk y desde entonces lo mantiene en Perl John Collins, físico de Penn State University; en una instalación de TeX Live 2024, latexmk -v responde «Latexmk, John Collins, 31 Jan. 2024. Version 4.83.». Viene con TeX Live y con MiKTeX, así que normalmente no hay nada que instalar.

terminal
$ latexmk -pdf doc.tex
Latexmk: applying rule 'pdflatex'...
Run number 1 of rule 'pdflatex'
Running 'pdflatex  -recorder  "doc.tex"'
Latexmk: References changed.
Latexmk: applying rule 'pdflatex'...
Run number 2 of rule 'pdflatex'
Running 'pdflatex  -recorder  "doc.tex"'
Latexmk: All targets (doc.pdf) are up-to-date

El -recorder que aparece en esa salida lo añade el propio latexmk. Con esa opción, el motor TeX escribe un archivo .fls con la lista de todo lo que esa ejecución leyó y escribió; latexmk lo contrasta con el registro para deducir las dependencias y guarda el estado de cada archivo en una base de datos llamada .fdb_latexmk. Lo decisivo es el criterio: latexmk compara sumas de comprobación del contenido, no fechas de modificación. Su manual explica el motivo sin rodeos. Un archivo escrito durante una ejecución de LaTeX es siempre posterior al que se leyó justo antes, de modo que, mirando solo las marcas de tiempo, parece perpetuamente desfasado. Esa dependencia circular, señala el manual, es propia de LaTeX, y latexmk se programó precisamente para superarla. También hay una red de seguridad: si el documento no se estabiliza tras $max_repeat ejecuciones —cinco por omisión— latexmk supone un bucle infinito y se detiene.

-pdf, -lualatex, -xelatex: elegir el motor

-pdf elige pdflatex, -lualatex elige lualatex y -xelatex elige xelatex. Sin ninguna opción, latexmk sigue haciendo lo que hacían sus primeras versiones y produce un .dvi, así que en cuanto se quiera un PDF hay que indicar una de ellas. Hay aquí un detalle que conviene conocer: incluso con -xelatex, latexmk no deja que xelatex escriba el PDF directamente. Primero genera un archivo intermedio .xdv, completa sobre él todas las repeticiones y solo entonces llama una vez a xdvipdfmx. Con gráficos .png grandes la etapa de PDF es lenta, y así no hay que reincrustar las imágenes en cada pasada. -lualatex abrevia -pdflua -dvi- -ps-, y -xelatex abrevia -pdfxe -dvi- -ps-. Para una ruta que pase por DVI, como la pareja japonesa upLaTeX + dvipdfmx, se elige -pdfdvi.

OpciónQué haceCuándo usarla
-pdfgenera el PDF con pdflatexcaso estándar de documentos en alfabeto latino
-lualatexgenera el PDF con lualatex (igual que -pdflua -dvi- -ps-)fuentes OpenType o extensiones escritas en Lua
-xelatexhace que xelatex produzca un .xdv y al final llama a xdvipdfmxcuando se usan directamente las fuentes del sistema
-pdfdvicrea primero un .dvi y lo convierte a PDFrutas por DVI como upLaTeX + dvipdfmx
-pvcvigila las fuentes y recompila con cada cambiomientras se escribe, para ver el resultado en cada guardado
-pvctimeouttermina -pvc tras un periodo de inactividad (30 minutos por omisión)para no dejar el proceso corriendo sin supervisión
-cborra los intermedios regenerables y conserva el PDFpara ordenar el directorio de trabajo
-Chace -c y además borra .dvi, .ps y .pdfdemostrar una compilación limpia; preparar una entrega
-gglimpia como haría -C y después compila normalmentereconstrucción desde cero en un solo comando
-fcontinúa el procesado pese a los errorescuando se quiere todo el registro de una vez
-silentreduce la salida del motor (igual que -quiet)para mantener legibles los registros de CI
-rlee además un archivo de configuración indicadopara compilar puntualmente por otra ruta

Recompilar cada vez que se guarda: latexmk -pvc

-pvc significa «preview continuously»: latexmk queda residente con un visor abierto y vuelve a ejecutar todo el bucle en cuanto cambia cualquier archivo fuente. Lo que vigila no es solo el .tex principal. La lista de dependencias construida a partir del .fls se convierte en la lista de vigilancia, de modo que los archivos de capítulo incorporados con \input/\include, los gráficos insertados y el archivo .bib quedan incluidos. La sensación es la de un servidor de desarrollo para un documento. Trae algunas manías: -pvc solo funciona con un archivo y es incompatible con -p y -pv. Este modo también desactiva el modo forzado -f; para combinarlos de veras hay que escribirlos en el orden -pvc -f. Por sí solo no termina nunca; es -pvctimeout quien añade un tiempo de espera por inactividad, fijado por omisión en 30 minutos (-pvctimeoutmins= lo cambia y -pvctimeout- vuelve a quitarlo). El visor también importa: el manual advierte de forma explícita de que acroread en MS-Windows bloquea el archivo PDF e impide escribir versiones nuevas, así que es una mala elección para la vista previa continua.

terminal
latexmk -pdf -pvc doc.tex                 # watch the sources, rebuild on every save
latexmk -pdf -pvc -pvctimeout doc.tex     # same, but give up after 30 idle minutes
latexmk -lualatex -pvc doc.tex            # the same loop, driven by lualatex

El botón de «compilar al guardar» de un editor suele ser latexmk por debajo. LaTeX Workshop para VS Code, TeXstudio, TeXShop, AUCTeX en Emacs, Overleaf: los nombres cambian, pero lo que se ejecuta es o bien el mismo comando, o bien una implementación interna de la misma idea. Conocer -pvc en la terminal ofrece, por tanto, un punto de repliegue: al bajar al comando desnudo cuando el editor se porta mal, se distingue si la culpa es del documento o de la configuración. Si solo falla la compilación del editor mientras latexmk sí pasa, el sospechoso son los ajustes del editor, no el documento.

latexmk -c frente a -C: limpiar los archivos generados

La diferencia está en un solo punto: si el PDF sobrevive o no. -c borra los archivos regenerables —.aux, .log, .toc, .fls, .fdb_latexmk y compañía— pero conserva .dvi, .ps y .pdf. -C borra también esas salidas. Para limpiar y reconstruir de una sola vez está -gg. Esto importa en la práctica porque un .aux caducado tapa los accidentes. Basta reordenar unas secciones o borrar un \label para que el PDF de la propia máquina siga saliendo verosímil, porque los valores antiguos siguen ahí, mientras que un coautor que acaba de clonar el repositorio, o la CI, obtiene una compilación rota. Ejecutar latexmk -C y ver después que latexmk -pdf termina bien es, antes de entregar, la prueba de que el documento se puede componer realmente solo a partir de sus fuentes.

terminal
latexmk -c                  # remove aux, log, toc, fls, fdb_latexmk ... keep the PDF
latexmk -C                  # remove all of that plus the dvi / ps / pdf output
latexmk -gg -pdf doc.tex    # clean first, then build again from scratch

Escribir la compilación en un archivo latexmkrc

Basta colocar junto al documento un archivo llamado latexmkrc o .latexmkrc para que quien escriba latexmk en ese directorio siga la misma ruta. Al arrancar, latexmk lee en este orden: el archivo del sistema, después el $HOME/.latexmkrc del usuario (o $XDG_CONFIG_HOME/latexmk/latexmkrc), después latexmkrc o .latexmkrc del directorio actual y, por último, lo que se indique con -r. Lo leído más tarde gana, así que la configuración del proyecto pisa las preferencias individuales. El contenido es código Perl, # inicia un comentario y en la mayoría de los casos bastan unas pocas asignaciones de variables. En trabajo colaborativo, incluir este archivo en el repositorio y convertirlo en el acuerdo —«este documento se construye así»— es lo que menos discusiones genera.

perl
# latexmkrc -- lives next to the document and is committed with it

$pdf_mode = 4;           # 4 = build the PDF with lualatex
$max_repeat = 7;         # allow a couple of extra passes on a long document

# Alternative route: upLaTeX -> DVI -> dvipdfmx
# $latex    = 'uplatex -interaction=nonstopmode -halt-on-error %O %S';
# $dvipdf   = 'dvipdfmx %O -o %D %S';
# $pdf_mode = 3;         # 3 = make the PDF from the DVI file

# Extra extensions that -c and -C should remove as well.
$clean_ext = 'synctex.gz run.xml bcf';

Alternativas a latexmk: arara, llmk, make

La línea divisoria se reduce a una pregunta: quién decide la secuencia de pasos. latexmk la deduce de los registros y las dependencias. arara, en cambio, no deduce nada. Lee directivas escritas en el propio documento —una línea de comentario como % arara: pdflatex— y ejecuta exactamente lo que está escrito, en el orden en que está escrito. Como dice su ficha en CTAN, arara determina sus acciones a partir de metadatos del código fuente y no de recursos indirectos como el análisis del archivo de registro. Lo desarrolla Island of TeX en torno a Paulo Roberto Massa Cereda y necesita Java para funcionar. llmk (empaquetado en TeX Live como light-latex-make, obra de Takuto Asakura) va aún más lejos en lo declarativo: el flujo se escribe en llmk.toml o en un campo TOML del código fuente, y solo requiere texlua; el diseño antepone que el resultado sea idéntico en cualquier entorno.

latex
% arara directives: the document itself states the workflow
% arara: pdflatex
% arara: biber
% arara: pdflatex
% arara: pdflatex
\documentclass{article}
toml
# llmk.toml -- next to the document; "source" is required in this file
source = "doc.tex"
latex = "lualatex"
bibtex = "biber"
sequence = ["latex", "bibtex", "latex", "latex"]

¿Y make a secas? Un Makefile puede dirigir LaTeX sin problema, pero make decide por fecha de modificación. Como el archivo .aux se reescribe en cada ejecución, las marcas de tiempo lo sitúan siempre después del que se leyó y, por tanto, perpetuamente desfasado. Es justo en ese punto donde el manual de latexmk afirma que esa dependencia circular es propia de LaTeX y que latexmk se escribió para superarla. Si aun así se opta por make, lo practicable es guardar una copia del .aux para compararla, o sencillamente llamar a latexmk desde el objetivo del Makefile. De hecho, muchísimos Makefiles de proyecto se reducen a una línea: latexmk -pdf $<.

HerramientaCómo se deciden los pasosDónde vive la configuraciónRequiere
latexmkdeducidos del registro, del .fls y de las sumas de comprobaciónlatexmkrc / .latexmkrc (Perl)Perl; viene con TeX Live y MiKTeX
ararase ejecutan tal como dicen las directivas del documentocomentarios % arara: en el documentoJava
llmksigue la sequence declarada en TOMLllmk.toml o un campo TOML en la fuentesolo texlua
makese deciden por fechas de modificación; flojo ante el ciclo del .auxMakefilemake; ya presente casi en todas partes

Qué comando usar al escribir, al compartir y al entregar

La elección se reduce a tres momentos. Mientras se escribe, vigilar con -pvc y mirar el resultado en cada guardado. Antes de entregar el documento a alguien, ejecutar una vez latexmk a secas. Justo antes de la entrega, borrarlo todo con latexmk -C y volver a compilar. Es sobre todo ese último paso, convertido en costumbre, el que evita el accidente clásico: descubrir en la fecha límite que el documento solo compila en la propia máquina. Y en cuanto los ajustes quedan fijados en latexmkrc y versionados, el servidor de CI y cada coautor siguen la misma ruta, con lo que la discusión de «a mí me funciona» ni siquiera llega a plantearse.

  • Mientras se escribelatexmk -pdf -pvc doc.tex: recompila automáticamente en cada guardado; añade -pvctimeout si no debe quedarse funcionando sin supervisión.
  • Fijar el motor → definir $pdf_mode y compañía en latexmkrc y versionarlo para que todos lo compartan.
  • Antes de pasárselo a un coautor → ejecutar una vez latexmk -pdf a secas y comprobar que no queda ningún LaTeX Warning: Label(s) may have changed..
  • Justo antes de entregar o publicarlatexmk -C para borrarlo todo y luego una compilación limpia; latexmk -gg -pdf doc.tex hace las dos cosas de golpe.
  • Compilar en un servidor o en CI → consulta la página de CI; -silent mantiene legibles los registros.