Understanding Arduino build process for IDE-haters

This is the sketch I'm testing my setup on:

#include <SdFat.h>
#include <Wire.h>
#define DS1307 0x68

byte decToBcd(byte val)
{
    return ((val / 10 * 16) + (val % 10));
}

void setDateDs1307(byte hour,          // 1-23
                   byte minute,        // 0-59
                   byte second,        // 0-59
                   byte dayOfWeek,     // 1-7
                   byte year,
                   byte month,         // 1-12
                   byte dayOfMonth)    // 1-28/29/30/31
{
    Wire.beginTransmission(DS1307);
    Wire.send(0);
    Wire.send(decToBcd(second));
    Wire.send(decToBcd(minute));
    Wire.send(decToBcd(hour));
    Wire.send(decToBcd(dayOfWeek));
    Wire.send(decToBcd(dayOfMonth));
    Wire.send(decToBcd(month));
    Wire.send(decToBcd(year));
    Wire.endTransmission();
}

void setup() {                
  pinMode(A0, OUTPUT);
  setDateDs1307(14, 14, 2, 7, 9, 2, 11);
}

void loop() {
  digitalWrite(A0, HIGH);
  delay(1000);
  digitalWrite(A0, LOW);
  delay(1000); 
}

It simply makes a single call via TWI and starts blinking. It requires sdfatlib but does not utilize it.

Makefile I have so far:

BOARD = atmega328
PORT = /dev/ttyUSB0
SKETCH = blink

ARDUINO-DIR = $(lastword $(wildcard /usr/share/arduino-*))
SKETCHBOOK-DIR = $(HOME)/sketchbook
TMP-DIR = tmp

EXTRA-INCLUDES = $(ARDUINO-DIR)/libraries/Wire/utility/
EXTRA-DEPS = $(ARDUINO-DIR)/libraries/Wire/utility/twi.c

include $(ARDUINO-DIR)/hardware/arduino/boards.txt

CXX = avr-g++
CC = avr-gcc
CXXFLAGS = -mmcu=$($(BOARD).build.mcu) -DF_CPU=$($(BOARD).build.f_cpu) \
	   -I$(ARDUINO-DIR)/hardware/arduino/cores/$($(BOARD).build.core)\
	   $(foreach dir,$(wildcard $(ARDUINO-DIR)/libraries/*),-I$(dir))\
	   $(foreach dir,$(wildcard $(SKETCHBOOK-DIR)/libraries/*),-I$(dir))\
	  -I$(EXTRA-INCLUDES)\
	  -Os\
	  -fno-threadsafe-statics
CFLAGS = $(CXXFLAGS)

.SECONDEXPANSION:

.PRECIOUS: %.deps

.PHONY: clean program

# List object files from .deps file
define list-obj-deps
  $(foreach base,$(shell xargs -L1 basename < $(SKETCH).deps),$(TMP-DIR)/$(base).obj)
endef

# Main sketch file is converted to .cpp
$(SKETCH).cpp: $(SKETCH).pde
	@echo Using $($(BOARD).name)
	@cat $< | sed -e '1i #include "WProgram.h"' > $@

# Save a list of project dependencies and copy them to TMP-DIR
$(SKETCH).deps: $(SKETCH).cpp $(wildcard *.c) $(wildcard *.cpp) $(wilcard *.h) $(wildcard *.hpp)
	@$(CXX) $(CXXFLAGS) -MM $< | sed -e 's/ \\//' -e '$ a.' -e "$ a$(EXTRA-DEPS)" | tail -n +2 | sort | uniq | xargs -L 1 dirname | uniq \
	| xargs -L1 -I{} find {} -maxdepth 1 -type f -regex .*\\\(c\\\|cpp\\\)$ > $@
	@xargs -L1 -I{} cp {} $(TMP-DIR) < $@

# Intermediate object files for dependencies
# @TODO Update when system libraries update
$(TMP-DIR)/%.obj: $(TMP-DIR)/%
	$(CC) $(CFLAGS) $(TMP-DIR)/$* -c -o $@

# @TODO Must somehow expand list-obj-deps call after updating .deps file
$(SKETCH).elf: $(SKETCH).deps $(call list-obj-deps)
	$(CC) $(CFLAGS) $(call list-obj-deps) -o $@

%.hex: %.elf $(call list-obj-deps)
	avr-gcc -O ihex $< $@

program: $(SKETCH).hex
	avrdude -p$($(BOARD).build.mcu)\
		-c$($(BOARD).upload.protocol)\
		-P$(PORT)\
		-b$($(BOARD).upload.speed)\
		-U flash:w:$(wildcard *.hex)\

clean:
	@rm -frv `hg status --unknown --no-status`

First we make a blink.cpp from blink.pde my adding

#include "WProgram.h"

Then through the GCC -M option we make a list of dependencies for our sketch:

$ $CXX $CXXFLAGS -MM blink.cpp

blink.o: blink.cpp \
 /usr/share/arduino-0021/hardware/arduino/cores/arduino/WProgram.h \
 /usr/share/arduino-0021/hardware/arduino/cores/arduino/wiring.h \
 /usr/share/arduino-0021/hardware/arduino/cores/arduino/binary.h \
 /usr/share/arduino-0021/hardware/arduino/cores/arduino/WString.h \
 /usr/share/arduino-0021/hardware/arduino/cores/arduino/HardwareSerial.h \
 /usr/share/arduino-0021/hardware/arduino/cores/arduino/Stream.h \
 /usr/share/arduino-0021/hardware/arduino/cores/arduino/Print.h \
 /home/bojes/sketchbook/libraries/SdFat/SdFat.h \
 /home/bojes/sketchbook/libraries/SdFat/Sd2Card.h \
 /home/bojes/sketchbook/libraries/SdFat/Sd2PinMap.h \
 /home/bojes/sketchbook/libraries/SdFat/SdInfo.h \
 /home/bojes/sketchbook/libraries/SdFat/FatStructs.h \
 /usr/share/arduino-0021/hardware/arduino/cores/arduino/Print.h \
 /usr/share/arduino-0021/libraries/Wire/Wire.h

Then according to the BuildProcess

The .c and .cpp files of the target are compiled and output with .o extensions to this directory, as is the main sketch file and any other .c or .cpp files in the sketch and any .c or .cpp files in any libraries which are #included in the sketch.

I assume that we need to gather all .c or .cpp files in any of directories listed by gcc -MM, copy them to our project's temporary lib and compile in objective files using

avr-gcc -c

plus the required include path options and F_CPU definition. With my Makefile I ended up with these files in my tmp/ subdirectory:

blink.cpp
blink.cpp.obj
HardwareSerial.cpp
HardwareSerial.cpp.obj
main.cpp
main.cpp.obj
pins_arduino.c
pins_arduino.c.obj
Print.cpp
Print.cpp.obj
Sd2Card.cpp
Sd2Card.cpp.obj
SdFile.cpp
SdFile.cpp.obj
SdVolume.cpp
SdVolume.cpp.obj
Tone.cpp
Tone.cpp.obj
WInterrupts.c
WInterrupts.c.obj
Wire.cpp
Wire.cpp.obj
wiring_analog.c
wiring_analog.c.obj
wiring.c
wiring.c.obj
wiring_digital.c
wiring_digital.c.obj
wiring_pulse.c
wiring_pulse.c.obj
wiring_shift.c
wiring_shift.c.obj
WMath.cpp
WMath.cpp.obj
WString.cpp
WString.cpp.obj