This tutorial will look into setting up your make file so you can easily compile your firmware with WinAVR. Firstly, here is a sample project to download which we will use with this tutorial. This project is for an ATMega8:

 ATMega8 Project with Serial Comms

Makfile basics

A makefile consists of 'rules.' A rule explains how and when to remake certain files, which are the targets of the particular file. A rule consists of three parts: one or more targets, zero or more prerequisites, and zero or more commands:
target... : preprequisites


A variable is a name defined in a makefile to represent a string of text.  Once the variable is defined, its value can be extracted with the $(variable) or ${variable} operators. eg:

NAME = tony
FULLNAME = $(NAME)_myatt


'#' in a line of a makefile starts a comment and extends to the end of the line.

Our Example Makefile

In this tutorial we will look at the supplied makefile and how it works. The analysis is broken into logical parts mainly broken up by the comments.

Part 1

MCU = atmega8
FORMAT = ihex
TARGET = main
SRC = $(TARGET).c usart.c

Here we define some variables for use throughout our makefile. Once you have a makefile which you are happy with, ideally this will be the only change required when you move from project to project. 

Compiler/Linker and other programs

CC = avr-gcc
OBJCOPY = avr-objcopy
AVRSIZE = avr-size
AVRDUDE = avrdude

These are some utilites used by our makefile. CC is our compilier/linker.

Compiler/Linker flags

CFLAGS += -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -Wall -Wstrict-prototypes -Wa,-adhlns=$(<:.c=.lst) -std=gnu99
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)

Some more variables are setup for easy changing of the compiler and linker flags. You can read up about avrgcc to find out what all these flags do, you shouldnt need to change them except for the -O option which sets the optimisation level (1,2,3,s)

Define all object files

OBJ = $(SRC:.c=.o) $(ASRC:.S=.o)

The compiler needs a list of object files used by the program. This variable contains a list of all object files generated from both the C and ASM source files.

Programming support using avrdude

AVRDUDE_FLAGS = -p $(MCU) -P lpt1 -c stk200

AvrDude is a command line AVR programmer which comes with WinAVR. These variables are used as command line arguments when using this programmmer. See the AvrDude documentation or our AvrDude Tutorial on how to setup and use AvrDude.

Targets for building

all: $(TARGET).elf $(TARGET).hex size

download: $(TARGET).hex
    rm -f $(TARGET).elf $(TARGET).hex $(OBJ:.o=.lst) $(OBJ)

    avr-size -A $(TARGET).elf

Targets are defined here as rules. We define four target rules: all, download, clean and size. The all target runs when make is called with no command line arguments. Each of the rules in the list must be complete before the command on the next line is called.

Rules for output files

%.hex: %.elf
    $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@

%.elf: $(OBJ)
    $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)

%.o : %.c
    $(CC) -c $(ALL_CFLAGS) $< -o $@

The rules for generating the output files are finally placed here. Note the '%' character will match any name. As the three rules show, the elf file must be built before the hex file, the objects must be compiled before the elf file linked and the object files must be compiled from the c files. Also note the '$@' which is a special variable for the file name of the target of the rule.

Object file dependencies

main.o: usart.h

Finally we list our object file dependencies. To save time, only files which have been editied are re-compilied. These rules allow us to tell the compilier that if a source file is change then another will also require re-compiling. This can be automated in the makefile, but I prefer to manually enter these dependencies.

Well thats about it for this tutorial.  You can find more information about GNU make all over the web:

GNU Make, Offical Documentation

An Introduction to Makefiles