Created
December 16, 2012 19:57
-
-
Save sjmeverett/4312170 to your computer and use it in GitHub Desktop.
Makefile to allow Arduino projects to be built at the command line. You just have to specify the arduino model and it will extract the appropriate settings from the boards.txt file. The makefile automatically discovers multiple boards.txt files under the arduino installation hardware directory and the sketchbook hardware directory and uses the a…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Makefile for building Arduino firmware with Arduino 1.0. | |
# Version 1.0 by stewartml (www.stewartml.co.uk) | |
# | |
# Adapted from Makefile-arduino v0.5 by Akkana Peck <[email protected]> | |
# Adapted from a long-ago Arduino 0011 Makefile by mellis, eighthave, oli.keller | |
# | |
# This Makefile allows you to build sketches from the command line | |
# without the Arduino environment (or Java). | |
# | |
# Detailed instructions for using this Makefile: | |
# | |
# 1. Copy this file into the folder with your firmware. Make sure the TARGET | |
# variable is correct; the default is for your main file to have the same | |
# name as the containing directory with a .cpp extension. Any files shoud | |
# have '#include <Arduino.h>' at the top and the main file should contain | |
# the setup() and loop() functions. | |
# | |
# 2. Make sure ARDUINO_DIR and SKETCHBOOK_DIR point to your arduino | |
# installation directory and sketchbook directory respectively. | |
# | |
# 4. Set ARDUINO_MODEL to your Arduino model. Run 'make boards' for a list of | |
# valid values. Note that this makefile supports multiple boards.txt files | |
# either under $(ARDUINO_DIR)/hardware or $(SKETCHBOOK_DIR)/hardware! | |
# | |
# 5. Run "make" to compile/verify your program. | |
# | |
# 6. Run "make upload" (and reset your Arduino if it requires it) to upload | |
# your program to the Arduino board. | |
# | |
# | |
# Known issues: this makefile will not work if you have spaces in your project | |
# directory path. I tried to fix it then gave up... | |
# | |
VERSION = 0.1 | |
# The build target | |
# defaults to the name of the containing directory | |
TARGET = $(notdir $(CURDIR)) | |
#TARGET = main | |
# Arduino model: | |
ARDUINO_MODEL = uno | |
# Which port do you want to use? | |
PORT = /dev/ttyACM* | |
# Standard Arduino libraries it will import, e.g. LiquidCrystal: | |
ARDUINO_LIBS = | |
# User-specified (in sketchbook/libraries/) libraries (untested): | |
USER_LIBS = | |
# Arduino modules to include | |
# I think the IDE uses some magic to figure out if you use Serial, it had better | |
# build HardwareSerial.cpp, but since we don't have that, put stuff like that | |
# here. (Removing default stuff you don't need will give you a smaller binary.) | |
# Leave off 'main' if you wan't to eschew the setup()/loop() functions and | |
# define your own main function. | |
ARDUINO_MODULES = Tone HardwareSerial WMath WString Print main | |
# Where do you keep the official Arduino software package? | |
ARDUINO_DIR = $(HOME)/arduino-1.0.2 | |
# Where is your sketchbook folder? | |
SKETCHBOOK_DIR = $(HOME)/sketchbook | |
# Where are tools like avr-gcc located on your system? | |
#AVR_TOOLS_PATH = $(ARDUINO_DIR)/hardware/tools/avr/bin | |
AVR_TOOLS_PATH = /usr/bin | |
# Where is avrdude? | |
AVRDUDE_PATH = $(ARDUINO_DIR)/hardware/tools | |
#Where is the avrdude configuration file? | |
#AVRDUDE_CONF = /etc/avrdude.conf | |
AVRDUDE_CONF = $(AVRDUDE_PATH)/avrdude.conf | |
# How to reset the device before downloading a new program. | |
# These don't always work; if the default one doesn't work, | |
# try uncommenting one of the others instead. | |
RESET_DEVICE = stty -F $(PORT) hupcl | |
# Perl version needs libdevice-serialport-perl : | |
#RESET_DEVICE = perl -MDevice::SerialPort -e 'Device::SerialPort->new("/dev/ttyUSB0")->pulse_dtr_on(1000)' | |
# Python version needs python-serial : | |
#RESET_DEVICE = python -c "import serial; s = serial.SERIAL('/dev/ttyUSB0', 57600); s.setDTR(True); sleep(1); s.setDTR(False)" | |
############################################################################ | |
# Below here nothing should need to be changed. Cross your fingers! | |
# Automatically figure out which boards.txt to use from the model name | |
BOARDS_TXT = $(shell grep -lr --include=boards.txt '$(ARDUINO_MODEL)\.' $(ARDUINO_DIR)/hardware $(SKETCHBOOK_DIR)/hardware) | |
ifeq ($(BOARDS_TXT),) | |
$(error Invalid ARDUINO_MODEL (run 'make boards' to see a list of valid values)) | |
endif | |
HARDWARE_DIR = $(shell dirname $(BOARDS_TXT)) | |
getSetting = $(shell awk -F"=" '$$1 == "$(ARDUINO_MODEL).$1" {print $$2}' $(BOARDS_TXT)) | |
# Set up values according to what the IDE uses: | |
MCU = $(call getSetting,build.mcu) | |
F_CPU = $(call getSetting,build.f_cpu) | |
UPLOAD_SPEED = $(call getSetting,upload.speed) | |
AVRDUDE_PROGRAMMER = $(call getSetting,upload.protocol) | |
ARDUINO_VARIANT = $(HARDWARE_DIR)/variants/$(call getSetting,build.variant) | |
ARDUINO_CORE = $(HARDWARE_DIR)/cores/$(call getSetting,build.core) | |
CWD = $(shell pwd) | |
CWDBASE = $(shell basename `pwd`) | |
TARFILE = $(TARGET)-$(VERSION).tar.gz | |
ARDUINO_CORE_C = $(patsubst $(ARDUINO_CORE)/%.c,applet/%.o,\ | |
$(ARDUINO_CORE)/wiring.c \ | |
$(ARDUINO_CORE)/wiring_analog.c \ | |
$(ARDUINO_CORE)/wiring_digital.c \ | |
$(ARDUINO_CORE)/wiring_pulse.c \ | |
$(ARDUINO_CORE)/wiring_shift.c \ | |
$(ARDUINO_CORE)/WInterrupts.c) | |
ARDUINO_MODULES_CPP = $(patsubst %,$(ARDUINO_CORE)/%.cpp,$(ARDUINO_MODULES)) | |
ARDUINO_CORE_CPP = $(patsubst $(ARDUINO_CORE)/%.cpp,applet/%.o,\ | |
$(ARDUINO_MODULES_CPP)) | |
SRC = | |
CXXSRC = | |
$(foreach l,$(ARDUINO_LIBS),$(ARDUINO_DIR)/libraries/$l/$l.cpp) \ | |
$(foreach l,$(USER_LIBS),$(SKETCHBOOK_DIR)/libraries/$l/$l.cpp) | |
# Tried to use patsubst, but gmake ignores the second occurrence of %. | |
# http://www.mail-archive.com/[email protected]/msg00426.html | |
# $(patsubst %,$(ARDUINO_DIR)/libraries/%/%.cpp,$(ARDUINO_LIBS)) \ | |
# $(patsubst %,$(HOME)/sketchbook/libraries/%/%.cpp,$(USER_LIBS)) | |
FORMAT = ihex | |
# Name of this Makefile (used for "make depend"). | |
MAKEFILE = Makefile | |
# Debugging format. | |
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. | |
# AVR (extended) COFF requires stabs, plus an avr-objcopy run. | |
DEBUG = stabs | |
OPT = s | |
# Place -D or -U options here | |
CDEFS = -DF_CPU=$(F_CPU) | |
# Include directories | |
CINCS = -I$(ARDUINO_CORE) -I$(ARDUINO_VARIANT) $(patsubst %,-I$(ARDUINO_DIR)/libraries/%,$(ARDUINO_LIBS)) $(patsubst %,-I$(SKETCHBOOK_DIR)/libraries/%,$(USER_LIBS)) | |
# Compiler flag to set the C Standard level. | |
# c89 - "ANSI" C | |
# gnu89 - c89 plus GCC extensions | |
# c99 - ISO C99 standard (not yet fully implemented) | |
# gnu99 - c99 plus GCC extensions | |
#CSTANDARD = -std=gnu99 | |
CDEBUG = -g$(DEBUG) | |
#CWARN = -Wall -Wstrict-prototypes | |
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums | |
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) | |
CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) | |
CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) | |
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs | |
LDFLAGS = -lm | |
# Programming support using avrdude. Settings and variables. | |
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex | |
AVRDUDE_FLAGS = -V -F -C $(AVRDUDE_CONF) -D \ | |
-p $(MCU) -P $(PORT) -c $(AVRDUDE_PROGRAMMER) \ | |
-b $(UPLOAD_SPEED) | |
# Program settings | |
CC = $(AVR_TOOLS_PATH)/avr-gcc | |
CXX = $(AVR_TOOLS_PATH)/avr-g++ | |
OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy | |
OBJDUMP = $(AVR_TOOLS_PATH)/avr-objdump | |
AR = $(AVR_TOOLS_PATH)/avr-ar | |
SIZE = $(AVR_TOOLS_PATH)/avr-size | |
NM = $(AVR_TOOLS_PATH)/avr-nm | |
AVRDUDE = $(AVRDUDE_PATH)/avrdude | |
REMOVE = rm -f | |
MV = mv -f | |
# Define all object files. | |
OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) $(ARDUINO_CORE_C) $(ARDUINO_CORE_CPP) | |
# Define all listing files. | |
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) | |
# Combine all necessary flags and optional flags. | |
# Add target processor to flags. | |
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) | |
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) | |
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) | |
# Default target. | |
all: applet_files build sizeafter | |
$(ARDUINO_CORE_C): applet/%.o: $(ARDUINO_CORE)/%.c | |
$(CC) -c $(ALL_CFLAGS) $< -o $@ | |
$(ARDUINO_CORE_CPP): applet/%.o: $(ARDUINO_CORE)/%.cpp | |
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@ | |
test: | |
@echo CXXSRC = $(CXXSRC) | |
build: elf hex | |
applet_files: | |
@test -d applet || mkdir applet | |
@cp $(TARGET).cpp applet/$(TARGET).cpp | |
@echo 'extern "C" void __cxa_pure_virtual() { while (1) ; }' >> applet/$(TARGET).cpp | |
elf: applet/$(TARGET).elf | |
hex: applet/$(TARGET).hex | |
eep: applet/$(TARGET).eep | |
lss: applet/$(TARGET).lss | |
sym: applet/$(TARGET).sym | |
# Program the device. | |
upload: applet/$(TARGET).hex | |
$(RESET_DEVICE) | |
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) | |
HEXSIZE = $(SIZE) --target=$(FORMAT) applet/$(TARGET).hex | |
ELFSIZE = $(SIZE) applet/$(TARGET).elf | |
sizebefore: | |
@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(HEXSIZE); echo; fi | |
sizeafter: | |
@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(HEXSIZE); echo; fi | |
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. | |
COFFCONVERT=$(OBJCOPY) --debugging \ | |
--change-section-address .data-0x800000 \ | |
--change-section-address .bss-0x800000 \ | |
--change-section-address .noinit-0x800000 \ | |
--change-section-address .eeprom-0x810000 | |
coff: applet/$(TARGET).elf | |
$(COFFCONVERT) -O coff-avr applet/$(TARGET).elf $(TARGET).cof | |
extcoff: $(TARGET).elf | |
$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf $(TARGET).cof | |
.SUFFIXES: .elf .hex .eep .lss .sym | |
.elf.hex: | |
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ | |
.elf.eep: | |
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ | |
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@ | |
# Create extended listing file from ELF output file. | |
.elf.lss: | |
$(OBJDUMP) -h -S $< > $@ | |
# Create a symbol table from ELF output file. | |
.elf.sym: | |
$(NM) -n $< > $@ | |
# Link: create ELF output file from library. | |
applet/$(TARGET).elf: applet/$(TARGET).cpp applet/core.a | |
$(CC) $(ALL_CFLAGS) -o $@ applet/$(TARGET).cpp -L. applet/core.a $(LDFLAGS) | |
applet/core.a: $(OBJ) | |
@for i in $(OBJ); do echo $(AR) rcs applet/core.a $$i; $(AR) rcs applet/core.a $$i; done | |
# Compile: create object files from C++ source files. | |
.cpp.o: | |
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@ | |
# Compile: create object files from C source files. | |
.c.o: | |
$(CC) -c $(ALL_CFLAGS) $< -o $@ | |
# Compile: create assembler files from C source files. | |
.c.s: | |
$(CC) -S $(ALL_CFLAGS) $< -o $@ | |
# Assemble: create object files from assembler source files. | |
.S.o: | |
$(CC) -c $(ALL_ASFLAGS) $< -o $@ | |
# Target: clean project. | |
clean: | |
$(REMOVE) applet/$(TARGET).hex applet/$(TARGET).eep applet/$(TARGET).cof applet/$(TARGET).elf \ | |
applet/$(TARGET).map applet/$(TARGET).sym applet/$(TARGET).lss applet/core.a \ | |
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) | |
tar: $(TARFILE) | |
$(TARFILE): | |
( cd .. && \ | |
tar czvf "$(TARFILE)" --exclude=applet --owner=root "$(CWDBASE)" && \ | |
mv "$(TARFILE)" "$(CWD)" && \ | |
echo Created $(TARFILE) \ | |
) | |
depend: | |
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ | |
then \ | |
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ | |
$(MAKEFILE).$$$$ && \ | |
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ | |
fi | |
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ | |
>> $(MAKEFILE); \ | |
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) | |
boards: | |
@grep -hr --include=boards.txt .name $(ARDUINO_DIR)/hardware $(SKETCHBOOK_DIR)/hardware | awk -F".name=" '{printf("%-20s %s\n", $$1, $$2)}' | sort | |
.PHONY: all build elf hex eep lss sym program coff extcoff clean depend applet_files sizebefore sizeafter boards |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment