An alternative markup language for man pages
3 min read
While developing many of my projects I've found myself faced with the timeless question: to document or not to document? My goal is to provide man pages for any project used from the command-line or designed to be integrated into a larger Linux ecosystem. And so, at the onset of my open-source journey, I stood at a crossroad: learn the unwieldy troff format of man pages or set up a process to build them from an alternative markup format.
This is an excerpt from the time command's man page written in troff:
.TH TIME 1 2019-03-06 "" "Linux User's Manual" .SH NAME time \- time a simple command or give resource usage .SH SYNOPSIS .B time \c .RI [ options ] " command " [ arguments... ] .SH DESCRIPTION The .B time command runs the specified program .I command with the given arguments.
From my perspective, an alternative is necessary. The markup syntax is cryptic and what would be inline markup in other formats requires a newline in troff.
There are numerous means of generating man pages from assorted markup formats. For example, using:
reStructured text with rst2man,
AsciiDoc format with AsciiDoc itself,
or Pod with pod2man
to name a few.
Admittedly, I'd enjoy writing man pages in Markdown, but in approaching the question of an appropriate build pipeline, I decided early on that I'd like to avoid any external dependencies. This eliminates most options, but the pod2man command is available by default in the Linux distributions I've used. With this in mind, Perl's Pod, or Plain Old Documentation, is the top contender.
Here's an example of a Pod-formatted man page from my iniq project:
=head1 NAME iniq - INI file reader =head1 SYNOPSIS B<iniq> [options] [FILE] With no FILE, read standard input. =head1 DESCRIPTION iniq is a simple INI file reader for the command line. It queries an INI file based on the path <I<section>><I<separator>><I<key>> and allows use of custom separators in the file and formatting of the output. Sections inherit keys from a special DEFAULT section unless the I<-D> flag is used. See below for examples. =head1 OPTIONS =over =item B<-h> Show help message.
Compared to troff, this is both easier to write and to read, which are important qualities in the maintenance of documentation.
.pod files to man pages
Producing a man page from a
.pod file is straightforward using the pod2man command. In most of my projects, this step is part of a
In the case of iniq, these
Makefile rules build and install its man page:
VERSIONCMD = git describe --dirty --tags --always 2> /dev/null VERSION := $(shell $(VERSIONCMD) || cat VERSION) PREFIX ?= /usr/local MANPREFIX ?= $(PREFIX)/share/man MANPAGE = iniq.1 $(MANPAGE): man/$(MANPAGE).pod pod2man -n=iniq -c=iniq -s=1 -r=$(VERSION) $< $(MANPAGE) install: $(MANPAGE) mkdir -p $(DESTDIR)$(MANPREFIX)/man1 cp -p $(MANPAGE) $(DESTDIR)$(MANPREFIX)/man1
The conversion command:
pod2man -n=$name -c=$header -s=$section -r=$footer $input $output
takes the input
.podfile as its first positional argument,
and the output file name as its second;
-nflag sets the man page name,
-cflag sets the page header,
-sflag sets the section, which should match the output file's extension,
-rflag sets the page footer, which in my projects is always the version.
Descriptions of pod2man's various options can be found here or in its man page using
man pod2man; and with that we've come full circle!