-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Add factory binary generation for release builds #5712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| Import("env") | ||
| import csv | ||
| import json | ||
| import os | ||
| import subprocess | ||
|
|
||
| OUTPUT_DIR = "build_output{}".format(os.path.sep) | ||
|
|
||
| def _get_cpp_define_value(env, define): | ||
| define_list = [item[-1] for item in env["CPPDEFINES"] if item[0] == define] | ||
| if define_list: | ||
| return define_list[0] | ||
| return None | ||
|
|
||
| def _get_app_offset(env): | ||
| try: | ||
| with open(env.BoardConfig().get("build.partitions")) as f: | ||
| for row in csv.reader(f): | ||
| row = [c.strip() for c in row] | ||
| if len(row) >= 4 and row[0] == "app0": | ||
| return int(row[3], 16) | ||
| except Exception: | ||
| pass | ||
| return 0x10000 | ||
|
|
||
| def create_factory_bin(source, target, env): | ||
| if env["PIOPLATFORM"] == "espressif8266": | ||
| return | ||
|
|
||
| app_bin = os.path.normpath(str(target[0])) | ||
| chip = env.get("BOARD_MCU") | ||
| flash_size = env.BoardConfig().get("upload.flash_size", "4MB") | ||
| flash_mode = env["__get_board_flash_mode"](env) | ||
| flash_freq = env["__get_board_f_flash"](env) | ||
|
Comment on lines
+33
to
+34
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🌐 Web query:
💡 Result: The functions get_board_flash_mode and get_board_f_flash are not documented, stable, or public PlatformIO API functions [1][2]. They are internal helper functions defined within specific PlatformIO development platforms, most notably the espressif32 platform [3][4][5][6]. These functions are injected into the SCons construction environment (env) by platform-specific builder scripts to facilitate the dynamic resolution of flash configuration parameters (like flash mode and flash frequency) from board configuration files during the build process [4][5][6]. Because they are implementation details of the platform's build logic, they are subject to change without notice and are not intended for use in user-level advanced scripts [1][2]. Attempting to use these functions in your own scripts can lead to runtime errors, particularly if the expected board configuration keys are missing or if the platform architecture changes [7]. If you need to access board configuration data in your scripts, you should use the official, documented methods, such as accessing the board configuration object via env.BoardConfig [1][8]. Citations:
🏁 Script executed: rg -n "__get_board_flash_mode|__get_board_f_flash|output_bins\.py|BoardConfig" .Repository: wled/WLED Length of output: 623 🏁 Script executed: sed -n '1,220p' pio-scripts/output_bins.pyRepository: wled/WLED Length of output: 2522 🏁 Script executed: rg -n "upload\.flash_mode|upload\.flash_freq|build\.flash_mode|build\.flash_freq|flash_mode|flash_freq" pio-scripts platformio.ini .Repository: wled/WLED Length of output: 3254 🏁 Script executed: sed -n '1,160p' pio-scripts/factory_bin.pyRepository: wled/WLED Length of output: 2467 🏁 Script executed: rg -n 'BoardConfig\(\)\.get\("build\.flash_mode"|BoardConfig\(\)\.get\("build\.f_flash"|BoardConfig\(\)\.get\("upload\.flash_mode"|BoardConfig\(\)\.get\("upload\.flash_freq"' .Repository: wled/WLED Length of output: 147 Avoid PlatformIO internal env hooks here. 🤖 Prompt for AI Agents
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these hooks available in pioarduino and newer tasmota framework releases, as we use them in our
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🤖 web_search executed:
Length of output: 13446
In env.Replace(
__get_board_boot_mode=_get_board_boot_mode,
__get_board_f_flash=_get_board_f_flash,
__get_board_f_image=_get_board_f_image,
__get_board_f_boot=_get_board_f_boot,
__get_board_flash_mode=_get_board_flash_mode,
__get_board_memory_type=_get_board_memory_type,
...
)This is consistent across recent pioarduino commits I looked at ( That said, my original caution still stands as a general principle: these are prefixed with double-underscore and are implementation details of the builder script (not part of PlatformIO's documented public scripting API per |
||
| app_offset = _get_app_offset(env) | ||
|
|
||
| release_name_def = _get_cpp_define_value(env, "WLED_RELEASE_NAME") | ||
| if release_name_def: | ||
| release_name = release_name_def.replace("\\\"", "") | ||
| with open("package.json") as f: | ||
| version = json.load(f)["version"] | ||
| out_file = os.path.join(OUTPUT_DIR, "release", f"WLED_{version}_{release_name}.factory.bin") | ||
| else: | ||
| out_file = os.path.join(OUTPUT_DIR, "firmware", f"{env['PIOENV']}.factory.bin") | ||
|
|
||
|
Comment on lines
+37
to
+45
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code is duplicated from The technique I ended up using with usermods was to store the relevant value in the environment. ( Probably the thing to do here is to have |
||
| os.makedirs(os.path.dirname(out_file), exist_ok=True) | ||
|
|
||
| cmd = [ | ||
| env.subst("$OBJCOPY"), | ||
| "--chip", chip, | ||
| "merge_bin", | ||
| "--output", os.path.normpath(out_file), | ||
| "--flash_mode", flash_mode, | ||
| "--flash_freq", flash_freq, | ||
| "--flash_size", flash_size, | ||
| ] | ||
|
|
||
| for section in env.subst(env.get("FLASH_EXTRA_IMAGES")): | ||
| addr, path = section.split(" ", 1) | ||
| cmd += [addr, os.path.normpath(path)] | ||
|
|
||
| cmd += [hex(app_offset), app_bin] | ||
|
|
||
| print(f"Generating factory binary: {out_file}") | ||
| result = subprocess.run(cmd, check=False, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True) | ||
| if result.returncode != 0: | ||
| print(f"Warning: factory binary generation failed:\n{result.stderr}") | ||
|
|
||
| env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", create_factory_bin) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be better to run this gate the other way around (ie.
if env["PIOPLATFORM"] != "espressif32": return).If we add support for any other platforms in the future, they'll almost certainly need a different approach.