How do I create a LaTeX package?
These are three related but different questions. We have already got some good answers on this site. So perhaps let's take this place to summarize it.
This answer is community wiki, so feel free to edit it. Of course you can add more information than site links.
Starting package writing
- Where do I start LaTeX programming?
- Classes and packages – what's the difference?
- Make your own .sty files
- Style/class tutorials
- Reference guide to begin writing a class and/or a package
Documenting packages
- How do I document my style files?
- Packages for documenting self written packages (sty-files)
- What is the gold standard of package documentation?
Publishing packages
- How does one publish/promote a new package?
- How can I contribute to CTAN?
- What is good practice when preparing a package for CTAN?
- How to upload my packages or document classes to CTAN?
- CLI tool to upload to CTAN
I've spent around a day trying to build my own package. Not impressed by the vast amount of sorry, but your princess is in another castle; I've decided to write up my findings. This is an MCVE "Hello, World!" project, and has taken some shortcuts to keep code size and answer size down.
The answer will help you understand what plugs together and how. It will also show you how to run your package locally, so you can sanity check your TeX installation and your package.
Starting point
I'll start this by showing what my TeX would look like without using a package.
The aim of the package is to move the definition of \hello
into a package called mypackage
.
document.tex
\documentclass{article}
\newcommand{\hello}{Hello, World!}
\begin{document}
\hello
\end{document}
I managed to achieve this goal, and by the end of this answer you too can use the following TeX.
package.tex
\documentclass{article}
\usepackage{mypackage}
\begin{document}
\hello
\end{document}
Making a package
The package file
There are two types of packages; styles (.sty
) and classes (.cls
). For this we'll be making a style. When writing your own style or class I'd recommend looking at Wikibooks' Creating Packages page.
Versions in LaTeX are generally provided as dates in the ISO 8601 date format, YYYY/MM/DD. And so when you specify both the TeX and your package version you should enter both in that form.
mypackage.sty
\NeedsTeXFormat{LaTeX2e}[1994/06/01]
\ProvidesPackage{mypackage}[2020/02/28 1.0.0 Tutorial project]
\newcommand{\hello}{Hello, World!}
\endinput
The above is the style file I made.
\NeedsTeXFormat
specifies which version of TeX is required, with the version (date) also specified.\ProvidesPackage
specifies what package we are defining. I have:- Called the package
mypackage
, Set the TeX version to todays date,
2020/02/28
Specified the version in Semantic Versioning
1.0.0
Added a short description of the project.
Tutorial project
- Called the package
\newcommand
defines the wanted\hello
command.\endinput
signals the end of the style file.
Install it locally
It's best if you sanity check the code. And so we can install the package locally. This is required to know, if you need to install your own or another persons package.
- Find where your TEXMF folder is.
Make the folders required by the TeX Directory Structure, TDS, standard.
Since we're making a LaTeX project, we'll place it in
texmf/tex/latex
. And to keep the folder clean, we'll place our package in themypackage
folder.Copy your package to the newly created folder.
In the shell it would look something like this.
Note: Ensure you change %USERPROFILE%/texmf
to whatever your output is.
$ kpsewhich -var-value=TEXMFHOME
%USERPROFILE%/texmf
$ mkdir %USERPROFILE%/texmf/tex/latex/mypackage/
$ cp mypackage.sty %USERPROFILE%/texmf/tex/latex/mypackage/
If your package isn't found, because your TeX isn't TDS compliant, then you can tell TeX where it is.
$ texhash %USERPROFILE%/texmf
Testing the package
We can now run package.tex
and it outputs "Hello, World!" as expected.
Documenting it
Converting from sty to dtx
The standard for documenting TeX projects is through dtx. This is some black magic that houses both the documentation and the package at the same time. To achieve this feat, the code contains a vast amount of comments and requires an installer.
The ins file extracts the information from the dtx and builds the sty or cls file.
The code is mostly boilerplate.
mypackage.ins
\input docstrip.tex
\keepsilent
\usedir{tex/latex/mypackage}
\generate{\file{mypackage.sty}{\from{mypackage.dtx}{package}}}
\Msg{Please move mypackage.sty to a TDS directory}
\endbatchfile
- You should change all occurrences of
mypackage
to the name of your package. You can change
\Msg
to whatever you want.
You can also include additional messages if you want the message split over multiple lines.Think
print
,echo
orsys.stdout.write
.
Making the dtx
To build the documentation, you run TeX on the dtx file. Just like you do with any other TeX document.
mypackage.dtx
% \iffalse
%<package>\NeedsTeXFormat{LaTeX2e}[1994/06/01]
%<package>\ProvidesPackage{mypackage}[2020/02/28 1.0.0 Tutorial project]
%<*driver>
\documentclass{ltxdoc}
\usepackage{mypackage}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
\DocInput{mypackage.dtx}
\end{document}
%</driver>
% \fi
%
% \begin{macro}{\hello}
% This is the function to display "Hello world!"
% \begin{macrocode}
\newcommand{\hello}{Hello world!}
% \end{macrocode}
% \end{macro}
\endinput
When the file is run through TeX, it evaluates the section from \documentclass
through \end{document}
, much like any other TeX file. If you comment out the \DocInput
line then you just get an empty file.
The magic happens when \DocInput
runs. This evaluates the file a second time, this time removing the comments from the file. The \iffalse
and \fi
cause the entire first section to not be run on the second evaluation, preventing \DocInput
from running a second time, and preventing \NeedsTeXFormat
from running ever.
From here, the rest of the file is simple.
%<package>
is a special comment which includes the line, uncommented, in sty.
This is as we specified it,package
, in the ins.\generate{\file{mypackage.sty}{\from{mypackage.dtx}{package}}}
Note: Do not put a space between
%
and<
otherwise it won't be included.\begin{macro}
documents the macro with the following line as the description.\newcommand{\hello}{...}
is exported to the sty.\endinput
is exported to the sty.
Install it locally
To install the package we need to run the ins to extract the sty from the dtx.
After extracting the sty, we then just install it as we did before.
In the shell this would look something like this.
$ tex mypackage.ins
$ cp mypackage.sty %USERPROFILE%/texmf/tex/latex/mypackage/
You can also see the documentation by running the dtx.
$ pdflatex mypackage.dtx
$ ./mypackage.pdf
Publishing
Now that you know what sty, cls, ins and dtx files are, and how to install them, understanding how to publish your TeX package is really simple. And the links provided by Stefan Kottwitz's answer can better describe this.
Going forward
I'd like to restate that this is an MVCE of how to make and install your own documented package. And so I've cut corners and not covered half the tooling available.
- Wikibooks has a more complete description on how to build a sty or cls.
- Scott Pakin's How to Package Your LaTeX Package on how to write your own dtx and ins.
- The links in Stefan Kottwitz's answer, as now you should have enough understanding of the entire system to understand the posts individually.