Custom Development Platforms

PlatformIO can build the same binary code under different host systems via the single command platformio run without any dependent software or requirements.

A manifest describes how to produce binaries for a particular platform under one or multiple host systems by a set of build scripts, toolchains, the settings for the most popular embedded boards, etc.

This guide explains how to write manifests, to support building for new development platforms.

Step-by-Step Manual

  1. Choose Packages for platform
  2. Create Manifest File platform.json
  3. Create Build Script main.py
  4. Finish with the Installation.

Packages

Some tools are the same when compiling for several platforms, for example a common compiler. A package is some tool or framework that can be used when compiling for one or multiple platforms. Even if multiple platforms use the same package, the package only needs to be downloaded once. Since each package is pre-built for the different host systems (Windows, Mac, Linux), developers can get started without first compiling the tools.

PlatformIO has a registry with pre-built packages for the most popular operating systems and you can use them in your platform manifest. These packages are stored in the super-fast and reliably CDN storage provided by JFrog Bintray.

Each platform definition must define packageRepositories to link to package manifest files that lists how PlatformIO can download the used packages. To use the pre-built packages, include http://dl.platformio.org/packages/manifest.json in the packageRepositories list. Platform definitions can also use custom packages.

Manifest File platform.json

Eack platform definition includes a manifest file with a particular format that is parsed by PlatformIO when handling projects using that platform.

Here is an example platform.json for the fictitious platform “myplatform”:

{
  "name": "myplatform",
  "title": "My Platform",
  "description": "My custom development platform",
  "url": "http://example.com",
  "homepage": "https://platformio.org/platforms/myplatform",
  "license": "Apache-2.0",
  "engines": {
    "platformio": "~3.0.0"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/platformio/platform-myplatform.git"
  },
  "version": "0.0.0",
  "packageRepositories": [
    "https://dl.bintray.com/platformio/dl-packages/manifest.json",
    "http://dl.platformio.org/packages/manifest.json",
    {
      "my_custom_package": [
        {
          "url": "http://dl.example.com/my_custom_package-darwin_x86_64-1.2.3.tar.gz",
          "sha1": "bb7ddac56a314b5cb1926cc1790ae4de3a03e65c",
          "version": "1.2.3",
          "system": [
              "darwin_x86_64",
              "darwin_i386"
          ]
        },
        {
          "url": "http://dl.example.com/my_custom_package-linux_aarch64-1.2.3.tar.gz",
          "sha1": "127ddac56a314b5cb1926cc1790ae4de3a03e65c",
          "version": "1.2.3",
          "system": "linux_aarch64"
        }
      ],
      "framework-%FRAMEWORK_NAME_1%": [
        {
          "url": "http://dl.example.com/packages/framework-%FRAMEWORK_NAME_1%-1.10607.0.tar.gz",
          "sha1": "adce2cd30a830d71cb6572575bf08461b7b73c07",
          "version": "1.10607.0",
          "system": "*"
        }
      ]
    }
  ],
  "frameworks": {
    "%FRAMEWORK_NAME_1%": {
      "package": "framework-%FRAMEWORK_NAME_1%",
      "script": "builder/frameworks/%FRAMEWORK_NAME_1%.py"
    },
    "%FRAMEWORK_NAME_N%": {
      "package": "framework-%FRAMEWORK_NAME_N%",
      "script": "builder/frameworks/%FRAMEWORK_NAME_N%.py"
    }
  },
  "packages": {
    "toolchain-gccarmnoneeabi": {
      "type": "toolchain",
      "version": ">=1.40803.0,<1.40805.0"
    },
    "framework-%FRAMEWORK_NAME_1%": {
      "type": "framework",
      "optional": true,
      "version": "~1.10607.0"
    },
    "framework-%FRAMEWORK_NAME_N%": {
      "type": "framework",
      "optional": true,
      "version": "~1.117.0"
    },
    "tool-direct-vcs-url": {
      "type": "uploader",
      "optional": true,
      "version": "https://github.com/user/repo.git"
    }
  }
}

Build Script main.py

Each platform definition must include a main.py.

PlatformIO’s build script is based on a next-generation build tool named SCons. PlatformIO has its own built-in firmware builder env.BuildProgram with deep library search. Please see the following template as start for developing your own main.py.

"""
    Build script for test.py
    test-builder.py
"""

from os.path import join
from SCons.Script import AlwaysBuild, Builder, Default, DefaultEnvironment

env = DefaultEnvironment()

# A full list with the available variables
# http://www.scons.org/doc/production/HTML/scons-user.html#app-variables
env.Replace(
    AR="ar",
    AS="gcc",
    CC="gcc",
    CXX="g++",
    OBJCOPY="objcopy",
    RANLIB="ranlib",

    UPLOADER=join("$PIOPACKAGES_DIR", "tool-bar", "uploader"),
    UPLOADCMD="$UPLOADER $SOURCES"
)

env.Append(
    ARFLAGS=["..."],

    ASFLAGS=["flag1", "flag2", "flagN"],
    CCFLAGS=["flag1", "flag2", "flagN"],
    CXXFLAGS=["flag1", "flag2", "flagN"],
    LINKFLAGS=["flag1", "flag2", "flagN"],

    CPPDEFINES=["DEFINE_1", "DEFINE=2", "DEFINE_N"],

    LIBS=["additional", "libs", "here"],

    BUILDERS=dict(
        ElfToBin=Builder(
            action=" ".join([
                "$OBJCOPY",
                "-O",
                "binary",
                "$SOURCES",
                "$TARGET"]),
            suffix=".bin"
        )
    )
)

# The source code of "platformio-build-tool" is here
# https://github.com/platformio/platformio-core/blob/develop/platformio/builder/tools/platformio.py

#
# Target: Build executable and linkable firmware
#
target_elf = env.BuildProgram()

#
# Target: Build the .bin file
#
target_bin = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf)

#
# Target: Upload firmware
#
upload = env.Alias(["upload"], target_bin, "$UPLOADCMD")
AlwaysBuild(upload)

#
# Target: Define targets
#
Default(target_bin)

Installation

Using the “myplatform” platform example above:

  1. Create a platforms directory in core_dir if it doesn’t exist.
  2. Create a myplatform directory in platforms
  3. Copy the platform.json and builder/main.py files to the myplatform directory.
  4. Search the available platforms via the platformio platform search command. You should see the new myplatform platform.
  5. Install the myplatform platform via the platformio platform install command.

Now, you can use myplatform as value for the platform option in “platformio.ini” (Project Configuration File).

Examples

Please take a look at the source code of existing PlatformIO Development Platforms.