CLI tool
plerup/makeEspArduino avatar
plerup/makeEspArduino

makeEspArduino: a make based build system for ESP8266 and ESP32 Arduino projects

A makefile for ESP8266 and ESP32 Arduino projects

546 stars131 forksPerlLGPL-2.1

At a glance

What is it?
makeEspArduino is a Makefile build system for projects that want to stay compatible with the Arduino ecosystem while building with make. It derives its recipes from the Arduino core's own platform.txt and boards.txt, discovers source and library dependencies from include directives, and can take the core either from Boards Manager through arduino-cli or from a git checkout you control.
Who is it for?
Adopt makeEspArduino if you are already building Arduino firmware for an ESP board and want reproducible command line builds that a CI system can run without the IDE. Do not adopt it if you are starting from scratch and are happy with the Arduino IDE, because the configuration surface is larger than what the IDE hides.
Can I use it commercially?
Yes, with conditions. LGPL-2.1 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 53 days ago.
What is it written in?
Mainly Perl, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the project is for

makeEspArduino provides a command-line build environment for the ESP8266 Arduino core and Arduino-ESP32, and the readme states the intent plainly: it is intended for projects that want to remain compatible with the Arduino ecosystem while using make for reproducible, automated, or production-oriented builds.

The compatibility constraint is the interesting part. Most people writing firmware for an ESP board start in the Arduino IDE, and the IDE handles an enormous amount of fiddly work behind a button: locating the toolchain, reading the board configuration, working out which libraries a sketch includes, deciding the flash layout, and then invoking the compiler with the right flags.

Reimplement that badly and you get a worse IDE. The approach here is to reuse it. The build recipes are derived from the Arduino core's platform.txt, boards.txt and related configuration files rather than being duplicated in the Makefile.

That single decision is what makes the project viable. The board definitions, the compiler flags, the memory sizes and the menu options for each board live in one place upstream, and reading them rather than copying them means a new board or a new core version does not require updating the build system.

The other thing the readme calls out is dependency discovery. Source and library dependencies are discovered recursively from include directives, and libraries may be located outside the directory hierarchy required by the Arduino IDE.

That second clause solves a real annoyance. The IDE expects libraries in a particular place, and a project that vendors its own libraries or pulls them from elsewhere has to work around it. Here, a library found by an include path is simply compiled.

The supported feature set is listed compactly: ESP8266 and ESP32 Arduino cores, Arduino Boards Manager installations, explicit ESP Arduino git checkouts, automatic source and library discovery, serial, OTA and HTTP upload, SPIFFS and LittleFS images, parallel builds and ccache, Visual Studio Code configuration generation, and crash and memory analysis tools.

The project is Perl by primary language, which makes sense for a build system whose dependency discovery works by parsing include directives out of source trees. It is LGPL-2.1 licensed and the last push was on 2026-08-31. The repository itself is small, with a LICENSE, a README, the makeEspArduino.mk makefile, an os/ directory and a tools/ directory.

Two ways to supply the core

There are two ways to provide the ESP Arduino core, and the distinction is the single most important configuration decision in the project.

The first is the Arduino package installation. If ESP_ROOT is not specified, makeEspArduino uses an ESP8266 or ESP32 core installed through the Arduino package system, and arduino-cli is required in this mode.

What arduino-cli is used for is worth being precise about, because the readme is careful here. It is the authoritative resolver for the installed platform location, the selected board and its default menu settings, compiler and SDK locations, esptool and other package-managed tools, and the Arduino build and upload properties.

The reason, stated plainly, is that this avoids depending on the internal directory structure used by Arduino Boards Manager. Boards Manager is a GUI that installs into directories whose layout is an implementation detail, and anything reading those directories directly breaks when it changes. Asking the CLI where things are is stable.

The division of labour is then explicit: the actual compilation and dependency handling are still performed by makeEspArduino, while Arduino CLI is used for configuration and package resolution. The CLI is a resolver, not the build system.

The second mode is a git checkout. If ESP_ROOT is specified, it must point to an ESP8266 Arduino or Arduino-ESP32 git checkout, and the selected checkout is used directly:

``` sh make -f makeEspArduino.mk ESP_ROOT=~/esp8266 ...

code

or for ESP32:

sh make -f makeEspArduino.mk ESP_ROOT=~/esp32 CHIP=esp32 ... ```

