14.4.6 Errors with distclean

As explained in the section above (see Checking the Distribution), ‘make distcheck’ attempts to build and check your package for errors. One such error you might see is:

ERROR: files left in build directory after distclean:

The file(s) left in the build directory after ‘make distclean’ has run are listed after this error message. This can happen in two ways:

In the first case of simple left-over files not intended to be distributed, the fix is to include them for cleaning (see What Gets Cleaned); this is straightforward and doesn’t need more explanation.

The second case, however, is not always easy to understand and fix, so let’s proceed with an example. Suppose our package contains a program for which we want to build a man page using help2man. GNU help2man produces simple manual pages from the --help and --version output of other commands (see The Help2man Manual). Because we don’t want to force our users to install help2man, we distribute the generated man page using the following setup.

# This Makefile.am is bogus.
bin_PROGRAMS = foo
foo_SOURCES = foo.c
dist_man_MANS = foo.1

foo.1: foo$(EXEEXT)
        help2man --output=foo.1 ./foo$(EXEEXT)

This will effectively distribute the man page. However, ‘make distcheck’ will fail with:

ERROR: files left in build directory after distclean:
./foo.1

Why was foo.1 rebuilt? Because although distributed, foo.1 depends on a non-distributed built file: foo$(EXEEXT). foo$(EXEEXT) is built by the user, so it will always appear to be newer than the distributed foo.1.

In other words, ‘make distcheck’ caught an inconsistency in our package. Our intent was to distribute foo.1 so users do not need to install help2man, but since this rule causes this file to be always rebuilt, users do need help2man. Either we should ensure that foo.1 is not rebuilt by users, or there is no point in distributing foo.1.

More generally, the rule is that distributed files should never depend on non-distributed built files. If you distribute something generated, distribute all its sources.

One way to fix the above example, while still distributing foo.1, is to not depend on foo$(EXEEXT), but instead on relevant source files. For instance, assuming foo --version and foo --help do not change unless foo.c or configure.ac change, we could write the following Makefile.am:

bin_PROGRAMS = foo
foo_SOURCES = foo.c
dist_man_MANS = foo.1

foo.1: foo.c $(top_srcdir)/configure.ac
        $(MAKE) $(AM_MAKEFLAGS) foo$(EXEEXT)
        help2man --output=foo.1 ./foo$(EXEEXT)

This way, foo.1 will not get rebuilt every time foo$(EXEEXT) changes. The make call makes sure foo$(EXEEXT) is up-to-date before help2man.

Another step towards ensuring this would be to use separate directories for binaries and man pages, and set SUBDIRS so that binaries are built before man pages. Unfortunately, this alone is, in general, not sufficient. In order to avoid to avoid concurrency bugs, it may be necessary to include wrappers; this is done by GNU Autoconf, as mentioned below.

We could also decide not to distribute foo.1. In this case it’s fine to have foo.1 dependent upon foo$(EXEEXT), since both will have to be rebuilt. However, it might be impossible to build the package in a cross-compilation, because building foo.1 involves an execution of foo$(EXEEXT). The exception would be if foo is a platform-independent script, such as help2man.

Another context where such errors are common is when distributed files are built by tools that are built by the package. The pattern is similar:

distributed-file: built-tools distributed-sources
        build-command

should be changed to

distributed-file: distributed-sources
        $(MAKE) $(AM_MAKEFLAGS) built-tools
        build-command

or you could choose not to distribute distributed-file, if cross-compilation does not matter.

The points made through these examples are worth summarizing:

  • Distributed files should never depend upon non-distributed built files.
  • Distributed files should be distributed with all their dependencies.
  • If a file is intended to be rebuilt by users, then there is no point in distributing it.

Real-world examples for help2man:

If you’re desperate, it’s possible to disable this check completely by setting distcleancheck_listfiles (see distcleancheck). Make sure you understand the reason why ‘make distcheck’ complains first. distcleancheck_listfiles is a way to hide errors, not to fix them. You can always do better.