Makefile for 0018 -- Assember listing

Hi, I wanted/needed to examine the generated assembler/machine-code. The Makefile previously performed this, so I just updated it.

I have tested the following on my Duemilanove (ATmega328p)
make
make upload
make lss
make clean

NOTE object files are placed in source directories.
The order of options and commands is different from the IDE, but I believe the resulting files are identical.

# Arduino 0018 Makefile
# Arduino adaptation 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 the makefile:
#
#  1. Copy this file into the folder with your sketch. There should be a
#     file with the same name as the folder and with the extension .pde
#     (e.g. foo.pde in the foo/ folder).
#
#  2. Modify the line containg "INSTALL_DIR" to point to the directory that
#     contains the Arduino installation (for example, under Mac OS X, this
#     might be /Applications/arduino-0012).
#
#  3. Modify the line containing "PORT" to refer to the filename
#     representing the USB or serial connection to your Arduino board
#     (e.g. PORT = /dev/tty.USB0).  If the exact name of this file
#     changes, you can use * as a wildcard (e.g. PORT = /dev/tty.usb*).
#
#  4. Set the line containing "MCU" to match your board's processor. 
#     Older one's are atmega8 based, newer ones like Arduino Mini, Bluetooth
#     or Diecimila have the atmega168.  If you're using a LilyPad Arduino,
#     change F_CPU to 8000000.
#
#  5. At the command line, change to the directory containing your
#     program's file and the makefile.
#
#  6. Type "make" and press enter to compile/verify your program.
#
#  7. Type "make upload", reset your Arduino board, and press enter to
#     upload your program to the Arduino board.
#
# $Id$

TARGET = $(notdir $(CURDIR))
INSTALL_DIR = $(HOME)/arduino-0018
PORT = /dev/ttyUSB*
UPLOAD_RATE = 57600
AVRDUDE_PROGRAMMER = stk500v1
#MCU = atmega168
MCU = atmega328p
F_CPU = 16000000

############################################################################
# Below here nothing should be changed...

VERSION=18
ARDUINO = $(INSTALL_DIR)/hardware/arduino/cores/arduino
#AVR_TOOLS_PATH = $(INSTALL_DIR)/hardware/tools/avr/bin
AVR_TOOLS_PATH = /usr/bin
AVRDUDE_PATH = $(INSTALL_DIR)/hardware/tools
C_MODULES =  \
$(ARDUINO)/wiring_pulse.c \
$(ARDUINO)/wiring_analog.c \
$(ARDUINO)/pins_arduino.c \
$(ARDUINO)/wiring.c \
$(ARDUINO)/wiring_digital.c \
$(ARDUINO)/WInterrupts.c \
$(ARDUINO)/wiring_shift.c \
# end of C_MODULES

CXX_MODULES = \
$(ARDUINO)/Tone.cpp \
$(ARDUINO)/main.cpp \
$(ARDUINO)/WMath.cpp \
$(ARDUINO)/Print.cpp \
$(ARDUINO)/HardwareSerial.cpp \
# end of CXX_MODULES

CXX_APP = applet/$(TARGET).cpp 
MODULES = $(C_MODULES) $(CXX_MODULES)
SRC = $(C_MODULES)
CXXSRC = $(CXX_MODULES) $(CXX_APP)
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
DEBUG = 

OPT = s

# Place -D or -U options here
CDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(VERSION)
CXXDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(VERSION)

# Place -I options here
CINCS = -I$(ARDUINO)
CXXINCS = -I$(ARDUINO)

# 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)

