An alternative markup language for man pages

An alternative markup language for man pages

James Reed's photo
James Reed
·Jan 30, 2022·

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:

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 depedencies. 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.

Converting .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 Makefile.

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 .pod file as its first positional argument,
  • and the output file name as its second;
  • the -n flag sets the man page name,
  • the -c flag sets the page header,
  • the -s flag sets the section, which should match the output file's extension,
  • the -r flag sets the page footer, which in my projects is always the version.

More information

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!

 
Share this