fbuild 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fbuild might be problematic. Click here for more details.

Files changed (93) hide show
  1. fbuild/__init__.py +0 -0
  2. fbuild/assets/example.txt +1 -0
  3. fbuild/build/__init__.py +117 -0
  4. fbuild/build/archive_creator.py +186 -0
  5. fbuild/build/binary_generator.py +444 -0
  6. fbuild/build/build_component_factory.py +131 -0
  7. fbuild/build/build_state.py +325 -0
  8. fbuild/build/build_utils.py +98 -0
  9. fbuild/build/compilation_executor.py +422 -0
  10. fbuild/build/compiler.py +165 -0
  11. fbuild/build/compiler_avr.py +574 -0
  12. fbuild/build/configurable_compiler.py +612 -0
  13. fbuild/build/configurable_linker.py +637 -0
  14. fbuild/build/flag_builder.py +186 -0
  15. fbuild/build/library_dependency_processor.py +185 -0
  16. fbuild/build/linker.py +708 -0
  17. fbuild/build/orchestrator.py +67 -0
  18. fbuild/build/orchestrator_avr.py +656 -0
  19. fbuild/build/orchestrator_esp32.py +797 -0
  20. fbuild/build/orchestrator_teensy.py +543 -0
  21. fbuild/build/source_compilation_orchestrator.py +220 -0
  22. fbuild/build/source_scanner.py +516 -0
  23. fbuild/cli.py +566 -0
  24. fbuild/cli_utils.py +312 -0
  25. fbuild/config/__init__.py +16 -0
  26. fbuild/config/board_config.py +457 -0
  27. fbuild/config/board_loader.py +92 -0
  28. fbuild/config/ini_parser.py +209 -0
  29. fbuild/config/mcu_specs.py +88 -0
  30. fbuild/daemon/__init__.py +34 -0
  31. fbuild/daemon/client.py +929 -0
  32. fbuild/daemon/compilation_queue.py +293 -0
  33. fbuild/daemon/daemon.py +474 -0
  34. fbuild/daemon/daemon_context.py +196 -0
  35. fbuild/daemon/error_collector.py +263 -0
  36. fbuild/daemon/file_cache.py +332 -0
  37. fbuild/daemon/lock_manager.py +270 -0
  38. fbuild/daemon/logging_utils.py +149 -0
  39. fbuild/daemon/messages.py +301 -0
  40. fbuild/daemon/operation_registry.py +288 -0
  41. fbuild/daemon/process_tracker.py +366 -0
  42. fbuild/daemon/processors/__init__.py +12 -0
  43. fbuild/daemon/processors/build_processor.py +157 -0
  44. fbuild/daemon/processors/deploy_processor.py +327 -0
  45. fbuild/daemon/processors/monitor_processor.py +146 -0
  46. fbuild/daemon/request_processor.py +401 -0
  47. fbuild/daemon/status_manager.py +216 -0
  48. fbuild/daemon/subprocess_manager.py +316 -0
  49. fbuild/deploy/__init__.py +17 -0
  50. fbuild/deploy/deployer.py +67 -0
  51. fbuild/deploy/deployer_esp32.py +314 -0
  52. fbuild/deploy/monitor.py +495 -0
  53. fbuild/interrupt_utils.py +34 -0
  54. fbuild/packages/__init__.py +53 -0
  55. fbuild/packages/archive_utils.py +1098 -0
  56. fbuild/packages/arduino_core.py +412 -0
  57. fbuild/packages/cache.py +249 -0
  58. fbuild/packages/downloader.py +366 -0
  59. fbuild/packages/framework_esp32.py +538 -0
  60. fbuild/packages/framework_teensy.py +346 -0
  61. fbuild/packages/github_utils.py +96 -0
  62. fbuild/packages/header_trampoline_cache.py +394 -0
  63. fbuild/packages/library_compiler.py +203 -0
  64. fbuild/packages/library_manager.py +549 -0
  65. fbuild/packages/library_manager_esp32.py +413 -0
  66. fbuild/packages/package.py +163 -0
  67. fbuild/packages/platform_esp32.py +383 -0
  68. fbuild/packages/platform_teensy.py +312 -0
  69. fbuild/packages/platform_utils.py +131 -0
  70. fbuild/packages/platformio_registry.py +325 -0
  71. fbuild/packages/sdk_utils.py +231 -0
  72. fbuild/packages/toolchain.py +436 -0
  73. fbuild/packages/toolchain_binaries.py +196 -0
  74. fbuild/packages/toolchain_esp32.py +484 -0
  75. fbuild/packages/toolchain_metadata.py +185 -0
  76. fbuild/packages/toolchain_teensy.py +404 -0
  77. fbuild/platform_configs/esp32.json +150 -0
  78. fbuild/platform_configs/esp32c2.json +144 -0
  79. fbuild/platform_configs/esp32c3.json +143 -0
  80. fbuild/platform_configs/esp32c5.json +151 -0
  81. fbuild/platform_configs/esp32c6.json +151 -0
  82. fbuild/platform_configs/esp32p4.json +149 -0
  83. fbuild/platform_configs/esp32s3.json +151 -0
  84. fbuild/platform_configs/imxrt1062.json +56 -0
  85. fbuild-1.1.0.dist-info/METADATA +447 -0
  86. fbuild-1.1.0.dist-info/RECORD +93 -0
  87. fbuild-1.1.0.dist-info/WHEEL +5 -0
  88. fbuild-1.1.0.dist-info/entry_points.txt +5 -0
  89. fbuild-1.1.0.dist-info/licenses/LICENSE +21 -0
  90. fbuild-1.1.0.dist-info/top_level.txt +2 -0
  91. fbuild_lint/__init__.py +0 -0
  92. fbuild_lint/ruff_plugins/__init__.py +0 -0
  93. fbuild_lint/ruff_plugins/keyboard_interrupt_checker.py +158 -0
