├── Blink.ino ├── Makefile ├── README.md ├── arduino_without_arduino.pdf ├── cleanup.sh └── makefile_shell_version.sh /Blink.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Blink 3 | Turns on an LED on for one second, then off for one second, repeatedly. 4 | 5 | Most Arduinos have an on-board LED you can control. On the Uno and 6 | Leonardo, it is attached to digital pin 13. If you're unsure what 7 | pin the on-board LED is connected to on your Arduino model, check 8 | the documentation at http://arduino.cc 9 | 10 | This example code is in the public domain. 11 | 12 | modified 8 May 2014 13 | by Scott Fitzgerald 14 | */ 15 | 16 | 17 | // the setup function runs once when you press reset or power the board 18 | void setup() { 19 | // initialize digital pin 13 as an output. 20 | pinMode(13, OUTPUT); 21 | } 22 | 23 | // the loop function runs over and over again forever 24 | void loop() { 25 | digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) 26 | delay(1000); // wait for a second 27 | digitalWrite(13, LOW); // turn the LED off by making the voltage LOW 28 | delay(1000); // wait for a second 29 | } 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## Halfhearted attempt to make an Arduino-alike build in a Makefile 2 | ## Following from my talk "Arduino without Arduino" 3 | ## 11 May, 2015 4 | ## This is quick and dirty, but works for me. :) 5 | 6 | ## "make" will compile the core libs and link your code against them 7 | ## "make flash" will create a hex file and upload it to your Arduino 8 | 9 | ## You may need to configure some stuff. 10 | 11 | ## This is the name of the file (drop the .ino) you're trying to build 12 | TARGET = Blink 13 | 14 | ## The location of my arduino install. This will probably be different for you. 15 | 16 | # Linux 17 | ARDUINO_INSTALL = /usr/share/arduino 18 | 19 | # MacOS X 20 | # ARDUINO_INSTALL = /Applications/Arduino.app/Contents/Java 21 | 22 | ## These are standard subdirectories in Arduino. This should work. 23 | ARDUINO_TOOLS = $(ARDUINO_INSTALL)/hardware/tools/avr/bin 24 | CORE = $(ARDUINO_INSTALL)/hardware/arduino/avr/cores/arduino 25 | VARIANT = $(ARDUINO_INSTALL)/hardware/arduino/avr/variants/standard 26 | 27 | ## These tools come with Arduino. This should work. 28 | ## If not, you may need to specify the paths by hand 29 | ## Windows folks may need to append ".exe" for all I know. 30 | CC = $(ARDUINO_TOOLS)/avr-gcc 31 | CXX = $(ARDUINO_TOOLS)/avr-g++ 32 | AR = $(ARDUINO_TOOLS)/avr-ar 33 | OBJCOPY = $(ARDUINO_TOOLS)/avr-objcopy 34 | OBJDUMP = $(ARDUINO_TOOLS)/avr-objdump 35 | AVRSIZE = $(ARDUINO_TOOLS)/avr-size 36 | AVRDUDE = $(ARDUINO_TOOLS)/avrdude 37 | 38 | ## Processor type and speed 39 | MCU = atmega328p 40 | F_CPU = 16000000L 41 | 42 | ## To flash, you may need to change the -P port to match your system 43 | ## e.g. COM3 or /dev/tty.usbserialxxxxx or whatever 44 | AVRDUDE_CONFIG = $(ARDUINO_INSTALL)/hardware/tools/avr/etc/avrdude.conf 45 | AVRDUDE_OPTIONS = -C $(AVRDUDE_CONFIG) -qq -p $(MCU) -c arduino -P /dev/ttyACM0 -b 115200 -D 46 | 47 | ## These are the flags that the Arduino IDE compiles with. They seem reasonable. 48 | ## -DARDUINO_AVR_UNO is specific to the Uno board 49 | CFLAGS = -c -g -Os -w -ffunction-sections -fdata-sections 50 | CFLAGS += -MMD -mmcu=$(MCU) -DF_CPU=$(F_CPU) 51 | CFLAGS += -DARDUINO=10604 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR 52 | CFLAGS += -I. -I$(VARIANT) -I$(CORE) 53 | 54 | CXXFLAGS = -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics 55 | CXXFLAGS += -MMD -mmcu=$(MCU) -DF_CPU=$(F_CPU) 56 | CXXFLAGS += -DARDUINO=10604 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR 57 | CXXFLAGS += -I. -I$(VARIANT) -I$(CORE) 58 | 59 | 60 | ######################### You shouldn't have to edit anything below here 61 | ######################### but have a look, because this is where the action's at. 62 | 63 | ## This sets up a virtual path to the core library 64 | VPATH = $(CORE) 65 | 66 | ## Core library depends on every c/c++ file in the $(CORE) directory: 67 | CORE_SOURCES = $(wildcard $(CORE)/*.c $(CORE)/*.cpp) 68 | CORE_OBJECTS = $(addsuffix .o, $(basename $(CORE_SOURCES))) 69 | LOCAL_CORE_OBJECTS = $(notdir $(CORE_OBJECTS)) 70 | HEADERS = $(wildcard $(CORE)/*.h) $(VARIANT)/pins_arduino.h 71 | 72 | all: $(TARGET).hex core.a 73 | 74 | ## Build Arduino core library from all of the object files 75 | ## Only rebuilds core when its source changes, cleans up the related object files 76 | ## If you want to force a core rebuild, just remove core.a 77 | core.a: $(CORE_SOURCES) 78 | @echo "---------- Rebuilding the core library" 79 | $(MAKE) $(LOCAL_CORE_OBJECTS) 80 | $(AR) rcs core.a $(LOCAL_CORE_OBJECTS) 81 | rm -f $(LOCAL_CORE_OBJECTS:.o=.d) 82 | rm -f $(LOCAL_CORE_OBJECTS) 83 | 84 | ## The Arduino .ino file is just a cpp file without the include files and function prototypes 85 | ## If you've defined other functions or linked to other libraries, you'll need to add them manually. 86 | %.cpp: %.ino 87 | @echo "---------- Making $@ from $< and compiling" 88 | @echo "#include \"Arduino.h\"" | cat > $@ 89 | @echo "void setup();" | cat >> $@ 90 | @echo "void loop();" | cat >> $@ 91 | @cat $< >> $@ 92 | 93 | # Build our target file's object 94 | $(TARGET).o: $(TARGET).cpp 95 | 96 | # Link target object against core.a library 97 | $(TARGET).elf: $(TARGET).o core.a 98 | @echo "---------- Linking $< to core library" 99 | $(CC) -w -Os -Wl,--gc-sections -mmcu=$(MCU) -o $@ $< core.a -L. -lm 100 | 101 | %.hex: %.elf 102 | @echo "---------- Creating hex file: $@" 103 | $(OBJCOPY) -O ihex -R .eeprom $< $@ 104 | 105 | %.eeprom: %.elf 106 | $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ 107 | 108 | flash: $(TARGET).hex 109 | $(AVRDUDE) $(AVRDUDE_OPTIONS) -U $< 110 | 111 | clean: 112 | rm -f *.o 113 | rm -f *.d 114 | rm -f $(TARGET).cpp 115 | rm -f $(TARGET).elf 116 | rm -f $(TARGET).hex 117 | 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Notes on my experiments with creating a Makefile to replicate the Arduino build chain (as of 1.6.4). Works for me. :) 2 | 3 | I started down this path because I wanted to understand the Arduino build chain, not because I wanted a working full-service Makefile for Aduino. That is to say, there's a complexity/readability tradeoff here, and this Makefile is heavy on the quick, dirty, and minimal side. If you want something more full-service, (https://github.com/sudar/Arduino-Makefile). 4 | 5 | Basically, all I did was to set up verbose logging in the Arduino IDE, copy the log files over, figure out what it was doing, and mimic it. 6 | 7 | The bash script `makefile_shell_version.sh` does just that, and is probably most readable if you're interested in what it took. OTOH, the `Makefile` should be easier/quicker to make work on your system with less editing. 8 | 9 | 10 | ## Summary 11 | 12 | The Arduino IDE compiles everything in the core (`.c` and `.cpp` files) and throws them all into a big library function, `core.a`. 13 | 14 | Your code (or the `Blink.ino` stand-in here) is then converted into a compilable `.cpp` file, compiled, and linked against the `core.a` library. 15 | 16 | To flash this into the Arduino, it's converted to an Intel hex file and passed off to AVRDUDE. 17 | 18 | 19 | ## .ino to .cpp 20 | 21 | The only part of this process that wasn't visible in the log file is the conversion from `.ino` to `.cpp`, so I just compared `Blink.ino` with `Blink.cpp`. The differences are straightforward. The IDE seems to do the following: 22 | 23 | 1. add `include "Arduino.h"` 24 | 2. add prototype declarations for each function in the .ino file, in this case `setup()` and `loop()` 25 | 3. delete all the comments. I don't do this. Why would you? 26 | 27 | ## Try it! 28 | 29 | This is all a rough draft, but if it works (or doesn't) for you, let me know. 30 | 31 | ## Context 32 | 33 | This came out of a talk I gave ("Doing Arduino without the Arduino"). Slides attached as PDF. You kinda had to be there, though. 34 | 35 | -------------------------------------------------------------------------------- /arduino_without_arduino.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexagon5un/arduino_CLI/1689bf3c4c842e17ac167ede67a266b0c723c72a/arduino_without_arduino.pdf -------------------------------------------------------------------------------- /cleanup.sh: -------------------------------------------------------------------------------- 1 | #rm -f *.cpp 2 | rm -f *.o 3 | rm -f *.d 4 | rm -f *.h 5 | rm -f *.eep 6 | #rm -f *.elf 7 | #rm -f *.hex 8 | rm -f *.c 9 | -------------------------------------------------------------------------------- /makefile_shell_version.sh: -------------------------------------------------------------------------------- 1 | 2 | ## This shell script does what the Arduino logfile does, and is just a PoC. 3 | ## You may need to specify paths for the AVR build commands like avr-gcc etc. 4 | ## You probably have them in your Arduino install under /hardware/tools/avr/bin/ 5 | ## and the same thing with the core code files directory. 6 | ## This is intended more as a demo than a workable tool. 7 | ## The Makefile stands a better chance of working for you. 8 | 9 | ## Complete clean start: rebuild cpp file from ino 10 | echo "#include \"Arduino.h\"" | cat > Blink.cpp 11 | echo "void setup();" | cat >> Blink.cpp 12 | echo "void loop();" | cat >> Blink.cpp 13 | cat Blink.ino >> Blink.cpp 14 | 15 | 16 | echo Copy all core code files over: 17 | CORE='/usr/share/arduino/hardware/arduino/avr/cores/arduino' 18 | VARIANT='/usr/share/arduino/hardware/arduino/avr/variants/standard' 19 | cp ${CORE}/* . 20 | cp ${VARIANT}/pins_arduino.h . 21 | 22 | echo Compile core files: 23 | date 24 | for f in *.cpp 25 | do avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10604 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -I. $f -o $f.o 26 | done 27 | 28 | for f in *.c 29 | do avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10604 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -I. $f -o $f.o 30 | done 31 | 32 | echo "Add all object files into core.a, creating library" 33 | for f in *.o 34 | do avr-ar rcs core.a $f 35 | done 36 | 37 | echo Compile our code, link it in to the core library 38 | avr-gcc -w -Os -Wl,--gc-sections -mmcu=atmega328p -o Blink.cpp.elf Blink.cpp.o core.a -L. -lm 39 | 40 | echo "Add in eeprom if needed (not for Blink)" 41 | avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 Blink.cpp.elf Blink.cpp.eep 42 | 43 | echo Convert elf to hex for avrdude 44 | avr-objcopy -O ihex -R .eeprom Blink.cpp.elf Blink.cpp.hex 45 | 46 | echo Flash it 47 | avrdude -qq -p atmega328p -c arduino -P /dev/ttyACM0 -b 115200 -D -U Blink.cpp.hex 48 | 49 | echo Done 50 | 51 | 52 | --------------------------------------------------------------------------------