Code Conventions for the Build System

Background

Whitespace and indentation in makefiles are more problematic than for other languages. Even while most of the time whitespace is not significant, sometimes it is. This might be considered a design flaw in make, but that's not something we can do anything about. In particular, initial tabs signify make rule recipes, and in make string manipulation, sometimes whitespace matter (and sometimes it does not).

Probably partly due to this and partly due to the legacy nature of the tools, there is little editor/IDE/tooling support for automatically formatting makefiles. This in turns makes keeping sane whitespace usage and indentation a "manual" task. The following rules are adapted to this reality. For simplicity, we have used the same set of rules (for those which apply) to shell scripts and autoconf source code as well.

The rules are based on the Java code conventions, but Makefiles are not Java source code, and there are several differences.

Whitespace and indentation rules

Indentation, required use

  1. The basic level of indentation is two spaces. Use this for "logical" indentation (if blocks, function definitions etc).
  2. If a line must be broken, use four spaces for indentation.
  3. Recipes in makefile rules must start with a tab (per definition).
  4. If a single tab (interpreted as 8 spaces wide) is not enough to put the recipe clearly indented (meaning at least 4 spaces difference) from the code around it, use additional tabs.
  5. Non-shell commands in a recipe (e.g. comments and make directives like ifdef) must not start with tab, but should instead be indented to the same level as the surrounding shell commands using spaces (with tabs interpreted as 8 spaces wide).
  6. Additional indentation in recipes should be done using space after the tab(s), as in normal makefile lines.
  7. Partial recipes (macro definitions that are supposed to be inlined into a recipe) should be treaded like a recipe and start with tabs as well.

Whitespace, required use

  1. Trailing whitespaces is never allowed.
  2. Do not use tabs, only spaces (except for in recipes, as stated by rule 3-7).

Whitespace, recommended use

  1. There should be no whitespace between the list of targets and the : at the start of a rule.
  2. There should be an empty line before and after each rule.
  3. Avoid empty lines inside the recipe.
  4. Broken lines should end with a backslash, and a single space before the backslash (" \").
  5. A single space should separate a comma from the next argument in a function call.
  6. A single space should be used before and after assignment operators (e.g. :=, =, +=).

These recommendations are not always possible to follow, since whitespace might have semantic meaning. If an exception from these recommendations is required by make, it should ideally be pointed out by a comment. Especially spacing around commas might be sensitive, so beware.

Style recommentations

  1. Use := (direct assignment) instead of = (recursive macro definition), unless you really need the recursive definition.
  2. In long lists, do not let the first and last element have different form. For instance, start the first element on a new line rather than after a :=, and end the list with an empty comment (#) to be able to have a trailing backslash on the last line.
  3. Avoid padding internally in a line with spaces to try to align some feature into columns with surrounding lines.
  4. For multiple commands run by the shell, separated by "&& \" or similar, all commands should start at the same indention level.

Rationales (to some of the rules)

1-2. This is in contrast to Java, which has twice as long indentations (4 space logical indentation, 8 spaces for wrapped lines). But since all indentation needs to be done basically by repeatedly pressing space, and since wrapped lines are fairly common, we felt it important to keep the indentation level short. Otherwise a wrapped line two levels in would needed 16 presses on the space bar.

9-12. Tabs are required in recipes, but for the sake of sanity, this is the only accepted use of tabs. The makefile syntax does not make it easy to spot rules in complex makefiles, and everything that helps in distinguishing rules from non-rules is needed.

16. Recursive macro definition (= instead of :=) slows down make and can have surprising effects. Typically this is not what you mean.

17-18. A very typical use case of makefile changes is to add things (files, compiler directives, etc) to a list. These rules help making such changes easy and context free. Otherwise the developer must modify several lines that are unrelated to the actual change. Chances are that a nicely padded grid will not be updated and start deteriorating from the very first change.

19. Separating multiple shell commands (e.g. after a shell "if" command) should not be considered a broken line which needs to be indenting, but a way to specify a list of commands on the same indentation levels. This is after all the intent; the && is merely a roundabout device to get this to work properly in makefiles.