www.alxm.org

Gamebuino META Makefile

This is something I wanted to get going for a while: build my Gamebuino games with a Makefile from the command line, instead of with the Arduino IDE. I've already been using an external editor to write the code, so why not drop the IDE altogether? This was a breeze thanks to the Arduino-Makefile project.

The advantages of bypassing the IDE include much faster build times, no more waiting for the application to start, and greater control over build settings.

I ran these steps on Linux Mint 18.3 and 19.1 with the current 64bit Arduino 1.8.x from the Arduino website. Arduino-Makefile is compatible with Windows and Mac too, though!


Setup for Gamebuino Development

You first need to setup your system for Gamebuino development. For simplicity, this article assumes everything, including the IDE, is installed in your home folder, $HOME. Without repeating much, the outline is:

Test that everything is working by building one of the example sketches:

We'll come back to this sketch later, and build it with a Makefile instead.


Install Arduino-Makefile

I installed the latest Arduino-Makefile from the project's Git repo, which has support for ARM-based devices like the Arduino Zero or Gamebuino META.

1
2
$ cd ~
$ git clone https://github.com/sudar/Arduino-Makefile

Write a Project Makefile

Let's build the first example sketch from the Gamebuino library:

1
$ cd ~/Arduino/libraries/Gamebuino_META/examples/1.Basics/a_Hello

In that folder, create a new file called Makefile with this content:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# Where you unzipped the Arduino IDE and cloned Arduino-Makefile
ARDUINO_DIR = $(HOME)/arduino
ARDMK_DIR = $(HOME)/Arduino-Makefile

# Specify the custom Gamebuino board and where it's installed
BOARD_TAG = gamebuino_meta_native
ALTERNATE_CORE_PATH = \
    $(HOME)/.arduino15/packages/gamebuino/hardware/samd/1.2.1

# The Arduino libraries the game uses
ARDUINO_LIBS = Gamebuino_META SPI

# The META lib expects __SKETCH_NAME__ to be defined
CFLAGS += -D__SKETCH_NAME__=\"$(TARGET).ino\"
CXXFLAGS += -D__SKETCH_NAME__=\"$(TARGET).ino\"

# Now that everything is configured, include Arduino-Makefile
include $(ARDMK_DIR)/Sam.mk

This file tells Arduino-Makefile where all the Arduino tools and libraries are installed, so it can use them to build the project. All the variables need to be named exactly as above.

The paths on your computer may be different, you can check what they are by compiling and uploading the sketch with the IDE and looking at the output log. Make sure to enable verbose output from File > Preferences:


Build the Project

1
2
3
4
5
6
7
8
9
$ cd ~/Arduino/libraries/Gamebuino_META/examples/1.Basics/a_Hello

# Check that the Makefile you wrote is there
$ ls
a_Hello.ino Makefile

# Build project and flash BIN to device
$ make
$ make upload

PS: Build with make -j for even faster builds that take advantage of your multi-core computer.


Customize the Project

By default, the project is structured like this:

1
2
3
4
5
6
MyProject/
┗━ a_Hello/
   ┣━ a_Hello-build-gamebuino_meta_native/
   ┃  ┗━ # Gamebuino .BIN file and other build-generated files
   ┣━ a_Hello.ino
   ┗━ Makefile

However, I build my games for multiple platforms, not just Gamebuino, and I like keeping the source code, Makefiles, and build-generated objects in separate non-nested folders, like so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
MyProject/
┣━ a_Hello/
┃  ┗━ a_Hello.ino
┣━ build/
┃  ┣━ gamebuino/
┃  ┃  ┗━ # Game.bin file, and other build-generated files
┃  ┣━ windows/
┃  ┃  ┗━ # Game.exe file, and other build-generated files
┃  ┗━ ...
┗━ make/
   ┣━ Makefile.gamebuino
   ┣━ Makefile.linux
   ┣━ Makefile.windows
   ┗━ ...

To build Game.bin, I'd like to be able to do this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ cd path/to/MyProject/

$ ls
a_Hello build make

$ ls make/
Makefile.gamebuino Makefile.linux Makefile.windows ...

$ cd make/
$ make -f Makefile.gamebuino

There's a little problem though: Arduino-Makefile expects Makefile.gamebuino to be in MyProject/a_Hello instead of MyProject/make, and also that you call it from there. This is what I wrote to work around this, lines 1-32 are new:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#
# Start project config
#

# Relative to this Makefile's location (and where it's called from)
MY_PROJECT_ROOT := $(realpath ..)

MY_MAKE_DIR = $(MY_PROJECT_ROOT)/make
MY_SOURCE_DIR = $(MY_PROJECT_ROOT)/a_Hello
MY_BUILD_DIR = $(MY_PROJECT_ROOT)/a_Hello_build

#
# End project config
#

ifndef ACTUALLY_BUILD

MAKE_COMMAND := $(MAKE) \
                  -C $(MY_SOURCE_DIR) \
                  -f $(MY_MAKE_DIR)/$(lastword $(MAKEFILE_LIST)) \
                  ACTUALLY_BUILD=1

all :
    $(MAKE_COMMAND) all

clean :
    $(MAKE_COMMAND) clean

upload :
    $(MAKE_COMMAND) upload

else

# Where to place the .BIN file and build object files
OBJDIR = $(MY_BUILD_DIR)

# Where you unzipped the Arduino IDE and cloned Arduino-Makefile
ARDUINO_DIR = /opt/arduino
ARDMK_DIR = /opt/Arduino-Makefile

# Specify the custom Gamebuino board and where it's installed
BOARD_TAG = gamebuino_meta_native
ALTERNATE_CORE_PATH = \
    $(HOME)/.arduino15/packages/gamebuino/hardware/samd/1.2.1

# Libraries the game uses
ARDUINO_LIBS = Gamebuino_META SPI

# The META lib expects __SKETCH_NAME__ to be defined
CFLAGS += -D__SKETCH_NAME__=\"$(TARGET).ino\"
CXXFLAGS += -D__SKETCH_NAME__=\"$(TARGET).ino\"

# Now that everything is configured, include Arduino-Makefile
include $(ARDMK_DIR)/Sam.mk

endif

How Does It Work?

When you run it with make -f Makefile.gamebuino, it takes the branch at line 16, which handles three rules from Arduino-Makefile. Each of those rules call the makefile again recursively.

When it runs recursively, it takes the branch at line 32, where it configures and includes Arduino-Makefile as usual, but as if called from MyProject/a_Hello instead of MyProject/make.


Check What Platform You're Building For

When a code base builds for multiple platforms, it's useful to distinguish between them so you can implement platform-specific features. One option is to check if __SAMD21G18A__ is defined, which is set by both Arduino-Makefile and the official IDE:

1
2
3
4
5
#ifdef __SAMD21G18A__
    // Gamebuino META code
#else
    // Code for other platforms
#endif