Help with Advanced Scripting

i have a project where i am having difficulties with one of my advanced scripts.

The script is meant to bundle the binary files into a zip archive - however it is bundling the main.cpp.o instead of the firmware file.

Here is the script:

#!/usr/bin/env python3
Import("env")

import sys
from ntpath import basename
from zipfile import ZipFile
import json


def createZip(source, target, env):
    if (
        sys.platform.startswith("ubuntu")
        or sys.platform.startswith("Linux")
        or sys.platform.startswith("linux")
    ):
        print("Program has been built, creating zip archive!")
        my_flags = env.ParseFlags(env["BUILD_FLAGS"])
        defines = dict()
        for x in my_flags.get("CPPDEFINES"):
            if type(x) is tuple:
                (k, v) = x
                defines[k] = v
            elif type(x) is list:
                k = x[0]
                v = x[1]
                defines[k] = v
            else:
                defines[x] = ""  # empty value
        s = lambda x: x.replace('"', "")

        print("FLASH_EXTRA_IMAGES: %s\n" % env["FLASH_EXTRA_IMAGES"])
        print("ESP32_APP_OFFSET: %s\n" % env["ESP32_APP_OFFSET"])
        array_args = [env["FLASH_EXTRA_IMAGES"], env["ESP32_APP_OFFSET"]]

        for (offset, image) in env["FLASH_EXTRA_IMAGES"]:
            print("\nImage: %s" % str(image))
            array_args.append(str(offset))
            array_args.append(str(image))

        for _source in source:
            print("\nSource: %s" % str(_source))
            array_args.append(str(_source))
        n = 2
        partitions_arg = array_args[1:] 
        partitions = final = [
            partitions_arg[i * n : (i + 1) * n]
            for i in range((len(partitions_arg) + n - 1) // n)
        ]
        file_name = "./build/{0}/{1}.zip".format(str(env["PIOENV"]), env["PROGNAME"])
        with ZipFile(file_name, "w") as archive:
            print('\nCreating "' + archive.filename + '"', end="\n")
            parts = []
            for [offset, path] in partitions:
                filename = basename(path)
                archive.write(path, filename)
                partition = {
                    "path": filename,
                    "offset": int(offset, 16),
                }
                parts.append(partition)
            manifest = {
                "chipFamily": "ESP32",
                "parts": parts,
            }
            archive.writestr("manifest.json", json.dumps(manifest))
    else:
        print("Not running on Linux, skipping zip creation")


env.AddPostAction("$PROGPATH", createZip)

In particular - the issue is that the source variable is only returning the main.cpp.o file instead of the firmware binary.

This is how i call the script in the ini file

extra_scripts =
	pre:tools/customname.py
	post:tools/createzip.py

How can i solve this?

Note: The firmware binary has a custom name.

So you want the .elf or .bin instead?

env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", createZip)
1 Like

The .bin Is it really that simple? I totally blanked on that path - i feel silly. Thank you - i’ll try it and let you know.

Hmm, it’s not working i am getting the error *** [.pio\build\esp_eye\OpenIris-v1.4.0-create-zip.3-esp_eye-5aca83e-create-zip.bin] 0x8000: The system cannot find the file specified

For some reason source is now only printing as the elf and not the bin file, and it’s failing to create the zip

I’ve checked - the error comes from here:

array_args = []

for [offset, image] in env["FLASH_EXTRA_IMAGES"]:
    print("\nImage: %s" % str(image))
    array_args.append(str(offset))
    array_args.append(str(image))

It cannot find the file - even though it 100% exists.

i got it working - you were right :slight_smile: thank you for your quick asnwer.