Generate a man page for a Swift command-line tool

Generate a man page for a Swift command-line tool

This blog post will teach you how to generate a manual page for your Swift command-line tool using Apple's swift-argument-parser. I will also teach you how to ensure that the man page will be installed along your command-line tool.

I'll use my command-line tool swiftplantuml as a concrete example.

What is a man page

A man page (short for manual page) is a form of software documentation usually found on a Unix or Unix-like operating system. Topics covered include computer programs (including library and system calls), formal standards and conventions, and even abstract concepts. A user may invoke a man page by issuing the man command.

Example

manual page for swiftplantuml

Generate a man page

Apple's ArgumentParser includes a SwiftPM plugin for generating man pages with version 1.1.4.

Make sure you are declaring 1.1.4 in your Package.swift manifest as dependency:

dependencies: [
    .package(
      name: "swift-argument-parser",
      url: "https://github.com/Apple/swift-argument-parser.git",
      from: "1.1.4"
    ),
],

You can create a single main page including all subcommands:

swift package plugin generate-manual

Or you create multiple man pages, one per subcommand:

swift package plugin generate-manual --multi-page

The generated man page(s) can be found in folder .build/plugins/GenerateManualPlugin/outputs

When running the command for my command-line tool swiftplantuml then the file swiftplantuml.1 gets generated in .build/plugins/GenerateManualPlugin/outputs/swiftplantuml

Viewing a man page

The man command to view a man page will search in various directories.

man swiftplantuml

If the requested man page was not found then you will see a message like this:

No manual entry for swiftplantuml

Installing a man page

I recommend you copy the generated man page to /usr/local/share/man/man1/ as /usr/local/share/man is part of the search path for man pages on Mac.

Note: You might have to create this directory. You can do so with mkdir -p /usr/local/share/man/man1

You can automate and make this step part of your tool installation.

For example, SwiftPlantUML offers a Makefile which can be used by tools like Homebrew to streamline the installation process. In SwiftPlantUML's Makefile I install not only the tools binary but also the man page. Below I share a snippet out of my Makefile:

install-man-files: $(SOURCES)
    mkdir -p ${DESTDIR}${mandir}/man1
    cp $(REPODIR)/man/swiftplantuml.1 ${DESTDIR}${mandir}/man1/swiftplantuml.1

build-swiftplantuml: $(SOURCES)
    @swift build \
        -c release \
        --disable-sandbox \
        --build-path "$(BUILDDIR)"

.PHONY: install
install: build-swiftplantuml
    @install -d "$(bindir)"
    @install "$(wildcard $(BUILDDIR)/**/release/swiftplantuml)" "$(bindir)"
    @make install-man-files

You may notice that I don't generate the man page with the SPM plugin during make install. I previously generated and then checked-in the file, in a folder named man, in Git. Why? Because I don't want to make Xcode 13.3 (= Swift 5.6 in which SPM introduced plugins) a requirement for installation.

I even revert to a dependency < 1.1.0 as ArgumentParser@1.1.0 and higher will require Swift 5.5. (Xcode 13 => macOS 11.3) and SwiftPlantUML shall be buildable from source from lower OS versions.

Man page vs help

You might ask: "What is the advantage of man pages over the generated help option?"

I raised the raise question in Swift Forums ⬇️

I leave you with the following answer:

Overall, man pages are simply the standard, conventional way of providing documentation for command line tools. Sticking to that convention makes your docs more easily accessible and useful, even if they have the same content as a --help.

Did you find this article valuable?

Support Marco Eidinger by becoming a sponsor. Any amount is appreciated!