Makefile

Comment

#this is comment....

Variable Declare

MACRO = value
ECE270TA = idiot

Use $(ECE270TA) or ${ECE270TA} to access the variable

:=

When using = to define a variable, make will extend the whole makefile, and determine what's the value of the variable.
When using :=, value of a variable is determined by the place in the makefile, instead of the final value after extending the whole makefile.

?=

If variable is not defined, define it. Otherwise, don't define it again.

+=

Append a new string to a defined variable

Syntax

target: dependencies
<Tab>Commands

or

target: dependencies; Commands
<Tab>Commands

Target

The file you want to build. Sometimes it may not be a real file, called fake object, ex. all.
If a target doesn't exist, make will execute and create it. Therefore, a fake object will always be executed.

Dependencies

Before creating a target, make will first check its dependencies.
If one of the dependencies does not exist, make will create that dependency first, then create target.
If all of them exist, make checks whether all dependencies are older than the target.
If all of them are older than the target, it means the target is up-to-date, so make doesn't create target again. Otherwise, make will execute and update the target.

Commands

Start from a <Tab>.
Every line of command will be executed in a new shell.
If you want to use a single shell to execute multiple commands, use ';' to separate commands.

Special Character

@: Don't display this line of command in terminal.
-: Even this line of command produces an error, don't stop running makefile.

Implicit rules

test.o:

is equal to the following:
test.o: 
     gcc -c test.c
test:

is equal to the following:
test:
     gcc -c test.c
     gcc -o test test.o

With implicit rules, we even don't need to write a make file to compile a c code.

Internal Variables

%: Represent one or more characters
<Ex> %.o : %.c makes all files named 'x.o', with files 'x.c' as dependencies, provided that ‘x.c’ exist or can be made.
$?: Dependencies newer than the target
$@: The target
$<: The first dependency
$*:
$^: The names of all the dependencies, with spaces between them.

Condition

ifeq (value1, value2)     #if (value1 == value2)
<Tab> commands
else
<Tab> commands
endif
ifneq (value1, value2)     #if (value1 != value2)
<Tab> commands
else
<Tab> commands
endif
ifdef variable     #if variable is not defined
<Tab> commands
else
<Tab> commands
endif
ifdef variable     #if variable is defined
<Tab> commands
else
<Tab> commands
endif

Internal Functions

shell:

contents := $(shell cat foo)

將含有檔案foo的目錄設定為變數contents的值,是用空格(而不是換行符)分離每一行。
dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))

The first repetition finds the value ‘a’ for dir, so it produces the same result as ‘$(wildcard a/*)’; the second repetition produces the result of ‘$(wildcard b/*)’; and the third, that of ‘$(wildcard c/*)’.

Enter Subdirectory

If the project contains many subdirectories, the following command can enter a subdirectory and make it.

cd subdir && make

When using "&&", if the command "cd subdir" produces an error, the shell will stop and prompt the error massage.
Each line of commands will be executed by a seperate shell.
If we use ";" instead of "&&" to seperate commands in a line, the shell will not stop when "cd subdir" produces an error.

Import File

include myrules.txt

Make Parameter

When we run make, we can define or override a variable from passing parameter

make ECE270TA="bitch"

Trace Makefile

Print Variable Value

Paste the following code in the top of makefile

ifdef TRACE
t:
       @echo "$(TRACE) == $($(TRACE))"
endif

then you can print the value of any variable

-> make t TRACE=ECE270TA
ECE270TA == idiot

Encountered Problems

  • 1. a variable/struct is defined in a .c file; the .o file build from the .c file should be included; make sure the makefile really include this .o file, and is not blocked by an #ifdef… condition
  • 2. a variable is defined in A.h file, and this A.h file is included by another header file B.h with a #if defined(FLAGS) condition. B.h are included by many files, and it is enclosed by a #ifndef __B.h; #def __B.h; #endif block. To make sure the vairable defined in A.h file is included, we need to define FLAGS, and include B.h. The problem is, if another file includes B.h before the FLAGS is defined, then A.h will not be included(because the if defined(FLAGS) and #ifndef __B.h; #def __B.h; #endif in B.h).

Reference

How to Trace Makefile
A Very Good Chinese Makefile Tutorial
GNU Make Chinese Manual
Implicit Rules
Internal Functions in makefile
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License