Makefile For Arduino Under Cygwin/Windows
This could still use a little cleanup. It handles building a project with multiple source files, but it still requires too much manual editing when a new library is pulled in, new source files are added, etc. The MY_LIBS thing is a pretty sloppy fix, as it should figure out what directories are in the sketch library folder and automatically put them in the path.
However, it works, and it got me out of the horrendous IDE.
Please note the -jcw extension on arduino-00xx directory. I have a special build that has some header files fixed to reduce errors when compiling with -W -Wall. This Makefile is using -w to keep things quiet while I was getting paths and such right. I would strongly suggest enabling -W -Wall (and removing the -w) so that fun little problems like signed vs unsigned compares don't bite you in the butt.
Under Cygwin, if you're using 'make' version 3.81 or higher, you will need to down-grade to 3.80. This is because at some point, some idiot decided to remove DOS path name support, so a ':' in something like 'ARDUINO_DIR = c:/cygwin/home' will result in an error message: "Error : *** target pattern contains no `%'." What moron decided this was a smart decision is beyond me. Instructions to down-grade to make-3.80 are here. It's very trivial to do so.
Why not just use the '/cygwin/c' nomenclature to refer to 'c:/'? Because the avr-gcc and avr-g++ built for Windows don't understand that. To it, it looks internally like '/cygwin/c/somepath', which doesn't exist, since it's a meta-directory inside the Cygwin environment, and the provided toolchain is not Cygwin-awares. An avr-gcc toolchain built for Cygwin would likely work, but that's not what ships in the Arduino toolchain.
# # $Id$ # $Revision$ # $Date$ # $Author$ # $HeadURL$ # # # Swiped from http://www.robgray.com/temp/makefile # # # Tune for project # PROJECT_NAME = Compactor MY_FILES = config.cpp dac.cpp log.cpp modem.cpp monitor.cpp nvprom.cpp remote.cpp storage.cpp util.cpp MY_LIBS = ../libraries/SdFat/Sd2Card.cpp ../libraries/SdFat/SdFile.cpp ../libraries/SdFat/SdVolume.cpp ../libraries/Time/Time.cpp ../libraries/Timer1/TimerOne.cpp MY_LIBS_INC = -I../libraries/SdFat -I../libraries/Time -I../libraries/Timer1 COM = 3 # # Tweak for Arduino-00xx package installation # VERSION=22 ARDUINO_DIR = c:/cygwin/home/jcw/arduino-00$(VERSION)-jcw ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ARDUINO_LIB = $(ARDUINO_DIR)/libraries AVRDUDE_PATH = $(ARDUINO_DIR)/hardware/tools/avr/bin AVRDUDECONFIG_PATH = $(ARDUINO_DIR)/hardware/tools/avr/etc AVR_TOOLS_PATH = $(ARDUINO_DIR)/hardware/tools/avr/bin TARGET = $(notdir $(CURDIR)) # # Tweak for AVR hardware (currently set for Arduino Mega 2560 on COM3) # PORT = //./COM$(COM) UPLOAD_RATE = 115200 AVRDUDE_PROGRAMMER = stk500v2 MCU = atmega2560 F_CPU = 16000000 # # Note that if your program has dependencies other than those # already listed below, you will need to add them accordingly. # C_MODULES = \ $(ARDUINO_CORE)/wiring_pulse.c \ $(ARDUINO_CORE)/wiring_analog.c \ $(ARDUINO_CORE)/pins_arduino.c \ $(ARDUINO_CORE)/wiring.c \ $(ARDUINO_CORE)/wiring_digital.c \ $(ARDUINO_CORE)/WInterrupts.c \ $(ARDUINO_CORE)/wiring_shift.c \ CXX_MODULES = $(MY_FILES) $(MY_LIBS) \ $(ARDUINO_CORE)/Tone.cpp \ $(ARDUINO_CORE)/main.cpp \ $(ARDUINO_CORE)/WMath.cpp \ $(ARDUINO_CORE)/Print.cpp \ $(ARDUINO_CORE)/HardwareSerial.cpp \ $(ARDUINO_LIB)/EEPROM/EEPROM.cpp CXX_APP = applet/$(TARGET).cpp MODULES = $(C_MODULES) $(CXX_MODULES) SRC = $(C_MODULES) CXXSRC = $(CXX_MODULES) $(CXX_APP) FORMAT = ihex # # 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 # DEBUG = # # Optimization level s, 0, 1, 2 or 3 # OPT = s # # Place -D (#define) or -U (#undef) options here # CDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(VERSION) CXXDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(VERSION) # # Place -I options here # CINCS = -I. -I$(ARDUINO_CORE) -I$(ARDUINO_LIB)/EEPROM $(MY_LIBS_INC) CXXINCS = -I. -I$(ARDUINO_CORE) -I$(ARDUINO_LIB)/EEPROM $(MY_LIBS_INC) # # 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 #CWARN = -Wall # show all warnings CWARN = -w # suppress all warnings ####CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums CTUNING = -ffunction-sections -fdata-sections CXXTUNING = -fno-exceptions -ffunction-sections -fdata-sections #CEXTRA = -Wa,-adhlns=$(<:.c=.lst) MMCU = -mmcu=$(MCU) CFLAGS = $(CDEBUG) -O$(OPT) $(CWARN) $(CTUNING) $(MMCU) $(CDEFS) $(CINCS) $(CSTANDARD) $(CEXTRA) CXXFLAGS = $(CDEBUG) -O$(OPT) $(CWARN) $(CXXTUNING) $(CDEFS) $(CINCS) #ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs LDFLAGS = -O$(OPT) -lm -Wl,--gc-sections -Wl,-Map,applet/$(TARGET).map # # Programming support using avrdude. Settings and variables. # AVRDUDE_PORT = $(PORT) AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex AVRDUDE_FLAGS = -V -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -b $(UPLOAD_RATE) -q -q # # Program names # CC = $(AVR_TOOLS_PATH)/avr-gcc CXX = $(AVR_TOOLS_PATH)/avr-g++ LD = $(AVR_TOOLS_PATH)/avr-gcc 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) OBJ_MODULES = $(C_MODULES:.c=.o) $(CXX_MODULES:.cpp=.o) # # 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 = $(CFLAGS) -mmcu=$(MCU) ALL_CXXFLAGS = $(CXXFLAGS) -mmcu=$(MCU) ALL_ASFLAGS = -x assembler-with-cpp $(ASFLAGS) -mmcu=$(MCU) ALL_LDFLAGS = $(LDFLAGS) -mmcu=$(MCU) # # Default target. # all: applet_files build sizeafter build: elf lss hex # # applet_files: quubmon.pde # applet/$(TARGET).cpp: $(PROJECT_NAME).pde # Here is the "preprocessing". # It creates a .cpp file based with the same name as the .pde file. # On top of the new .cpp file comes the WProgram.h header. # and prototypes for setup() and Loop() # Then the .cpp file will be compiled. Errors during compile will # refer to this new, automatically generated, file. # Not the original .pde file you actually edit... @test -d applet || mkdir applet @echo '#include "WProgram.h"' > applet/$(TARGET).cpp @echo 'void setup();' >> applet/$(TARGET).cpp @echo 'void loop();' >> applet/$(TARGET).cpp @cat $(PROJECT_NAME).pde >> 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 @echo "Programming..." @$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) # # Display size of file. # HEXSIZE = $(SIZE) --target=$(FORMAT) applet/$(TARGET).elf ELFSIZE = $(SIZE) -C 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) -O $(FORMAT) -j .eeprom --set-section-flags=.eeprom="alloc,load" --no-change-warnings --change-section-lma .eeprom=0 $< $@ # # 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).o applet/core.a .depend @$(LD) $(ALL_LDFLAGS) -o $@ applet/$(TARGET).o applet/core.a applet/core.a: $(OBJ_MODULES) #@for i in $(OBJ_MODULES); do echo $(AR) rcs applet/core.a $$i; $(AR) rcs applet/core.a $$i; done @for i in $(OBJ_MODULES); do $(AR) rcs applet/core.a $$i; done # # Compile: create object files from C++ source files. # .cpp.o: @echo Compiling $< @$(CXX) -c $(ALL_CXXFLAGS) $< -o $@ # # Compile: create object files from C source files. # .c.o: @echo Compiling $< @$(CC) -c $(ALL_CFLAGS) $< -o $@ # # Compile: create assembler files from C source files. # .c.s: @echo Compiling $< @$(CC) -S $(ALL_CFLAGS) $< -o $@ # # Assemble: create object files from assembler source files. # .S.o: @echo Assembling $< @$(CC) -c $(ALL_ASFLAGS) $< -o $@ # # Automatic dependencies # %.d: %.c $(CC) -M $(ALL_CFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@ %.d: %.cpp $(CXX) -M $(ALL_CXXFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@ # # 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) .PHONY: all build elf hex eep lss sym program coff extcoff applet_files sizebefore sizeafter # # The .depend files contains the list of header files that the # various source files depend on. By doing this, we'll only # rebuild the .o's that are affected by header files changing. # .depend: $(CC) -M $(CINCS) $(CXX_MODULES) $(CXX_APP) > .depend # # Utility targets # dep: $(CC) -M $(CINCS) $(CXX_MODULES) $(CXX_APP) > .depend # # Include the .depend file so we have the list of dependencies # ifeq (.depend,$(wildcard .depend)) include .depend endif