Learning Makefile(s)
I am learning how to write a proper Makefile
using
https://makefiletutorial.com/#getting-started. And I am just writing down the things that jump at me, not complete neither a tutorial, just a look-up post or cheatsheet for me.
- 🗂️ Makefiles must be indented using TABs and not spaces or make will fail.
- 📝 each section, or block, is called a target (
target:
) and it's actually a filename - when a target is run (aka when the commands of a target are run), the commands will create a file with the same name as the target
- no target supplied as an argument to the make command, the first target is run
- the target
compile: main.c
hasmain.c
as dependency and will re-run this target when the file had changed - ❛ quotes have no meaning to Make, they are simply characters (that are assigned to the variable)
- 💡 create
all
as a first target, so it will run by default if make is called without a target - when there are multiple targets for a rule, the commands will be run for each target
$@
is an automatic variable that contains the target name*
and%
are called wildcards in Make*
searches your filesystem for matching filenames, always wrap it in thewildcard
function- when
*
matches no files, it is left as it is (unless run in thewildcard
function),thing_wrong := *.o # Don't do this!
%
is really useful, but is somewhat confusingecho $@ # Outputs the target name
echo $? # Outputs all prerequisites newer than the target
echo $^ # Outputs all prerequisites
- don't use implicit rules, at least try to prevent them, they become confusing
- each command is run in a new shell (or at least the effect is as such)
- The default shell is /bin/sh, change by adding
SHELL=/bin/bash
at the top of the Makefile - Add a
-
before a command to suppress the error - Add
-i
to suppress the error for every command - To recursively call a makefile, use the special
$(MAKE)
instead ofmake
- String substitution:
$(text:pattern=replacement)
is a shorthand for$(patsubst pattern,replacement,text)
- Target scoped variable, for a target
main.c
can be defined (e.g. in the line above) by prefixing it with the target name,main.c: variableName = 42
for a target like this with a prerequisite$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c
, a variable can be defined like so:$(BUILD_DIR)/%.o: SOURCE_FILE = $^ # prerequisites