The readme gives three reasons this mode is useful: when a project needs strict control over the framework version, when it uses the framework as a git submodule, or when it builds against an unreleased development branch.

Those are three genuinely different situations and they share one root cause. The git checkout is pinned, so the build is reproducible in a way that a Boards Manager installation is not, where the installed version is whatever happens to be on the machine.

The cost of that mode is stated as well. The required compiler and tools must have been installed using the setup procedure provided by the corresponding upstream repository, so the checkout is not self-sufficient.

Requirements and the first build

The host requirements are short: GNU Make, Perl, Python 3, pyserial, and the tools required by the selected ESP Arduino core. For an Arduino package installation, arduino-cli is also required.

pyserial has a specific job, which is USB serial-port discovery and the built-in serial monitor, and it is installed the usual way:

``` sh python3 -m pip install pyserial

code

And makeEspArduino itself is cloned like anything else:

sh git clone https://github.com/plerup/makeEspArduino.git cd makeEspArduino

code

The quick start then depends on the mode. With a Boards Manager installation, you install the core with the Arduino IDE Boards Manager or the CLI, and the readme gives the CLI form for both platforms:

sh arduino-cli core install esp8266:esp8266

code

sh arduino-cli core install esp32:esp32

code

Then building and flashing the demo for ESP8266 is:

sh make -f makeEspArduino.mk DEMO=1 flash

code

For ESP32 you add the chip selection:

sh make -f makeEspArduino.mk CHIP=esp32 DEMO=1 flash

code

And for a specific board you set BOARD to the Arduino board identifier:

sh make -f makeEspArduino.mk CHIP=esp32 BOARD=XIAO_ESP32C6 DEMO=1 flash

code

The list of valid identifiers is discoverable rather than documented, which is the better approach for a long list:

sh make -f makeEspArduino.mk CHIP=esp32 list_boards

code

The git checkout path is longer because the upstream framework has its own setup step. The readme shows cloning the core, updating submodules, and running the tool installation script:

sh git clone https://github.com/esp8266/Arduino.git ~/esp8266 cd ~/esp8266 git submodule update --init cd tools python3 get.py ```

After which the build is the same command with ESP_ROOT set. The readme adds an important instruction for the git modes: when changing tags or branches, rerun the upstream tool installation procedure if required by that version, and always follow the tool installation instructions for the particular upstream core version, because these procedures may change between releases.

That is the price of the pinned mode. The framework's own tooling is versioned with the framework, so a version bump can require a setup step, and the readme flags it rather than letting you discover it.

Targets, boards and the flash layout

The set of common targets is short and covers the whole loop:

``` sh espmake espmake flash espmake run espmake clean espmake list_boards espmake list_lib

code

The espmake shortcut is an installed wrapper around the make invocation with the right makefile, so a normal build is just espmake with no arguments when SKETCH is not specified, in which case makeEspArduino looks for a sketch in the current directory. A sketch can also be named explicitly:

sh espmake SKETCH=/path/to/project/project.ino

code

Or reached through the core tree, which is handy for testing an example:

sh espmake SKETCH="$(ESP_ROOT)/libraries/Ticker/examples/TickerBasic/TickerBasic.ino"

code

Help is available from the makefile itself, which is where the descriptions of the available targets, configuration variables and their defaults live:

sh make -f makeEspArduino.mk help

code

Or from the installed shortcut:

sh espmake help

code

Board selection is where the two chip families diverge most sharply, and the readme is explicit that CHIP selects the platform with the values esp8266 and esp32, and that ESP8266 is the default. BOARD is the board identifier from the Arduino core's boards.txt, and the readme makes a point of saying it is not necessarily the display name shown in the Arduino IDE, which is a classic source of confusion when the two differ.

The examples given are:

sh espmake CHIP=esp8266 BOARD=generic espmake CHIP=esp32 BOARD=esp32 espmake CHIP=esp32 BOARD=XIAO_ESP32C6

code

Board-specific Arduino menu defaults are applied when the configuration is generated, and can then be overridden through the corresponding makeEspArduino variables where supported.

The flash layout is the part that needs the most care, because ESP8266 and ESP32 use different models. For ESP8266, FLASH_DEF selects the flash layout from the board's eesz or flash-size menu, and that selection controls the application layout and the filesystem region. For ESP32, FLASH_DEF is not used at all, because flash layout is defined by a partition table instead. PARTITION_SCHEME selects an Arduino PartitionScheme menu entry:

sh espmake CHIP=esp32 BOARD=esp32 PARTITION_SCHEME=huge_app ```

