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.
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 the mypackage
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
or sys.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.
.sty
file is already enough. See Make your own .sty files for the minimal set of headers (which are also technically optional, but should be added to any real package).