Target templates

Templates define common flags and sources for targets. They do not define targets, by themselves. Templates offer a better structured way to inheriting sources and libraries.

# Build a program that does some math
program prog {
   sources {
      main.c
      math.c
   }
   link {
      -lm
   }
}
# Build a program that does the same math but with GMP
program gmpprog {
   sources {
      # Import prog's sources
      sources (prog)
      # except math.c
      exclude { math.c }
      # because we reimplement it using GMP
      gmpmath.c
   }
   link {
      # Import prog's link section
      link (prog)
      # And link against GMP
      -lgmp
   }
}

The above example can be better written as follows:

template math-program {
   sources {
      main.c
   }
   link {
      -lm
   }
}
# Inherit from the "math-program" template.
program prog : math-program {
   sources {
      math.c
   }
}
program gmpprog : math-program {
   sources {
      gmpmath.c
   }
   link {
      -lgmp
   }
}

Both programs inherit the sources and link blocks from math-program and add their own sources to it. This method is better structured but less flexible. Templates can inherit from other templates. It is still possible to import sources from other templates and even targets.

Note that templates also have their own namespace, so that it is possible to declare a template with the same name as a target.

It is not possible to exclude inherited sources, link, etc. Template inheritance forms an is-a relationship.

Multiple inheritance

Multiple templates can be inherited. Order of inheritance does not matter and conflicts are flagged as an error. Two templates linking against the same library or listing the exact same source file is not a conflict. Targets can not serve as a base, so a target or template cannot inherit from another target, only from templates. Inheriting from a template more than once, even implicitly through another base, is an error.

template math-program {
   sources {
      math-support.c
   }
   link {
      -lm
   }
}
template system-program {
   sources {
      system-support.c
   }
   link {
      -lutil
   }
}
program sysprog : math-program, system-program {
   sources {
      main.c
   }
}

Filtering

As we learned in variables, one may filter the $(prog.link) variable by locally built libraries. Templates take this one step further by allowing you to filter by template.

template math-library {
   ...
}
library mathsupport : math-library {
   ...
}
program mathprog {
   sources { ... }
   link {
      # Link against two support libraries
      mathsupport
      support
      # Also link against libm
      -lm
   }
}

In the above example, the $(mathprog.link) variable would expand to " mathsupport support -lm". The expansion of $(mathprog.link : library) would be " mathsupport support", and expanding the pseudo-variable $(mathprog.link : math-library) results in just " mathsupport". This is especially useful in pattern rules.