CFLAGS = $(CDEBUG) -O$(OPT) $(CWARN) $(CTUNING) $(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


# Programming support using avrdude. Settings and variables.
AVRDUDE_PORT = $(PORT)
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex

#AVRDUDE_FLAGS = -V -F -C $(INSTALL_DIR)/hardware/tools/avr/etc/avrdude.conf \

AVRDUDE_FLAGS = -V -F -C $(INSTALL_DIR)/hardware/tools/avrdude.conf \
-p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
-b $(UPLOAD_RATE)

# Program settings
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 hex 

#applet_files: $(TARGET).pde
applet/$(TARGET).cpp: $(TARGET).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 $(TARGET).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
      $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)


      # Display size of file.
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) -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: $(TARGET).pde applet/core.a 
applet/$(TARGET).elf: applet/$(TARGET).o applet/core.a 
      $(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



# 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 $@


# 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 clean applet_files sizebefore sizeafter

#include $(SRC:.c=.d)
#include $(CXXSRC:.cpp=.d)

it does not work for me :'(

it says the following:

make upload
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avrdude -V -F -C /Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/etc/avrdude.conf  -U flash:w:applet/sheldon_cooper.hex

avrdude: no programmer has been specified on the command line or the config file
         Specify a programmer using the -c option and try again

make: *** [upload] Error 1

and also I have another problem, I have an include (#include Robot.h) but it seems makefile can't find it (Ardiuno IDE does when I upload the code). I get the following when I run make command:

make
# 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/sheldon_cooper.cpp
echo 'void setup();' >> applet/sheldon_cooper.cpp
echo 'void loop();' >> applet/sheldon_cooper.cpp
cat sheldon_cooper.pde >> applet/sheldon_cooper.cpp
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++ -c -g -Os -w       -fno-exceptions -ffunction-sections -fdata-sections -DF_CPU=16000000L -DARDUINO=18 -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino -mmcu=atmega168 applet/sheldon_cooper.cpp -o applet/sheldon_cooper.o
applet/sheldon_cooper.cpp:23:19: error: Robot.h: No such file or directory
applet/sheldon_cooper.cpp:26: error: 'Robot' does not name a type

any ideas?

Thanks very much

thanks for this - really handy for compiling from another editor (I use vim instead of Arduino "IDE")

maesitos - try changing these lines (around line 94 I think):

# Place -I options here
CINCS = -I$(ARDUINO)
CXXINCS = -I$(ARDUINO)

to this:

# Place -I options here
CINCS = -I$(ARDUINO) -I`pwd`
CXXINCS = -I$(ARDUINO) -I`pwd`

This makes gcc look in the current directory for header files. I'm assuming you have

include "Robot.h" at the start of the source file already.

Also, I think this might be needed on line 176:

echo 'int main(void) {\n init();\n setup();\n for (;;) loop();\n return 0;\n}\n' >> build/$(TARGET).cpp

for the code to actually RUN, right?
Arduino adds that as well when it preprocesses the .pde file.

Please, return the possibility to create applet folder like in version 0017. May be in preferences. I see at least two reasons for it:

  1. Sure, that more than 1% of users are with brains and want to keep .hex and .elf files with sketch for future investigations or just using without necessity of every time compiling /uploading to get files again.

  2. In Windows - temp folder like build1755132727304913499.tmp are usually in directory C:\Documents and Settings...\Local Settings\Temp, which is usually hidden. So it is necessary to keep Hidden files opened, which is not very smart idea.

Sorry, I put my reply by mistake

The Makefile does not work at my Gentoo-System. Arduino is installed in /usr/share/arduino-0018/. If I set ARDUINO_PATH:=/usr/share/arduino-0018/ make fails with:

rose@thinkpad:/home/rose/Txt/Test/Arduino/led(93)$ make /usr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -DF_CPU=16000000L -DARDUINO=18 -I/usr/share/arduino-0018/hardware/arduino/cores/arduino -mmcu=atmega328p /usr/share/arduino-0018/hardware/arduino/cores/arduino/wiring_pulse.c -o /usr/share/arduino-0018/hardware/arduino/cores/arduino/wiring_pulse.o Assembler messages: Fatal error: can't create /usr/share/arduino-0018/hardware/arduino/cores/arduino/wiring_pulse.o: Permission denied make: *** [/usr/share/arduino-0018/hardware/arduino/cores/arduino/wiring_pulse.o] Fehler 1

The message:

Fatal error: can’t create /usr/share/arduino-0018/hardware/arduino/cores/arduino/wiring_pulse.o: Permission denied

Should give you a pretty good clue what you need to do. It appears that you do not have write permission to the file or one or more of it’s parent directories. Check the permissions on the file, and it’s parent directories, and change whichever one(s) are causing the problem.

It has nothing to do with the makefile.

At first I have to correct that I did not set ARDUINO_PATH to /usr/share/arduino-0018 but INSTALL_DIR. The problem seems to be for me that make tries to write to directories below the install dir. It is normal that an ordinary user (as user rose for example) has no right to write to /usr/share/arduino-0018/... . With the arduino-ide I can work as a ordinary user without problems. The rules in the Makefile should be changed, so that the created object files go to the local directory.

I've based my makefile on the one here. I have several CPP files in my source directory. Make clean keeps deleting the actual source, I list my files in the variable CXXFILES. on clean I have added

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) $(CXXFILES:.cpp=.d)

Even without this, all my CPP files get deleted, this is because I append my Variable to the CXXSRC variable. Any clues as to why this is deleting my CPP files. It seems that the $(OBJ) substitution is also deleting the source files since if I remove everything folllowing $(LST) my files still get deleted

The other thing I'm having problems with is getting libraries to be compiled. I can add each library source to the makefile, but that seems cumbersom, and the IDE seems to automatically find and build the library

I probably should specify the envionment.. MAC OSX Gnumake 3.81 It looks like the string substituions are not properly working