Build example and generate merged binary. Args: example: Example name to build output_path: Optional custom output path for merged binary Returns: SketchResult with merged_bin_path populated
(
self, example: str, output_path: Optional[Path] = None
)
| 1399 | return merged_bin if merged_bin.exists() else None |
| 1400 | |
| 1401 | def build_with_merged_bin( |
| 1402 | self, example: str, output_path: Optional[Path] = None |
| 1403 | ) -> SketchResult: |
| 1404 | """Build example and generate merged binary. |
| 1405 | |
| 1406 | Args: |
| 1407 | example: Example name to build |
| 1408 | output_path: Optional custom output path for merged binary |
| 1409 | |
| 1410 | Returns: |
| 1411 | SketchResult with merged_bin_path populated |
| 1412 | """ |
| 1413 | # 1. Validate board support |
| 1414 | if not self.supports_merged_bin(): |
| 1415 | return SketchResult( |
| 1416 | success=False, |
| 1417 | output=f"Board {self.board.board_name} does not support merged binary. " |
| 1418 | f"Supported platforms: ESP32, ESP8266", |
| 1419 | build_dir=self.build_dir, |
| 1420 | example=example, |
| 1421 | ) |
| 1422 | |
| 1423 | # 2. Build normally first. |
| 1424 | # |
| 1425 | # Both backends produce the artifact set ``esptool merge_bin`` needs |
| 1426 | # (``firmware.bin`` + ``bootloader.bin`` + ``partitions.bin``), just |
| 1427 | # in different directories. ``_artifacts_dir`` returns whichever path |
| 1428 | # the active backend wrote to, so the merge step below reads from |
| 1429 | # the right place without copying anything around. |
| 1430 | # |
| 1431 | # fbuild >= 2.1.7 is required for ESP32 merged-bin support — earlier |
| 1432 | # versions did not emit the boot/partition artifacts (FastLED#2287). |
| 1433 | cancelled = threading.Event() |
| 1434 | result = self._internal_build_no_lock(example, cancelled) |
| 1435 | if not result.success: |
| 1436 | return result |
| 1437 | |
| 1438 | # 3. Use esptool to merge binaries |
| 1439 | # PlatformIO doesn't have a merge_bin target - we must use esptool directly |
| 1440 | env_name = self.board.board_name |
| 1441 | artifacts_dir = self._artifacts_dir(env_name) |
| 1442 | |
| 1443 | # Find required binary components |
| 1444 | bootloader_bin = artifacts_dir / "bootloader.bin" |
| 1445 | partitions_bin = artifacts_dir / "partitions.bin" |
| 1446 | boot_app0_bin = artifacts_dir / "boot_app0.bin" |
| 1447 | firmware_bin = artifacts_dir / "firmware.bin" |
| 1448 | |
| 1449 | # Verify all required files exist |
| 1450 | missing_files: list[str] = [] |
| 1451 | for bin_file in [bootloader_bin, partitions_bin, firmware_bin]: |
| 1452 | if not bin_file.exists(): |
| 1453 | missing_files.append(str(bin_file)) |
| 1454 | |
| 1455 | if missing_files: |
| 1456 | # The build appeared to succeed but the expected artifacts aren't |
| 1457 | # where we look for them. Most often this means the compile |
| 1458 | # actually failed earlier, or fbuild's ESP32 orchestrator skipped |