New in version 3.4.1.
Warning
Advanced Scripting is recommended for Advanced Users and requires Python language knowledge.
We highly recommend to take a look at Dynamic build flags option where you can use any programming language. Also, this option is useful if you need to apply changes to the project before building/uploading process:
Macro with the latest VCS revision/tag “on-the-fly”
Generate dynamic headers (*.h
)
Process media content before generating SPIFFS image
Make some changes to source code or related libraries
More details Dynamic build flags.
PlatformIO Build System allows to launch custom extra_scripts (based on SCons software construction tool) while processing environment. For more details please follow to “Construction Environments” section of SCons documentation.
Warning
You can not run/debug these scripts directly with Python Interpreter. They will be loaded automatically when you processing project environment using platformio run command.
There are 2 type of extra scripts:
PRE - executes before a main script of Development Platforms
POST - executes after a main script of Development Platforms
Multiple extra scripts are allowed. Please split them via “, ” (comma + space) in the same line or use multi-line values.
For example, Project Configuration File platformio.ini
[env:my_env_1]
platform = ...
; without prefix, POST script
extra_scripts = post_extra_script.py
[env:my_env_2]
platform = ...
extra_scripts = pre:pre_extra_script1.py, pre:pre_extra_script2.py
[env:my_env_3]
platform = ...
extra_scripts =
pre:pre_extra_script.py
post:post_extra_script1.py
post_extra_script2.py
This option can be set by global environment variable
PLATFORMIO_EXTRA_SCRIPTS
.
Take a look at the multiple snippets/answers for the user questions:
PlatformIO Build System has rich API that allows to attach different pre-/post
actions (hooks) using env.AddPreAction(target, callback)
or
env.AddPreAction(target, [callback1, callback2, ...])
function. A first
argument target
can be a name of target that is passed using
platformio run --target
command, a name of built-in targets
(buildprog, size, upload, program, buildfs, uploadfs, uploadfsota) or path
to file which PlatformIO processes (ELF, HEX, BIN, OBJ, etc.).
Examples
extra_script.py
file is located on the same level as platformio.ini
.
platformio.ini
:
[env:pre_and_post_hooks]
extra_scripts = post:extra_script.py
extra_script.py
:
Import("env")
#
# Dump build environment (for debug)
# print env.Dump()
#
#
# Change build flags in runtime
#
env.ProcessUnFlags("-DVECT_TAB_ADDR")
env.Append(CPPDEFINES=("VECT_TAB_ADDR", 0x123456789))
#
# Upload actions
#
def before_upload(source, target, env):
print "before_upload"
# do some actions
# call Node.JS or other script
env.Execute("node --version")
def after_upload(source, target, env):
print "after_upload"
# do some actions
print "Current build targets", map(str, BUILD_TARGETS)
env.AddPreAction("upload", before_upload)
env.AddPostAction("upload", after_upload)
#
# Custom actions when building program/firmware
#
env.AddPreAction("buildprog", callback...)
env.AddPostAction("buildprog", callback...)
#
# Custom actions for specific files/objects
#
env.AddPreAction("$BUILD_DIR/${PROGNAME}.elf", [callback1, callback2,...])
env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", callback...)
# custom action before building SPIFFS image. For example, compress HTML, etc.
env.AddPreAction("$BUILD_DIR/spiffs.bin", callback...)
# custom action for project's main.cpp
env.AddPostAction("$BUILD_DIR/src/main.cpp.o", callback...)
# Custom HEX from ELF
env.AddPostAction(
"$BUILD_DIR/${PROGNAME}.elf",
env.VerboseAction(" ".join([
"$OBJCOPY", "-O", "ihex", "-R", ".eeprom",
"$BUILD_DIR/${PROGNAME}.elf", "$BUILD_DIR/${PROGNAME}.hex"
]), "Building $BUILD_DIR/${PROGNAME}.hex")
)
-Wl,
prefix¶Sometimes you need to pass extra flags to GCC linker without Wl,
. You could
use build_flags option but it will not work. PlatformIO
will not parse these flags to LINKFLAGS
scope. In this case, simple
extra script will help:
platformio.ini
:
[env:env_extra_link_flags]
platform = windows_x86
extra_scripts = extra_script.py
extra_script.py
(place it near platformio.ini
):
Import('env')
#
# Dump build environment (for debug)
# print env.Dump()
#
env.Append(
LINKFLAGS=[
"-static",
"-static-libgcc",
"-static-libstdc++"
]
)
Example, specify own upload command for Atmel AVR:
platformio.ini
:
[env:env_custom_uploader]
platform = atmelavr
extra_scripts = /path/to/extra_script.py
custom_option = hello
extra_script.py
:
Import('env')
from base64 import b64decode
#
# Dump build environment (for debug)
# print env.Dump()
#
env.Replace(UPLOADHEXCMD='"$UPLOADER" ' + b64decode(ARGUMENTS.get("CUSTOM_OPTION")) + ' --uploader --flags')
# uncomment line below to see environment variables
# print ARGUMENTS
Sometime is useful to have a different firmware/program name in build_dir.
platformio.ini
:
[env:env_custom_prog_name]
platform = espressif8266
board = nodemcuv2
framework = arduino
build_flags = -D VERSION=13
extra_scripts = pre:extra_script.py
extra_script.py
:
Import("env")
my_flags = env.ParseFlags(env['BUILD_FLAGS'])
defines = {k: v for (k, v) in my_flags.get("CPPDEFINES")}
# print defines
env.Replace(PROGNAME="firmware_%s" % defines.get("VERSION"))
There is a list with built-in targets which could be processed using
platformio run --target
option. You can create unlimited number of
the own targets and declare custom handlers for them.
Let’s create a simple ping
target and process it with
platformio run --target ping
command:
platformio.ini
:
[env:env_custom_target]
platform = ...
...
extra_scripts = extra_script.py
custom_ping_host = google.com
extra_script.py
:
from base64 import b64decode
from SCons.Script import ARGUMENTS, AlwaysBuild
Import("env")
def mytarget_callback(*args, **kwargs):
print "Hello PlatformIO!"
env.Execute("ping " + b64decode(ARGUMENTS.get("CUSTOM_PING_HOST")))
AlwaysBuild(env.Alias("ping", "", mytarget_callback))