Skip to content

build_release_files: read the linker memory table when size.json is missing - #11314

Merged
dhalbert merged 4 commits into
adafruit:mainfrom
MakerClassCZ:ci-language-skip-fallback
Sep 7, 2026
Merged

build_release_files: read the linker memory table when size.json is missing#11314
dhalbert merged 4 commits into
adafruit:mainfrom
MakerClassCZ:ci-language-skip-fallback

Conversation

@lynt-smitka

Copy link
Copy Markdown

On pull requests the languages other than en_US are skipped when the en_US build leaves 10 KB of headroom. That reads firmware.size.json, which raspberrypi, mimxrt10xx, broadcom, silabs, cxd56, renode and zephyr-cp never write, so every PR builds all 17 languages for every board of those ports; a Pico 2 with 190 KB free included. Their link step prints the ld memory usage table (FLASH_FIRMWARE: 1378984 B 1532 KB 87.90%), so when size.json is missing the used and region sizes are taken from that line instead.

@dhalbert dhalbert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider just fixing the ports that fail to generate firmware.size.json, or alternatively always looking in make_output for the size info?

Seven ports never write firmware.size.json, so build_release_files.py cannot
tell whether the en_US build left room and builds all 17 languages for every
board of those ports on every pull request.

They cannot use this script as it stands: it reads the region size out of a
linker script, which needs the size to be a literal there. raspberrypi writes
LENGTH = firmware_size, a symbol the board can override; broadcom, cxd56 and
silabs link a script from a submodule or an SDK; zephyr-cp has no script of its
own at all.

The linker map has the same numbers with the symbols already resolved, and
every one of these ports either writes a map already or is one flag away from
it. So read the Memory Configuration table when the file has one, and keep the
linker script path for the ports that pass one. The region name is FLASH_FIRMWARE
or FLASH, or --region for anything else.

Wired into raspberrypi, renode, mimxrt10xx, broadcom, cxd56 and silabs, which
only needed -Wl,-Map added. A missing map or an unknown region name prints what
was found and writes nothing, so the language skip falls back to today's
behaviour instead of failing the build.

zephyr-cp still needs doing; its Makefile has none of the toolchain variables.
Its makefile has none of the toolchain variables the other ports get from
circuitpy_mkenv.mk, so there is no size(1) to pipe in. There does not need to
be: what the image occupies in flash is the size of the binary, which is how
ports/espressif has always measured it. Pass --image and the region still comes
from the map.

Measured on rpi_pico: 502256 bytes used of a 1040128 byte region, against the
502000 and 1040128 Zephyr prints itself -- the difference is the 256 byte
second stage, which the .bin includes and the FLASH region does not.
Neither has a flash firmware region to measure against. cxd56 links the image
into RAM through the Spresense SDK script, so its map has one region and it is
called ram; broadcom boots kernel.img off an SD card and its regions are RAM and
READONLY. Nothing there constrains the firmware, so there is no headroom to
compute and the step only printed what it could not find.
@lynt-smitka
lynt-smitka force-pushed the ci-language-skip-fallback branch from fc7ff89 to 48e5ad1 Compare September 7, 2026 09:20
atmel-samd, analog, litex, nordic and stm were still passing their linker
script, which left the script answering the same question two ways. Their maps
carry the same numbers -- the script computed them, ld resolved them -- so point
those five at the map as well and the linker script parser, the K and M suffix
handling and the eval that needed them all come out.

What a port supplies is now one rule: the map for the region, size(1) or --image
for what is used.
@lynt-smitka

Copy link
Copy Markdown
Author

Had to dig deeper on this 🙂.

Unfortunately I could not unify everything on the make_output route, because there is no ld table line on espressif to read...

So I looked how to generate firmware.size.json instead. The current way does not work for raspberrypi, whose linker script says LENGTH = firmware_size, a symbol the board overrides; for silabs, whose script comes from the SDK; or for zephyr-cp, which has no linker script of its own.

But the linker map is the third way to get the numbers. ld resolves the region lengths there, and it is a file rather than build output.

I verified it works on the ports that were missing it.

Then I used the same route for the ports that already worked, so it is uniform.

The only exception is espressif (again - no ld region). It keeps its own script, but it writes the same firmware.size.json as everything else, so there is still just one interface.

@lynt-smitka

Copy link
Copy Markdown
Author

Results from this PR CI run:

port boards without map with map
zephyr-cp 29 16.20 h 6.12 h -62%
raspberrypi 158 7.38 h 4.79 h -35%
mimxrt10xx 16 1.00 h 0.47 h -53%
silabs 3 0.19 h 0.11 h -39%
renode 1 0.02 h 0.01 h -16%

@dhalbert dhalbert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much. This is tremendous work!

@dhalbert
dhalbert merged commit e6bf001 into adafruit:main Sep 7, 2026
427 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants