Creación de paquetes y clases

Abre la distribución de un paquete LaTeX y puede que no encuentres ningún .sty. Lo que hay en su lugar son dos archivos, .dtx e .ins: una realización de la programación literaria en la que el código y su comentario viven en un solo archivo. Pasa el .dtx de booktabs por docstrip e informa Lines processed: 1053 / Comments removed: 882 / Codelines passed: 161. De 1053 líneas, solo 161 son código de verdad; el otro 85 % es prosa. Dale el mismo archivo a pdflatex y esa prosa se convierte en un manual PDF compuesto. Esta página va desde reunir en tu propio .sty las macros que pegas una y otra vez en el preámbulo hasta escribir un .dtx, probarlo y publicarlo en CTAN.

El esqueleto .sty: escribir una fecha te da comprobación de versión

Un paquete es un archivo .sty, en tu proyecto o instalado en algún sitio. Sus dos primeras líneas son la presentación: \NeedsTeXFormat{LaTeX2e} indica el formato requerido y \ProvidesPackage{name}[date version description] declara el nombre del paquete y su versión. El nombre debe coincidir con el basename del archivo. La parte entre corchetes es opcional, pero escribirla reporta algo concreto: los usuarios podrán exigir una fecha mínima con \usepackage{mypackage}[2027/01/01], y una copia más antigua produce LaTeX Warning: You have requested, on input line 2, version '2027/01/01' of package mypackage, but only version '2026/08/17 v1.0 ...' is available. La fecha se escribe en forma YYYY/MM/DD. Esa única línea te ahorrará, dentro de unos años, un correo del tipo «no funciona y no sé por qué».

En el cuerpo, trae las dependencias con \RequirePackage{...}, el equivalente de \usepackage dentro de un .sty. Carga xcolor para color, tikz para dibujo, y así sucesivamente. Para decirle algo al usuario, usa \PackageWarning{name}{message}, o \PackageError{name}{message}{help} cuando no puedas continuar. Ambos toman el nombre del paquete como primer argumento, así que quien lea el registro verá de un vistazo de dónde viene el mensaje. La maquinaria para aceptar \usepackage[option]{name}\DeclareOption con \ProcessOptions, y la pareja \DeclareKeys / \ProcessKeyOptions que ofrece el núcleo actual— es común con las clases y está reunida en la página de clases. Los pasos son idénticos al escribir un paquete. El paquete kvoptions, que encontrarás en .sty más antiguos, es una generación anterior de la misma idea.

mypackage.sty
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mypackage}[2026/08/17 v1.0 My helpers]

\RequirePackage{xcolor}

\newcommand{\greet}[1][world]{Hello, \textcolor{blue}{#1}!}

\endinput

Escribir tu propio .dtx e .ins: qué significa %<*package>

El truco detrás del .dtx es casi bochornosamente simple: un % al principio de la línea separa el comentario del código. Las líneas que empiezan por % son prosa; el resto es código. Por eso un mismo archivo se lee de dos maneras. Ejecuta tex mypackage.ins y docstrip tira la prosa y escribe el .sty; ejecuta pdflatex mypackage.dtx y la prosa se compone como cuerpo mientras el código se cita con números de línea. Qué tramos se extraen lo marcan las guardas, %<*package> y %</package>, y la línea \generate{\file{mypackage.sty}{\from{mypackage.dtx}{package}}} del .ins dice: «escribe lo que haya dentro de la guarda package en mypackage.sty». Los nombres de guarda los eliges tú, de modo que un solo .dtx puede generar a la vez un .sty, un .cls y un archivo de configuración. Lo que pongas entre \preamble y \endpreamble se antepone como comentario a cada archivo generado: ahí va el aviso de licencia.

mypackage.dtx
% \iffalse meta-comment
% Copyright (C) 2026 Example Author
% This work may be distributed and/or modified under the conditions of
% the LaTeX Project Public License, version 1.3c or later.
% \fi
%
% \iffalse
%<*driver>
\documentclass{ltxdoc}
\usepackage{mypackage}
\EnableCrossrefs
\CodelineIndex
\begin{document}
\DocInput{mypackage.dtx}
\PrintIndex
\end{document}
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\ProvidesPackage{mypackage}
%<package>  [2026/08/17 v1.0 A demonstration package]
% \fi
%
% \title{The \textsf{mypackage} package}
% \author{Example Author}
% \maketitle
%
% \section{Usage}
% \DescribeMacro{\greet}
% |\greet| prints a greeting; the optional argument sets the name.
%
% \StopEventually{}
%
% \section{Implementation}
%    \begin{macrocode}
%<*package>
\RequirePackage{xcolor}
\newcommand{\greet}[1][world]{Hello, \textcolor{blue}{#1}!}
%</package>
%    \end{macrocode}
% \Finale
\endinput

El lado del comentario necesita apenas un puñado de comandos. \DocInput{archivo} es el caballo de batalla que vuelve a leer el .dtx, y el tramo cercado por %<*driver>%</driver> es la pequeña configuración de documento que lo hace (con ltxdoc). La implementación se cita dentro de \begin{macrocode}\end{macrocode}, por convención con cuatro espacios de sangría en las líneas de cierre. \DescribeMacro{\comando} destaca un comando en el texto de cara al usuario y lo registra en el índice. \StopEventually{} marca la frontera donde empieza la implementación, lo que importa al generar una versión abreviada solo para usuarios. Por último, \Finale ordena el índice y el historial de cambios. Ejecuta el .dtx anterior con un .ins de seis líneas y obtienes Lines processed: 41 / Comments removed: 24 / Codelines passed: 10, y el .sty generado se abre con la nota automática %% This is file 'mypackage.sty', generated with the docstrip utility.

mypackage.ins
\input docstrip.tex
\keepsilent
\preamble
Generated from mypackage.dtx -- do not edit this file directly.
\endpreamble
\generate{\file{mypackage.sty}{\from{mypackage.dtx}{package}}}
\endbatchfile

Un .dtx se pudre solo: booktabs ya no se compone

Hay una trampa que conviene conocer antes de ponerse: el .sty puede seguir funcionando mientras el .dtx deja de componerse. En TeX Live 2024, pdflatex booktabs.dtx lanza 127 errores y no produce PDF alguno. El primero es ! Improper alphabetic constant, y muere cerca de la \CharacterTable. Entretanto, booktabs.sty funciona a la perfección. La causa es que el suelo bajo la documentación se movió: doc.sty en TeX Live 2024 es la v3.0m, del 2022/11/13 —la «V3» reescrita por Frank Mittelbach—, mientras que booktabs.dtx sigue siendo de enero de 2020. El booktabs.pdf que viene en la distribución lleva esa misma fecha de enero de 2020 y nunca se ha regenerado desde entonces. En contraste, en el mismo TeX Live 2024, multirow.dtx (30 páginas), tabularx.dtx (12 páginas) y array.dtx (35 páginas) se componen todos sin un solo aviso: no es, pues, un defecto del mecanismo sino un problema de mantenimiento. Compila de verdad tu propio .dtx en cada versión.

No hace falta partir de una página en blanco. TeX Live incluye una introducción llamada dtxtut y, con ella, una pareja de plantillas, skeleton.dtx y skeleton.ins. Los rastros de los paquetes que empezaron copiándola sobreviven en lugares inesperados: la línea 18 de skeleton.ins dice \usedir{tex/latex/skeleton}, y la misma línea sigue en la línea 36 de booktabs.ins: el skeleton de la plantilla nunca se renombró. Al recorrer los 1402 archivos .ins bajo source/latex en TeX Live 2024, booktabs es el único que aún arrastra ese resto. Es un detalle entrañable, pero la lección es clara: si partes de la plantilla, busca su nombre antes de publicar.

Escribir en expl3: \ProvidesExplPackage

Si el cuerpo va a ser expl3, cambia la línea de identificación por \ProvidesExplPackage{name}{date}{version}{description}. Además de repartirse en cuatro argumentos, tiene otra propiedad importante: el comando termina ejecutando \ExplSyntaxOn. Así, desde la línea siguiente a la declaración la sintaxis expl3 está disponible sin que hayas escrito nunca \ExplSyntaxOn. El .sty de abajo no contiene ni una sola aparición, y sin embargo tanto \tl_new:N como \NewDocumentCommand funcionan tal cual. Cómo leer expl3 en sí está en la página de expl3.

expldemo.sty
\NeedsTeXFormat{LaTeX2e}
% four arguments, and it turns on expl3 syntax by itself
\ProvidesExplPackage{expldemo}{2026/08/17}{1.0}{Expl demo}

\tl_new:N \l_expldemo_tl
\tl_set:Nn \l_expldemo_tl { from~expl3 }

\NewDocumentCommand \shout { } { \tl_use:N \l_expldemo_tl }

Probar y construir la distribución: l3build

En vez de teclear tex mypackage.ins y pdflatex mypackage.dtx a mano cada vez, puedes delegar el trabajo en l3build, mantenido por el LaTeX Project (la copia de TeX Live 2024 es la publicación del 2024-02-08). Pon un build.lua en la raíz del proyecto con el nombre del módulo y sus archivos: l3build unpack ejecuta el .ins y deja el .sty en build/unpacked/, mientras que l3build doc compone el .dtx en un PDF bajo build/doc/. La ventaja es que nada de lo generado ensucia tu directorio de trabajo. l3build check es el banco de pruebas: coteja documentos de prueba .lvt con archivos .tlg de salida de registro esperada en testfiles/ y te muestra una diferencia en cuanto la salida cambia. Cuando el resultado compuesto lo custodia la máquina y no el ojo, refactorizar deja de dar miedo.

build.lua
module       = "mypackage"
sourcefiles  = {"mypackage.dtx", "mypackage.ins"}
installfiles = {"mypackage.sty"}
uploadconfig = { pkg = "mypackage" }

-- l3build unpack   -> build/unpacked/mypackage.sty
-- l3build doc      -> build/doc/mypackage.pdf
-- l3build check    -> run testfiles/*.lvt against *.tlg
-- l3build ctan     -> mypackage-ctan.zip, ready to upload

Publicar en CTAN: qué va en el zip y la licencia

Ejecuta l3build ctan y obtienes un único zip listo para subir. Dentro hay un directorio con el nombre del paquete, mypackage/, que contiene los fuentes (.dtx e .ins) y el manual PDF compilado. No incluir el .sty es la costumbre en este mundo; quien reciba el archivo lo genera desde el .ins. Añade un README y un registro de cambios y la forma queda correcta. Ojo, eso sí: l3build ctan recoge los PDF que encuentre en el directorio de trabajo, así que las pruebas de impresión sueltas se empaquetan junto con todo — lista el archivo con unzip -l después de construirlo y compruébalo. La subida en sí se hace por el formulario web de CTAN, pero TeX Live incluye también ctan-o-mat, que valida y sube desde la línea de comandos usando un archivo de configuración con la descripción, los datos de contacto y la licencia.

Hay que decidir una licencia. CTAN pide que se declaren las condiciones de distribución, y la elección aparece también en la información de paquete de TeX Live. El estándar de facto de este mundo es la LPPL (LaTeX Project Public License); cómo elegir y en qué se diferencian las versiones —en particular dónde vive realmente la cláusula de «renómbralo si lo modificas»— se expone en la página de la licencia. Escribe las condiciones que adoptes en tres sitios: el metacomentario al principio del .dtx, el \preamble del .ins (que encabeza cada archivo generado y llega, por tanto, a quien solo recibió el .sty) y el README. Llegado ahí, tu paquete se convierte en algo que un desconocido podrá abrir con texdoc dentro de unos años.

  • Escribe siempre la fecha de \ProvidesPackage como YYYY/MM/DD. Sin ella los usuarios no pueden exigir una versión.
  • Compila el .dtx cada vez. Que el .sty siga funcionando mientras el .dtx falla ocurre de verdad: mira booktabs.
  • Si partes de la plantilla, busca su nombre. Un resto de skeleton sigue vivo en TeX Live 2024.
  • Revisa el zip de l3build ctan con unzip -l. Recoge los PDF que anden por el directorio de trabajo.
  • Declara la licencia en tres sitios: el .dtx, el \preamble del .ins y el README. Tiene que llegar a quien solo recibió el .sty.