home | tech | misc | code | bookmarks (broken) | contact | README


make (portable) notes

This page is about techniques for building your Makefile in a portable way. This tips can be used for different flavours of make. For specific NetBSD make tips, please see the bmake notes (NetBSD make) page.

Dependencies that are needed for a file but are not needed to generate it

I have a RST (reStructuredText) file that will be converted to HTML. The main file main.rst include other files:

.. include:: dep.rst

foo
bar

Makefile is used to generate the resulting HTML file:

all.html: all.rst dep.rst
        rst2html $> $@

The problem is that $> expands to all dependencies, not the first one.

It is actually more complex than that. I want to parse dep.rst separately by a parser of myself that checks the validity of blocks of code. So, my actual Makefile looks like that:

all.html: all.rst
        rst2html $> $@

all.rst: dep.rst

dep.rst:
        check $@

This approach has a problem: it doesn't execute check command. So, the next try was to make dep.rst a phony target:

all.html: all.rst
        rst2html $> $@

all.rst: dep.rst

.PHONY: dep.rst

dep.rst:
        check $@

This has another problem. check command is always executed but when dep.rst is updated, all.html is not created again (they are now phony targets and no timestamp verification is made against them -- actualy they aren't even files :-]).

Well, I can simply make all.html depend on everyone and hardcode the first dependency instead of using $>:

all.html: all.rst dep.rst
        rst2html all.rst $@

dep.rst:
        check $@

This has another problem: all.html is updated when dep.rst and all.rst are newer, but the check command is never executed. The reason is that dep.rst doesn't have any dependency to compare against.

Finally I found a satisfactory solution without having to do any ugly hack. If, in last example, dep.rst is not built because it doesn't have any dependency to compare. So let's create a dep.check file that is the target and make dep.rst a dependency of it. It would work, but it would not to be good to have lots of temporary files in the development directory. So I personally chose to make check files phony targets, with the issue of having it being executed always (if you want to make it a phony target or not, it is something you might think). Result was:

all: dep.check all.html

all.html: all.rst
        rst2html all.rst $@

all.rst: dep.rst
        touch $@

.PHONY: dep.check
dep.check: dep.rst
        check $>

If you have lots of source files, you can use your make tool features. I'm using NetBSD make, which has powerful features and I prefer over GNU make (for more information on NetBSD make in this web site, please visit the bmake notes (NetBSD make) page). My resulting Makefile is similar to the example below. I'm using a variable called RSTDOCS to hold names of all reStructuredText that are not 00-all.rst. CHECKS hold names of phony targets to be executed:

RSTDOCS = boot.rst fdisk.rst
CHECKS = ${RSTDOCS:.rst=.check}

TARGETS = 00-all.html

all: ${CHECKS} ${TARGETS}

00-all.html: 00-all.rst
        rst2html ${.ALLSRC} ${.TARGET}

00-all.rst: ${RSTDOCS}
        touch ${.TARGET}

# Check all rst files
.for rst in ${RSTDOCS}
check=${rst:.rst=.check}
${check}: ${rst}
        awk -f tools/source.awk ${.ALLSRC}
.endfor

.PHONY: clean
clean:
        rm -f ${TARGETS}