@@ -0,0 +1,383 @@
1
+ """ESP32 Platform Package Management.
2
+
3
+ This module handles downloading, extracting, and managing ESP32 platform packages
4
+ from GitHub releases. It provides access to the Arduino-ESP32 core, toolchains,
5
+ and platform-specific tools needed for ESP32 builds.
6
+
7
+ Platform Structure (after extraction):
8
+ platform-espressif32/
9
+ ├── platform.json # Package metadata with download URLs
10
+ ├── boards/ # Board definitions (JSON files)
11
+ │ └── esp32-c6-devkitm-1.json
12
+ ├── builder/ # PlatformIO build scripts
13
+ │ └── frameworks/
14
+ │ └── arduino.py
15
+ └── ... # Other platform files
16
+
17
+ Key Packages (from platform.json):
18
+ - framework-arduinoespressif32: Arduino core (cores/, variants/)
19
+ - framework-arduinoespressif32-libs: Pre-built ESP-IDF libraries
20
+ - toolchain-riscv32-esp: RISC-V GCC (for C3, C6, H2)
21
+ - toolchain-xtensa-esp-elf: Xtensa GCC (for ESP32, S2, S3)
22
+ - tool-esptoolpy: Upload tool
23
+ """
24
+
25
+ import json
26
+ from pathlib import Path
27
+ from typing import Any, Dict, Optional
28
+
29
+ from .cache import Cache
30
+ from .downloader import DownloadError, ExtractionError, PackageDownloader
31
+ from .package import IPackage, PackageError
32
+
33
+
34
+ class PlatformErrorESP32(PackageError):
35
+ """Raised when ESP32 platform operations fail."""
36
+
37
+ pass
38
+
39
+
40
+ class PlatformESP32(IPackage):
41
+ """Manages ESP32 platform package download, extraction, and access.
42
+
43
+ This class handles the pioarduino/platform-espressif32 package which contains:
44
+ - Arduino core for ESP32 family (C3, C6, S2, S3, H2, etc.)
45
+ - Toolchains (riscv32-esp-elf-gcc, xtensa-esp-elf-gcc)
46
+ - Platform tools (esptool, mkspiffs, etc.)
47
+ - Board definitions and variants
48
+ """
49
+
50
+ def __init__(self, cache: Cache, platform_url: str, show_progress: bool = True):
51
+ """Initialize ESP32 platform manager.
52
+
53
+ Args:
54
+ cache: Cache manager instance
55
+ platform_url: URL to platform package (e.g., GitHub release ZIP)
56
+ show_progress: Whether to show download/extraction progress
57
+ """
58
+ self.cache = cache
59
+ self.platform_url = platform_url
60
+ self.show_progress = show_progress
61
+ self.downloader = PackageDownloader()
62
+
63
+ # Extract version from URL (e.g., "55.03.34" from release tag)
64
+ self.version = self._extract_version_from_url(platform_url)
65
+
66
+ # Get platform path from cache
67
+ self.platform_path = cache.get_platform_path(platform_url, self.version)
68
+
69
+ @staticmethod
70
+ def _extract_version_from_url(url: str) -> str:
71
+ """Extract version string from platform URL.
72
+
73
+ Args:
74
+ url: Platform URL (e.g., https://github.com/.../55.03.34/platform.zip)
75
+
76
+ Returns:
77
+ Version string (e.g., "55.03.34")
78
+ """
79
+ # URL format: .../releases/download/{version}/platform-espressif32.zip
80
+ parts = url.split("/")
81
+ for i, part in enumerate(parts):
82
+ if part == "download" and i + 1 < len(parts):
83
+ return parts[i + 1]
84
+
85
+ # Fallback: use URL hash if version extraction fails
86
+ from .cache import Cache
87
+
88
+ return Cache.hash_url(url)[:8]
89
+
90
+ def ensure_package(self) -> Path:
91
+ """Ensure platform is downloaded and extracted.
92
+
93
+ Returns:
94
+ Path to the extracted platform directory
95
+
96
+ Raises:
97
+ PlatformErrorESP32: If download or extraction fails
98
+ """
99
+ return self.ensure_platform()
100
+
101
+ def ensure_platform(self) -> Path:
102
+ """Ensure platform is downloaded and extracted.
103
+
104
+ Returns:
105
+ Path to the extracted platform directory
106
+
107
+ Raises:
108
+ PlatformErrorESP32: If download or extraction fails
109
+ """
110
+ if self.is_installed():
111
+ if self.show_progress:
112
+ print(f"Using cached ESP32 platform {self.version}")
113
+ return self.platform_path
114
+
115
+ try:
116
+ if self.show_progress:
117
+ print(f"Downloading ESP32 platform {self.version}...")
118
+
119
+ # Download and extract platform package
120
+ self.cache.ensure_directories()
121
+
122
+ # Use downloader to handle download and extraction
123
+ archive_name = Path(self.platform_url).name
124
+ archive_path = self.platform_path.parent / archive_name
125
+
126
+ # Download if not cached
127
+ if not archive_path.exists():
128
+ archive_path.parent.mkdir(parents=True, exist_ok=True)
129
+ self.downloader.download(self.platform_url, archive_path, show_progress=self.show_progress)
130
+ else:
131
+ if self.show_progress:
132
+ print(f"Using cached archive {archive_name}")
133
+
134
+ # Extract to platform directory
135
+ if self.show_progress:
136
+ print(f"Extracting platform to {self.platform_path}...")
137
+
138
+ # Create temp extraction directory
139
+ temp_extract = self.platform_path.parent / "temp_extract"
140
+ temp_extract.mkdir(parents=True, exist_ok=True)
141
+
142
+ self.downloader.extract_archive(archive_path, temp_extract, show_progress=self.show_progress)
143
+
144
+ # Find the platform directory in the extracted content
145
+ # Usually it's a subdirectory like "platform-espressif32/"
146
+ extracted_dirs = list(temp_extract.glob("platform-*"))
147
+ if not extracted_dirs:
148
+ # Maybe it extracted directly
149
+ extracted_dirs = [temp_extract]
150
+
151
+ source_dir = extracted_dirs[0]
152
+
153
+ # Move to final location
154
+ if self.platform_path.exists():
155
+ import shutil
156
+
157
+ shutil.rmtree(self.platform_path)
158
+
159
+ source_dir.rename(self.platform_path)
160
+
161
+ # Clean up temp directory
162
+ if temp_extract.exists() and temp_extract != self.platform_path:
163
+ import shutil
164
+
165
+ shutil.rmtree(temp_extract, ignore_errors=True)
166
+
167
+ if self.show_progress:
168
+ print(f"ESP32 platform installed to {self.platform_path}")
169
+
170
+ return self.platform_path
171
+
172
+ except (DownloadError, ExtractionError) as e:
173
+ raise PlatformErrorESP32(f"Failed to install ESP32 platform: {e}")
174
+ except KeyboardInterrupt as ke:
175
+ from fbuild.interrupt_utils import handle_keyboard_interrupt_properly
176
+
177
+ handle_keyboard_interrupt_properly(ke)
178
+ raise # Never reached, but satisfies type checker
179
+ except Exception as e:
180
+ raise PlatformErrorESP32(f"Unexpected error installing platform: {e}")
181
+
182
+ def is_installed(self) -> bool:
183
+ """Check if platform is already installed.
184
+
185
+ Returns:
186
+ True if platform directory exists with key files
187
+ """
188
+ if not self.platform_path.exists():
189
+ return False
190
+
191
+ # Verify essential platform files exist
192
+ required_files = [
193
+ self.platform_path / "platform.json",
194
+ self.platform_path / "boards",
195
+ ]
196
+
197
+ return all(f.exists() for f in required_files)
198
+
199
+ def get_platform_json(self) -> Dict[str, Any]:
200
+ """Load and parse platform.json metadata.
201
+
202
+ Returns:
203
+ Dictionary containing platform metadata
204
+
205
+ Raises:
206
+ PlatformErrorESP32: If platform.json doesn't exist or is invalid
207
+ """
208
+ platform_json_path = self.platform_path / "platform.json"
209
+
210
+ if not platform_json_path.exists():
211
+ raise PlatformErrorESP32(f"platform.json not found at {platform_json_path}. " + "Ensure platform is downloaded first.")
212
+
213
+ try:
214
+ with open(platform_json_path, "r") as f:
215
+ return json.load(f)
216
+ except json.JSONDecodeError as e:
217
+ raise PlatformErrorESP32(f"Failed to parse platform.json: {e}")
218
+ except KeyboardInterrupt as ke:
219
+ from fbuild.interrupt_utils import handle_keyboard_interrupt_properly
220
+
221
+ handle_keyboard_interrupt_properly(ke)
222
+ raise # Never reached, but satisfies type checker
223
+ except Exception as e:
224
+ raise PlatformErrorESP32(f"Failed to read platform.json: {e}")
225
+
226
+ def get_package_url(self, package_name: str) -> Optional[str]:
227
+ """Get download URL for a specific package.
228
+
229
+ Args:
230
+ package_name: Name of the package (e.g., "toolchain-riscv32-esp")
231
+
232
+ Returns:
233
+ URL string or None if package not found
234
+ """
235
+ platform_json = self.get_platform_json()
236
+ packages = platform_json.get("packages", {})
237
+
238
+ if package_name not in packages:
239
+ return None
240
+
241
+ package_info = packages[package_name]
242
+ return package_info.get("version") # "version" field contains URL
243
+
244
+ def get_required_packages(self, board_mcu: str) -> Dict[str, str]:
245
+ """Get required packages for a specific MCU.
246
+
247
+ Args:
248
+ board_mcu: MCU type (e.g., "esp32c6", "esp32s3", "esp32")
249
+
250
+ Returns:
251
+ Dictionary of package_name -> url for required packages
252
+ """
253
+ packages = {}
254
+
255
+ # All ESP32 boards need the Arduino framework
256
+ framework_url = self.get_package_url("framework-arduinoespressif32")
257
+ if framework_url:
258
+ packages["framework-arduinoespressif32"] = framework_url
259
+
260
+ libs_url = self.get_package_url("framework-arduinoespressif32-libs")
261
+ if libs_url:
262
+ packages["framework-arduinoespressif32-libs"] = libs_url
263
+
264
+ # Check for MCU-specific skeleton libraries
265
+ # These are used when the main libs package is empty or incomplete
266
+ # The naming pattern is: framework-arduino-{mcu_suffix}-skeleton-lib
267
+ # where mcu_suffix is extracted from the MCU name (e.g., "esp32c2" -> "c2")
268
+ mcu_suffix = board_mcu.replace("esp32", "")
269
+ skeleton_lib_name = f"framework-arduino-{mcu_suffix}-skeleton-lib"
270
+ skeleton_lib_url = self.get_package_url(skeleton_lib_name)
271
+ if skeleton_lib_url:
272
+ packages[skeleton_lib_name] = skeleton_lib_url
273
+
274
+ # Determine which toolchain is needed based on MCU architecture
275
+ if board_mcu in [
276
+ "esp32c3",
277
+ "esp32c6",
278
+ "esp32h2",
279
+ "esp32c2",
280
+ "esp32c5",
281
+ "esp32p4",
282
+ ]:
283
+ # RISC-V based ESP32s
284
+ toolchain_url = self.get_package_url("toolchain-riscv32-esp")
285
+ if toolchain_url:
286
+ packages["toolchain-riscv32-esp"] = toolchain_url
287
+ else:
288
+ # Xtensa based ESP32s (original ESP32, S2, S3)
289
+ toolchain_url = self.get_package_url("toolchain-xtensa-esp-elf")
290
+ if toolchain_url:
291
+ packages["toolchain-xtensa-esp-elf"] = toolchain_url
292
+
293
+ # Add esptool (needed for all ESP32 boards)
294
+ esptool_url = self.get_package_url("tool-esptoolpy")
295
+ if esptool_url:
296
+ packages["tool-esptoolpy"] = esptool_url
297
+
298
+ return packages
299
+
300
+ def get_boards_dir(self) -> Path:
301
+ """Get path to boards directory.
302
+
303
+ Returns:
304
+ Path to boards directory containing JSON board definitions
305
+ """
306
+ return self.platform_path / "boards"
307
+
308
+ def get_board_json(self, board_id: str) -> Dict[str, Any]:
309
+ """Load board configuration from JSON.
310
+
311
+ Args:
312
+ board_id: Board identifier (e.g., "esp32-c6-devkitm-1")
313
+
314
+ Returns:
315
+ Dictionary containing board configuration
316
+
317
+ Raises:
318
+ PlatformErrorESP32: If board JSON doesn't exist or is invalid
319
+ """
320
+ board_json_path = self.get_boards_dir() / f"{board_id}.json"
321
+
322
+ if not board_json_path.exists():
323
+ raise PlatformErrorESP32(f"Board definition not found: {board_id} " + f"at {board_json_path}")
324
+
325
+ try:
326
+ with open(board_json_path, "r") as f:
327
+ return json.load(f)
328
+ except json.JSONDecodeError as e:
329
+ raise PlatformErrorESP32(f"Failed to parse board JSON: {e}")
330
+ except KeyboardInterrupt as ke:
331
+ from fbuild.interrupt_utils import handle_keyboard_interrupt_properly
332
+
333
+ handle_keyboard_interrupt_properly(ke)
334
+ raise # Never reached, but satisfies type checker
335
+ except Exception as e:
336
+ raise PlatformErrorESP32(f"Failed to read board JSON: {e}")
337
+
338
+ def list_boards(self) -> list[str]:
339
+ """List all available board IDs.
340
+
341
+ Returns:
342
+ List of board identifiers
343
+ """
344
+ boards_dir = self.get_boards_dir()
345
+ if not boards_dir.exists():
346
+ return []
347
+
348
+ return [f.stem for f in boards_dir.glob("*.json") if f.is_file() and not f.name.endswith(".py")]
349
+
350
+ def get_package_info(self) -> Dict[str, Any]:
351
+ """Get information about the installed platform.
352
+
353
+ Returns:
354
+ Dictionary with platform information
355
+ """
356
+ return self.get_platform_info()
357
+
358
+ def get_platform_info(self) -> Dict[str, Any]:
359
+ """Get information about the installed platform.
360
+
361
+ Returns:
362
+ Dictionary with platform information
363
+ """
364
+ info = {
365
+ "version": self.version,
366
+ "path": str(self.platform_path),
367
+ "url": self.platform_url,
368
+ "installed": self.is_installed(),
369
+ }
370
+
371
+ if self.is_installed():
372
+ info["boards_dir"] = str(self.get_boards_dir())
373
+ info["available_boards"] = len(self.list_boards())
374
+
375
+ # Get package information
376
+ try:
377
+ platform_json = self.get_platform_json()
378
+ info["platform_version"] = platform_json.get("version")
379
+ info["available_packages"] = list(platform_json.get("packages", {}).keys())
380
+ except PlatformErrorESP32:
381
+ pass
382
+
383
+ return info
@@ -0,0 +1,312 @@
1
+ """Teensy Platform Package Management.
2
+
3
+ This module coordinates Teensy platform components including toolchain and framework.
4
+ It provides a unified interface for managing Teensy 4.x platform builds.
5
+
6
+ Platform Components:
7
+ - ARM GCC Toolchain (arm-none-eabi-gcc)
8
+ - Teensy Cores Framework (Arduino core for Teensy 4.x)
9
+
10
+ Supported Boards:
11
+ - Teensy 4.1 (NXP i.MX RT1062, ARM Cortex-M7 @ 600MHz)
12
+ - Teensy 4.0 (NXP i.MX RT1062, ARM Cortex-M7 @ 600MHz)
13
+ """
14
+
15
+ from pathlib import Path
16
+ from typing import Any, Dict, List
17
+
18
+ from .cache import Cache
19
+ from .framework_teensy import FrameworkErrorTeensy, FrameworkTeensy
20
+ from .package import IPackage, PackageError
21
+ from .toolchain_teensy import ToolchainErrorTeensy, ToolchainTeensy
22
+
23
+
24
+ class PlatformErrorTeensy(PackageError):
25
+ """Raised when Teensy platform operations fail."""
26
+
27
+ pass
28
+
29
+
30
+ class PlatformTeensy(IPackage):
31
+ """Manages Teensy platform components and configuration.
32
+
33
+ This class coordinates the Teensy toolchain and framework to provide
34
+ a complete build environment for Teensy 4.x boards.
35
+ """
36
+
37
+ def __init__(self, cache: Cache, board_mcu: str, show_progress: bool = True):
38
+ """Initialize Teensy platform manager.
39
+
40
+ Args:
41
+ cache: Cache manager instance
42
+ board_mcu: MCU type (e.g., "imxrt1062")
43
+ show_progress: Whether to show download/extraction progress
44
+ """
45
+ self.cache = cache
46
+ self.board_mcu = board_mcu
47
+ self.show_progress = show_progress
48
+
49
+ # Initialize toolchain and framework
50
+ self.toolchain = ToolchainTeensy(cache, show_progress=show_progress)
51
+ self.framework = FrameworkTeensy(cache, show_progress=show_progress)
52
+
53
+ def ensure_package(self) -> Path:
54
+ """Ensure platform components are downloaded and extracted.
55
+
56
+ Returns:
57
+ Path to the framework directory (main platform directory)
58
+
59
+ Raises:
60
+ PlatformErrorTeensy: If download or extraction fails
61
+ """
62
+ try:
63
+ # Ensure toolchain is installed
64
+ self.toolchain.ensure_toolchain()
65
+
66
+ # Ensure framework is installed
67
+ framework_path = self.framework.ensure_framework()
68
+
69
+ return framework_path
70
+
71
+ except (ToolchainErrorTeensy, FrameworkErrorTeensy) as e:
72
+ raise PlatformErrorTeensy(f"Failed to install Teensy platform: {e}")
73
+ except KeyboardInterrupt as ke:
74
+ from fbuild.interrupt_utils import handle_keyboard_interrupt_properly
75
+
76
+ handle_keyboard_interrupt_properly(ke)
77
+ raise # Never reached, but satisfies type checker
78
+ except Exception as e:
79
+ raise PlatformErrorTeensy(f"Unexpected error installing platform: {e}")
80
+
81
+ def is_installed(self) -> bool:
82
+ """Check if platform is already installed.
83
+
84
+ Returns:
85
+ True if both toolchain and framework are installed
86
+ """
87
+ return self.toolchain.is_installed() and self.framework.is_installed()
88
+
89
+ def get_compiler_flags(self, board_config: Any) -> List[str]:
90
+ """Get compiler flags for Teensy builds.
91
+
92
+ Args:
93
+ board_config: Board configuration object
94
+
95
+ Returns:
96
+ List of compiler flags
97
+ """
98
+ flags = [
99
+ # CPU and architecture
100
+ "-mcpu=cortex-m7",
101
+ "-mthumb",
102
+ "-mfloat-abi=hard",
103
+ "-mfpu=fpv5-d16",
104
+ # Optimization
105
+ "-O2",
106
+ "-g",
107
+ # Warnings
108
+ "-Wall",
109
+ "-Wextra",
110
+ "-Wno-unused-parameter",
111
+ # Standards
112
+ "-std=gnu11", # For C files
113
+ # Board-specific defines
114
+ f"-DF_CPU={board_config.f_cpu}",
115
+ "-DARDUINO_TEENSY41",
116
+ "-D__IMXRT1062__",
117
+ "-DARDUINO=10819",
118
+ "-DTEENSYDUINO=159",
119
+ "-DUSB_SERIAL",
120
+ # Memory layout
121
+ "-DARDUINO_ARCH_TEENSY",
122
+ ]
123
+
124
+ return flags
125
+
126
+ def get_compiler_flags_cpp(self, board_config: Any) -> List[str]:
127
+ """Get C++ compiler flags for Teensy builds.
128
+
129
+ Args:
130
+ board_config: Board configuration object
131
+
132
+ Returns:
133
+ List of C++ compiler flags
134
+ """
135
+ # Start with base C flags
136
+ flags = self.get_compiler_flags(board_config)
137
+
138
+ # Replace C standard with C++ standard
139
+ flags = [f for f in flags if not f.startswith("-std=gnu11")]
140
+ flags.extend(
141
+ [
142
+ "-std=gnu++14",
143
+ "-fno-exceptions",
144
+ "-fno-rtti",
145
+ "-felide-constructors",
146
+ "-fno-threadsafe-statics",
147
+ ]
148
+ )
149
+
150
+ return flags
151
+
152
+ def get_linker_flags(self, board_config: Any, board_id: str = "teensy41") -> List[str]:
153
+ """Get linker flags for Teensy builds.
154
+
155
+ Args:
156
+ board_config: Board configuration object
157
+ board_id: Board identifier for linker script selection
158
+
159
+ Returns:
160
+ List of linker flags
161
+ """
162
+ # Get linker script
163
+ linker_script = self.framework.get_linker_script(board_id)
164
+ if not linker_script:
165
+ raise PlatformErrorTeensy(f"Linker script not found for board: {board_id}")
166
+
167
+ flags = [
168
+ # CPU and architecture
169
+ "-mcpu=cortex-m7",
170
+ "-mthumb",
171
+ "-mfloat-abi=hard",
172
+ "-mfpu=fpv5-d16",
173
+ # Optimization
174
+ "-O2",
175
+ # Linker script
176
+ f"-T{linker_script}",
177
+ # Linker options
178
+ "-Wl,--gc-sections",
179
+ "-Wl,--print-memory-usage",
180
+ # Math library
181
+ "-lm",
182
+ "-lstdc++",
183
+ ]
184
+
185
+ return flags
186
+
187
+ def get_include_dirs(self, board_config: Any) -> List[Path]:
188
+ """Get include directories for Teensy builds.
189
+
190
+ Args:
191
+ board_config: Board configuration object
192
+
193
+ Returns:
194
+ List of include directory paths
195
+ """
196
+ includes = []
197
+
198
+ # Core includes
199
+ try:
200
+ core_includes = self.framework.get_core_includes("teensy4")
201
+ includes.extend(core_includes)
202
+ except FrameworkErrorTeensy:
203
+ pass
204
+
205
+ return includes
206
+
207
+ def get_core_sources(self) -> List[Path]:
208
+ """Get core source files for Teensy builds.
209
+
210
+ Returns:
211
+ List of core source file paths
212
+ """
213
+ try:
214
+ return self.framework.get_core_sources("teensy4")
215
+ except FrameworkErrorTeensy:
216
+ return []
217
+
218
+ def get_toolchain_binaries(self) -> Dict[str, Path]:
219
+ """Get paths to toolchain binaries.
220
+
221
+ Returns:
222
+ Dictionary mapping tool names to paths
223
+
224
+ Raises:
225
+ PlatformErrorTeensy: If toolchain binaries are not found
226
+ """
227
+ tools = self.toolchain.get_all_tool_paths()
228
+
229
+ # Verify all required tools exist
230
+ required_tools = ["gcc", "g++", "ar", "objcopy", "size"]
231
+ for tool_name in required_tools:
232
+ if tool_name not in tools or tools[tool_name] is None:
233
+ raise PlatformErrorTeensy(f"Required tool not found: {tool_name}")
234
+
235
+ # Filter out None values
236
+ return {name: path for name, path in tools.items() if path is not None}
237
+
238
+ def get_package_info(self) -> Dict[str, Any]:
239
+ """Get information about the installed platform.
240
+
241
+ Returns:
242
+ Dictionary with platform information
243
+ """
244
+ return self.get_platform_info()
245
+
246
+ def get_board_json(self, board_id: str) -> Dict[str, Any]:
247
+ """Get board configuration in JSON format.
248
+
249
+ This method returns board configuration compatible with the format
250
+ expected by ConfigurableCompiler and ConfigurableLinker.
251
+
252
+ Args:
253
+ board_id: Board identifier (e.g., "teensy41")
254
+
255
+ Returns:
256
+ Dictionary containing board configuration
257
+
258
+ Raises:
259
+ PlatformErrorTeensy: If board is not supported
260
+ """
261
+ # Map board IDs to their configurations
262
+ board_configs = {
263
+ "teensy41": {
264
+ "build": {
265
+ "mcu": "imxrt1062",
266
+ "f_cpu": "600000000L",
267
+ "core": "teensy4",
268
+ "variant": "teensy41",
269
+ "board": "TEENSY41",
270
+ },
271
+ "name": "Teensy 4.1",
272
+ "upload": {
273
+ "maximum_size": 8126464,
274
+ "maximum_ram_size": 524288,
275
+ },
276
+ },
277
+ "teensy40": {
278
+ "build": {
279
+ "mcu": "imxrt1062",
280
+ "f_cpu": "600000000L",
281
+ "core": "teensy4",
282
+ "variant": "teensy40",
283
+ "board": "TEENSY40",
284
+ },
285
+ "name": "Teensy 4.0",
286
+ "upload": {
287
+ "maximum_size": 2031616,
288
+ "maximum_ram_size": 524288,
289
+ },
290
+ },
291
+ }
292
+
293
+ if board_id not in board_configs:
294
+ raise PlatformErrorTeensy(f"Unsupported board: {board_id}. " + f"Supported boards: {', '.join(board_configs.keys())}")
295
+
296
+ return board_configs[board_id]
297
+
298
+ def get_platform_info(self) -> Dict[str, Any]:
299
+ """Get information about the installed platform.
300
+
301
+ Returns:
302
+ Dictionary with platform information
303
+ """
304
+ info = {
305
+ "platform": "teensy",
306
+ "mcu": self.board_mcu,
307
+ "installed": self.is_installed(),
308
+ "toolchain": self.toolchain.get_toolchain_info(),
309
+ "framework": self.framework.get_framework_info(),
310
+ }
311
+
312
+ return info