When you wrote for the second time almost the same code and for the next time you started to copy & paste those code. That sounds like you should introduce a function. Functions in Makefile can shorten and clean things up and will be shown in the following…

Basic syntax

define print_anything
 @echo "\nMakefile: $(1)\n"
endef

That is a simple print function taking one argument to echo with a prefix and two line breaks. Functions in a Makefile are enclosed with the two keywords define and endef (yes, that extra d is omitted and reads rather unusual). There is no need to define arguments of those functions, it is possible to access them directly by $(1) and subsequently with $(n) where n > 0. The indention is optional what is noteworthy due to Makefile targets forcing indention. In this particular case it can increase readability like it is always with indention.

test:
 $(call print_anything, "Testing a first function in a Makefile.")

The custom function print is called with the keyword call inside $(). The parameters are passed to the function by specifying them inside those parenthesis separated by a comma. Makefile targets won’t complain when this comma has been forgotten. The parameter will be silently ignored and won’t be available inside the function. Thats one drawback of calling those functions and can lead to some time spend debugging weird issues.

Example to color output with functions

After writing about the basic syntax of how to define and call a function it is time for a more practical example. In the following there’re be a few functions defined to color the output of Makefiles. Three levels of messages will be used, they read - info, warning and error. This time it’ll be shown the other way round.

That’s the target to test all three print functions:

test_colors:
 $(call print_info, "That\'s an information only.")
 $(call print_warning, "That\'s a warning. Maybe you should do something.")
 $(call print_error, "That\'s an error. Do something! Now!")

Three distinct functions are coloring the output based upon the urgency of the message.

define print_info
 $(call print, $(1), "gray")
endef

define print_warning
 $(call print, $(1), "yellow")
endef

define print_error
 $(call print, $(1), "red")
endef

All those function call another function print and passing next to the message itself another parameter naming the color.

define print
 @case ${2} in \
  gray)    echo "\e[90m${1}\e[0m" ;; \
  red)     echo "\e[91m${1}\e[0m" ;; \
  yellow)  echo "\e[93m${1}\e[0m" ;; \
  *)       echo "\e[97m${1}\e[0m" ;; \
 esac
endef

This named color is processed by a switch-case-block which matches the human-readable name to the corresponding terminal control sequence. A fallback will color everything white, should the function called directly.

That’s it, a short and direct primer to functions inside Makefiles without too many words describing probably obvious things. Like always there is much more to write about functions, but to be frank I even did not check upon further things which I could maybe add to that blog post here. Used to discover things in passing when I need them, instead of studying manuals in advance. But people deal in different ways with learning new things and thats another story for another blog post.

Downloads

To check both examples, run…

make -f Makefile-functions.mk test
make -f Makefile-functions.mk test_colors