Collected Markdown Makefile Wisdom

November 20, 2008

I’ve collected a few examples of Makefile rules that use various implementations of Markdown to generate XHTML from plain text files.

First, Hans Fugal offers the following Markdown Makefile Idiom:

all: $(patsubst %.txt,%.html,$(wildcard *.txt))
%.html: %.txt header.html footer.html
    cat header.html > $@
    markdown $< >> $@
    cat footer.html >> $@

This one is pretty standard. The patsubst macro is used to generate the list of .html targets from the filenames of all .txt files in the directory. It processes all of the .txt files using Markdown and applies a header and footer.

P. Damian Cugley wrote up some notes on using Markdown and Make to maintain a bunch of documents. He provides the following Make rules:

MARKDOWN = markdown
txtFiles = index.txt

all: $(txtFiles:.txt=.html)

clean:
    rm -f $(txtFiles:.txt=.html)

.SUFFIXES: .txt .html
.txt.html:
    $(MARKDOWN) < $< > $@

This version is much like the previous one except that it doesn’t perform any globbing–one has to list the txtFiles manually. However, the best part of this example is the more advanced version that follows (see the link). It uses a clever sed script to wrap a header and footer around the output, using the first h1 element on the page as the title.

The Pandoc source code includes the Markdown source for the website and a Makefile for building it. It is complicated by the fact that it also automatically runs some demos, but abstracting away from that it basically does the following:

ALL := index.html README.html INSTALL.html examples.html
PANDOC_PATH ?= $(dir $(shell which pandoc))
MAKEPAGE = $(PANDOC_PATH)/pandoc -s -S -H css -A footer.html

%.html : %.txt css
    $(MAKEPAGE) $< > $@

Here, Pandoc’s -s flag results in a standalone XHTML document with an appropriate header and footer. The -H flag includes the contents of a file before the document body while -A works similarly at the end of the document.

A project called Obi has a documentation Makefile which processes pages with Markdown but calls xsltproc using the stylesheet template.xslt which takes the text of the first h1 tag to use as the title.

XSLT =          xsltproc
PERL =          perl
MARKDOWN =      markdown
INDENT =        xmllint --format
STYLESHEET =    template.xslt
HTML_FILES =    blocks.html events.html index.html manual.html plan.html

all: $(HTML_FILES)

%.html: %.txt
    echo "<markdown>" > $@.markdown && \
    $(MARKDOWN) $< >> $@.markdown && \
    echo "</markdown>" >> $@.markdown && \
    $(XSLT) $(STYLESHEET) $@.markdown | $(INDENT) - > $@ && \
    $(RM) $@.markdown

.PHONY: clean

clean:
    $(RM) *.markdown $(HTML_FILES)

Finally, the rngzip Makefile contains the following:

DOCS := README INSTALL USAGE CAVEATS COPYING
DOCS_HTML := $(addprefix doc/,$(addsuffix .html,$(DOCS)))

MARKDOWN = libs/markdown/Markdown.pl
doc/%.html: % doc/head doc/foot
    (cat doc/head; perl $(MARKDOWN) <$*; cat doc/foot) \
      | recode -d u8..h4 >$@

This example groups the header, body, and footer and pipes everything to recode to convert the entities from UTF–8 to HTML4. This construct might be useful for other types of processing as well (e.g., tidy).