If PARTITION_SCHEME is empty the board or core default is used, and a custom partition table can still be supplied through PART_FILE where supported by the selected core.

Inspecting what was resolved

The last documented mechanism is the one that saves the most time when a build does not behave the way you expect.

makeEspArduino writes the effective Arduino configuration to a file inside the build directory:

``` text $(BUILD_DIR)/arduino.mk ```

The readme says this is the first place to look when comparing a makeEspArduino build with Arduino IDE or CLI behaviour. That is a much more useful framing than simply saying the file exists, because it tells you what to do with it.

The reasoning is straightforward. The whole design rests on deriving the configuration from the Arduino core's own files, and that creates a class of problem that is specific to this project: if the flags or the memory layout differ between what makeEspArduino computed and what the IDE computed, you need to know which values differ and in which direction. Dumping the resolved configuration to a file gives you something you can read and compare.

That is also why the project ships the additional tooling listed in the feature set. Visual Studio Code configuration generation produces the project files an editor needs so that the same build can be driven from an IDE, which matters for a team where some people want a terminal and others want an editor. Crash and memory analysis tools are the counterpart to the build itself, since firmware that runs out of heap is a different problem from firmware that does not compile, and the memory usage numbers come from the same resolved configuration.

The upload options are the other practical group. Serial upload is the obvious one, and pyserial handles the port discovery. OTA upload sends the firmware over the network instead of a cable, which is what you want for a device already mounted somewhere, and HTTP upload is the third option, which suits a device behind a web interface. The filesystem image support, SPIFFS and LittleFS, covers the case where the firmware needs data files alongside it.

Combined with parallel builds and ccache, the feature list is aiming at the same goal throughout: a build that is fast enough to run on every change and reproducible enough to run unattended, which is what the readme means by production-oriented builds.

Editorial conclusion

Adopt makeEspArduino if you are already building Arduino firmware for an ESP board and want reproducible command line builds that a CI system can run without the IDE. Do not adopt it if you are starting from scratch and are happy with the Arduino IDE, because the configuration surface is larger than what the IDE hides. Before you commit, decide which of the two core modes you want, since Boards Manager and git checkout have different setup procedures, and run the help target to see the full list of variables and their defaults rather than guessing at them.

Frequently asked questions

What is makeEspArduino?

It is a Makefile-based build system for ESP8266 and ESP32 Arduino projects, providing a command-line build environment for the ESP8266 Arduino core and Arduino-ESP32. It is intended for projects that want to remain compatible with the Arduino ecosystem while using make for reproducible, automated or production-oriented builds.

What is the difference between ESP_ROOT and the arduino-cli mode?

If ESP_ROOT is not specified, the core comes from an Arduino package installation and arduino-cli is required, used as the authoritative resolver for the platform location, board defaults, compiler and SDK locations and package-managed tools. If ESP_ROOT is specified, it must point to an ESP8266 or Arduino-ESP32 git checkout used directly, which is useful for strict version control, submodule use or unreleased branches.

How do I build and flash a demo for an ESP32 board?

Install the core with arduino-cli core install esp32:esp32, then run make -f makeEspArduino.mk CHIP=esp32 DEMO=1 flash for the default board or add BOARD= with a board identifier such as XIAO_ESP32C6 for a specific one. The valid identifiers can be listed with make -f makeEspArduino.mk CHIP=esp32 list_boards.

What do I need installed on my machine to use makeEspArduino?

GNU Make, Perl, Python 3, pyserial, which is used for USB serial port discovery and the built-in serial monitor and installs with python3 -m pip install pyserial, plus the tools required by the selected ESP Arduino core. For a package installation you also need arduino-cli.

How do flash layouts differ between ESP8266 and ESP32?

For ESP8266, FLASH_DEF selects the flash layout from the board's eesz or flash-size menu and that controls both the application layout and the filesystem region. For ESP32, FLASH_DEF is not used because the layout comes from a partition table, selected with PARTITION_SCHEME, for example PARTITION_SCHEME=huge_app, with the board or core default used when it is empty and a custom table possible through PART_FILE.

Official sources

  1. Issues
  2. License: LGPL-2.1
  3. plerup/makeEspArduino on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/plerup-makeesparduino.svg)](https://hysenlabs.com/projects/plerup-makeesparduino)

Was this useful?