fbuild 1.2.8__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.
- fbuild/__init__.py +390 -0
- fbuild/assets/example.txt +1 -0
- fbuild/build/__init__.py +117 -0
- fbuild/build/archive_creator.py +186 -0
- fbuild/build/binary_generator.py +444 -0
- fbuild/build/build_component_factory.py +131 -0
- fbuild/build/build_info_generator.py +624 -0
- fbuild/build/build_state.py +325 -0
- fbuild/build/build_utils.py +93 -0
- fbuild/build/compilation_executor.py +422 -0
- fbuild/build/compiler.py +165 -0
- fbuild/build/compiler_avr.py +574 -0
- fbuild/build/configurable_compiler.py +664 -0
- fbuild/build/configurable_linker.py +637 -0
- fbuild/build/flag_builder.py +214 -0
- fbuild/build/library_dependency_processor.py +185 -0
- fbuild/build/linker.py +708 -0
- fbuild/build/orchestrator.py +67 -0
- fbuild/build/orchestrator_avr.py +651 -0
- fbuild/build/orchestrator_esp32.py +878 -0
- fbuild/build/orchestrator_rp2040.py +719 -0
- fbuild/build/orchestrator_stm32.py +696 -0
- fbuild/build/orchestrator_teensy.py +580 -0
- fbuild/build/source_compilation_orchestrator.py +218 -0
- fbuild/build/source_scanner.py +516 -0
- fbuild/cli.py +717 -0
- fbuild/cli_utils.py +314 -0
- fbuild/config/__init__.py +16 -0
- fbuild/config/board_config.py +542 -0
- fbuild/config/board_loader.py +92 -0
- fbuild/config/ini_parser.py +369 -0
- fbuild/config/mcu_specs.py +88 -0
- fbuild/daemon/__init__.py +42 -0
- fbuild/daemon/async_client.py +531 -0
- fbuild/daemon/client.py +1505 -0
- fbuild/daemon/compilation_queue.py +293 -0
- fbuild/daemon/configuration_lock.py +865 -0
- fbuild/daemon/daemon.py +585 -0
- fbuild/daemon/daemon_context.py +293 -0
- fbuild/daemon/error_collector.py +263 -0
- fbuild/daemon/file_cache.py +332 -0
- fbuild/daemon/firmware_ledger.py +546 -0
- fbuild/daemon/lock_manager.py +508 -0
- fbuild/daemon/logging_utils.py +149 -0
- fbuild/daemon/messages.py +957 -0
- fbuild/daemon/operation_registry.py +288 -0
- fbuild/daemon/port_state_manager.py +249 -0
- fbuild/daemon/process_tracker.py +366 -0
- fbuild/daemon/processors/__init__.py +18 -0
- fbuild/daemon/processors/build_processor.py +248 -0
- fbuild/daemon/processors/deploy_processor.py +664 -0
- fbuild/daemon/processors/install_deps_processor.py +431 -0
- fbuild/daemon/processors/locking_processor.py +777 -0
- fbuild/daemon/processors/monitor_processor.py +285 -0
- fbuild/daemon/request_processor.py +457 -0
- fbuild/daemon/shared_serial.py +819 -0
- fbuild/daemon/status_manager.py +238 -0
- fbuild/daemon/subprocess_manager.py +316 -0
- fbuild/deploy/__init__.py +21 -0
- fbuild/deploy/deployer.py +67 -0
- fbuild/deploy/deployer_esp32.py +310 -0
- fbuild/deploy/docker_utils.py +315 -0
- fbuild/deploy/monitor.py +519 -0
- fbuild/deploy/qemu_runner.py +603 -0
- fbuild/interrupt_utils.py +34 -0
- fbuild/ledger/__init__.py +52 -0
- fbuild/ledger/board_ledger.py +560 -0
- fbuild/output.py +352 -0
- fbuild/packages/__init__.py +66 -0
- fbuild/packages/archive_utils.py +1098 -0
- fbuild/packages/arduino_core.py +412 -0
- fbuild/packages/cache.py +256 -0
- fbuild/packages/concurrent_manager.py +510 -0
- fbuild/packages/downloader.py +518 -0
- fbuild/packages/fingerprint.py +423 -0
- fbuild/packages/framework_esp32.py +538 -0
- fbuild/packages/framework_rp2040.py +349 -0
- fbuild/packages/framework_stm32.py +459 -0
- fbuild/packages/framework_teensy.py +346 -0
- fbuild/packages/github_utils.py +96 -0
- fbuild/packages/header_trampoline_cache.py +394 -0
- fbuild/packages/library_compiler.py +203 -0
- fbuild/packages/library_manager.py +549 -0
- fbuild/packages/library_manager_esp32.py +725 -0
- fbuild/packages/package.py +163 -0
- fbuild/packages/platform_esp32.py +383 -0
- fbuild/packages/platform_rp2040.py +400 -0
- fbuild/packages/platform_stm32.py +581 -0
- fbuild/packages/platform_teensy.py +312 -0
- fbuild/packages/platform_utils.py +131 -0
- fbuild/packages/platformio_registry.py +369 -0
- fbuild/packages/sdk_utils.py +231 -0
- fbuild/packages/toolchain.py +436 -0
- fbuild/packages/toolchain_binaries.py +196 -0
- fbuild/packages/toolchain_esp32.py +489 -0
- fbuild/packages/toolchain_metadata.py +185 -0
- fbuild/packages/toolchain_rp2040.py +436 -0
- fbuild/packages/toolchain_stm32.py +417 -0
- fbuild/packages/toolchain_teensy.py +404 -0
- fbuild/platform_configs/esp32.json +150 -0
- fbuild/platform_configs/esp32c2.json +144 -0
- fbuild/platform_configs/esp32c3.json +143 -0
- fbuild/platform_configs/esp32c5.json +151 -0
- fbuild/platform_configs/esp32c6.json +151 -0
- fbuild/platform_configs/esp32p4.json +149 -0
- fbuild/platform_configs/esp32s3.json +151 -0
- fbuild/platform_configs/imxrt1062.json +56 -0
- fbuild/platform_configs/rp2040.json +70 -0
- fbuild/platform_configs/rp2350.json +76 -0
- fbuild/platform_configs/stm32f1.json +59 -0
- fbuild/platform_configs/stm32f4.json +63 -0
- fbuild/py.typed +0 -0
- fbuild-1.2.8.dist-info/METADATA +468 -0
- fbuild-1.2.8.dist-info/RECORD +121 -0
- fbuild-1.2.8.dist-info/WHEEL +5 -0
- fbuild-1.2.8.dist-info/entry_points.txt +5 -0
- fbuild-1.2.8.dist-info/licenses/LICENSE +21 -0
- fbuild-1.2.8.dist-info/top_level.txt +2 -0
- fbuild_lint/__init__.py +0 -0
- fbuild_lint/ruff_plugins/__init__.py +0 -0
- fbuild_lint/ruff_plugins/keyboard_interrupt_checker.py +158 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
"""RP2040/RP2350 Toolchain Management.
|
|
2
|
+
|
|
3
|
+
This module handles downloading, extracting, and managing ARM GCC toolchain
|
|
4
|
+
needed for Raspberry Pi Pico (RP2040) and Pico 2 (RP2350) builds.
|
|
5
|
+
|
|
6
|
+
Toolchain Download Process:
|
|
7
|
+
1. Download ARM GCC toolchain for ARM Cortex-M
|
|
8
|
+
2. Extract to cache directory
|
|
9
|
+
3. Provide access to compiler binaries
|
|
10
|
+
|
|
11
|
+
Toolchain Structure (after extraction):
|
|
12
|
+
arm-none-eabi/
|
|
13
|
+
├── bin/
|
|
14
|
+
│ ├── arm-none-eabi-gcc.exe
|
|
15
|
+
│ ├── arm-none-eabi-g++.exe
|
|
16
|
+
│ ├── arm-none-eabi-ar.exe
|
|
17
|
+
│ ├── arm-none-eabi-objcopy.exe
|
|
18
|
+
│ └── ...
|
|
19
|
+
├── lib/
|
|
20
|
+
└── include/
|
|
21
|
+
|
|
22
|
+
Supported Boards:
|
|
23
|
+
- Raspberry Pi Pico (RP2040, ARM Cortex-M0+ @ 133MHz)
|
|
24
|
+
- Raspberry Pi Pico W (RP2040, ARM Cortex-M0+ @ 133MHz)
|
|
25
|
+
- Raspberry Pi Pico 2 (RP2350, ARM Cortex-M33 @ 150MHz)
|
|
26
|
+
- Raspberry Pi Pico 2 W (RP2350, ARM Cortex-M33 @ 150MHz)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
import platform
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from typing import Any, Dict, Optional
|
|
32
|
+
|
|
33
|
+
from .cache import Cache
|
|
34
|
+
from .downloader import DownloadError, ExtractionError, PackageDownloader
|
|
35
|
+
from .package import IToolchain, PackageError
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ToolchainErrorRP2040(PackageError):
|
|
39
|
+
"""Raised when RP2040/RP2350 toolchain operations fail."""
|
|
40
|
+
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ToolchainRP2040(IToolchain):
|
|
45
|
+
"""Manages RP2040/RP2350 toolchain download, extraction, and access.
|
|
46
|
+
|
|
47
|
+
This class handles downloading and managing ARM GCC toolchain for RP2040/RP2350:
|
|
48
|
+
- ARM GCC for RP2040 (ARM Cortex-M0+)
|
|
49
|
+
- ARM GCC for RP2350 (ARM Cortex-M33)
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
# Binary prefix for ARM GCC toolchain
|
|
53
|
+
BINARY_PREFIX = "arm-none-eabi-"
|
|
54
|
+
|
|
55
|
+
# Toolchain download URLs for different platforms
|
|
56
|
+
# Source: https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
|
|
57
|
+
# Version 15.2.Rel1 (released December 17, 2025)
|
|
58
|
+
TOOLCHAIN_URLS = {
|
|
59
|
+
"Windows": "https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.2.rel1-mingw-w64-x86_64-arm-none-eabi.zip",
|
|
60
|
+
"Linux": "https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi.tar.xz",
|
|
61
|
+
"Darwin": "https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.2.rel1-darwin-x86_64-arm-none-eabi.tar.xz",
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
cache: Cache,
|
|
67
|
+
show_progress: bool = True,
|
|
68
|
+
):
|
|
69
|
+
"""Initialize RP2040/RP2350 toolchain manager.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
cache: Cache manager instance
|
|
73
|
+
show_progress: Whether to show download/extraction progress
|
|
74
|
+
"""
|
|
75
|
+
self.cache = cache
|
|
76
|
+
self.show_progress = show_progress
|
|
77
|
+
self.downloader = PackageDownloader()
|
|
78
|
+
|
|
79
|
+
# Get platform-specific toolchain URL
|
|
80
|
+
self.toolchain_url = self._get_platform_toolchain_url()
|
|
81
|
+
|
|
82
|
+
# Extract version from URL
|
|
83
|
+
self.version = self._extract_version_from_url(self.toolchain_url)
|
|
84
|
+
|
|
85
|
+
# Get toolchain path from cache
|
|
86
|
+
self.toolchain_path = cache.get_toolchain_path(self.toolchain_url, self.version)
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def _get_platform_toolchain_url() -> str:
|
|
90
|
+
"""Get toolchain URL for the current platform.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
URL to platform-specific toolchain archive
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
ToolchainErrorRP2040: If platform is not supported
|
|
97
|
+
"""
|
|
98
|
+
system = platform.system()
|
|
99
|
+
if system not in ToolchainRP2040.TOOLCHAIN_URLS:
|
|
100
|
+
raise ToolchainErrorRP2040(f"Unsupported platform: {system}. " + f"Supported platforms: {', '.join(ToolchainRP2040.TOOLCHAIN_URLS.keys())}")
|
|
101
|
+
return ToolchainRP2040.TOOLCHAIN_URLS[system]
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def _extract_version_from_url(url: str) -> str:
|
|
105
|
+
"""Extract version string from toolchain URL.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
url: Toolchain URL
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
Version string (e.g., "15.2.rel1")
|
|
112
|
+
"""
|
|
113
|
+
# Extract version from URL pattern: .../15.2.rel1/...
|
|
114
|
+
parts = url.split("/")
|
|
115
|
+
for part in parts:
|
|
116
|
+
if "rel" in part.lower() and part[0].isdigit():
|
|
117
|
+
return part
|
|
118
|
+
|
|
119
|
+
# Fallback: use URL hash if version extraction fails
|
|
120
|
+
from .cache import Cache
|
|
121
|
+
|
|
122
|
+
return Cache.hash_url(url)[:8]
|
|
123
|
+
|
|
124
|
+
def ensure_toolchain(self) -> Path:
|
|
125
|
+
"""Ensure toolchain is downloaded and extracted.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Path to the extracted toolchain directory
|
|
129
|
+
|
|
130
|
+
Raises:
|
|
131
|
+
ToolchainErrorRP2040: If download or extraction fails
|
|
132
|
+
"""
|
|
133
|
+
if self.is_installed():
|
|
134
|
+
if self.show_progress:
|
|
135
|
+
print(f"Using cached ARM GCC toolchain {self.version}")
|
|
136
|
+
return self.toolchain_path
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
if self.show_progress:
|
|
140
|
+
print(f"Downloading ARM GCC toolchain {self.version}...")
|
|
141
|
+
|
|
142
|
+
# Download and extract toolchain package
|
|
143
|
+
self.cache.ensure_directories()
|
|
144
|
+
|
|
145
|
+
# Use downloader to handle download and extraction
|
|
146
|
+
archive_name = Path(self.toolchain_url).name
|
|
147
|
+
toolchain_cache_dir = self.toolchain_path.parent / "bin"
|
|
148
|
+
toolchain_cache_dir.mkdir(parents=True, exist_ok=True)
|
|
149
|
+
archive_path = toolchain_cache_dir / archive_name
|
|
150
|
+
|
|
151
|
+
# Download if not cached
|
|
152
|
+
if not archive_path.exists():
|
|
153
|
+
self.downloader.download(self.toolchain_url, archive_path, show_progress=self.show_progress)
|
|
154
|
+
else:
|
|
155
|
+
if self.show_progress:
|
|
156
|
+
print("Using cached toolchain archive")
|
|
157
|
+
|
|
158
|
+
# Extract to toolchain directory
|
|
159
|
+
if self.show_progress:
|
|
160
|
+
print("Extracting toolchain...")
|
|
161
|
+
|
|
162
|
+
# Create temp extraction directory
|
|
163
|
+
temp_extract = toolchain_cache_dir / "temp_extract"
|
|
164
|
+
temp_extract.mkdir(parents=True, exist_ok=True)
|
|
165
|
+
|
|
166
|
+
self.downloader.extract_archive(archive_path, temp_extract, show_progress=self.show_progress)
|
|
167
|
+
|
|
168
|
+
# Find the toolchain directory in the extracted content
|
|
169
|
+
# Usually it's a subdirectory like "arm-gnu-toolchain-15.2.rel1-..."
|
|
170
|
+
extracted_dirs = list(temp_extract.glob("arm-gnu-toolchain-*"))
|
|
171
|
+
if not extracted_dirs:
|
|
172
|
+
# Maybe it extracted directly
|
|
173
|
+
extracted_dirs = [temp_extract]
|
|
174
|
+
|
|
175
|
+
source_dir = extracted_dirs[0]
|
|
176
|
+
|
|
177
|
+
# Move to final location (toolchain_path/bin)
|
|
178
|
+
final_bin_path = toolchain_cache_dir
|
|
179
|
+
if final_bin_path.exists() and final_bin_path != temp_extract:
|
|
180
|
+
# Remove old installation
|
|
181
|
+
import shutil
|
|
182
|
+
|
|
183
|
+
for item in final_bin_path.iterdir():
|
|
184
|
+
if item.name != "temp_extract" and not item.name.endswith((".zip", ".tar", ".xz", ".gz")):
|
|
185
|
+
if item.is_dir():
|
|
186
|
+
shutil.rmtree(item)
|
|
187
|
+
else:
|
|
188
|
+
item.unlink()
|
|
189
|
+
|
|
190
|
+
# Copy contents from source_dir to final_bin_path
|
|
191
|
+
import shutil
|
|
192
|
+
|
|
193
|
+
for item in source_dir.iterdir():
|
|
194
|
+
dest = final_bin_path / item.name
|
|
195
|
+
if item.is_dir():
|
|
196
|
+
if dest.exists():
|
|
197
|
+
shutil.rmtree(dest)
|
|
198
|
+
shutil.copytree(item, dest)
|
|
199
|
+
else:
|
|
200
|
+
if dest.exists():
|
|
201
|
+
dest.unlink()
|
|
202
|
+
shutil.copy2(item, dest)
|
|
203
|
+
|
|
204
|
+
# Clean up temp directory
|
|
205
|
+
if temp_extract.exists():
|
|
206
|
+
import shutil
|
|
207
|
+
|
|
208
|
+
shutil.rmtree(temp_extract, ignore_errors=True)
|
|
209
|
+
|
|
210
|
+
# Update toolchain_path to point to the actual installation location
|
|
211
|
+
self.toolchain_path = toolchain_cache_dir
|
|
212
|
+
|
|
213
|
+
if self.show_progress:
|
|
214
|
+
print("ARM GCC toolchain installed successfully")
|
|
215
|
+
|
|
216
|
+
return self.toolchain_path
|
|
217
|
+
|
|
218
|
+
except (DownloadError, ExtractionError) as e:
|
|
219
|
+
raise ToolchainErrorRP2040(f"Failed to install ARM GCC toolchain: {e}")
|
|
220
|
+
except KeyboardInterrupt as ke:
|
|
221
|
+
from fbuild.interrupt_utils import handle_keyboard_interrupt_properly
|
|
222
|
+
|
|
223
|
+
handle_keyboard_interrupt_properly(ke)
|
|
224
|
+
raise # Never reached, but satisfies type checker
|
|
225
|
+
except Exception as e:
|
|
226
|
+
raise ToolchainErrorRP2040(f"Unexpected error installing toolchain: {e}")
|
|
227
|
+
|
|
228
|
+
def is_installed(self) -> bool:
|
|
229
|
+
"""Check if toolchain is already installed.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
True if toolchain directory exists with key binaries
|
|
233
|
+
"""
|
|
234
|
+
if not self.toolchain_path.exists():
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
# Verify essential toolchain binaries exist
|
|
238
|
+
gcc_path = self._find_binary("gcc")
|
|
239
|
+
return gcc_path is not None and gcc_path.exists()
|
|
240
|
+
|
|
241
|
+
def get_bin_dir(self) -> Optional[Path]:
|
|
242
|
+
"""Get path to toolchain bin directory.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Path to bin directory containing compiler binaries, or None if not found
|
|
246
|
+
"""
|
|
247
|
+
# Check common bin directory locations
|
|
248
|
+
possible_paths = [
|
|
249
|
+
self.toolchain_path / "bin" / "bin", # Nested bin
|
|
250
|
+
self.toolchain_path / "bin", # Direct bin
|
|
251
|
+
]
|
|
252
|
+
|
|
253
|
+
for path in possible_paths:
|
|
254
|
+
if path.exists() and path.is_dir():
|
|
255
|
+
# Verify it contains toolchain binaries
|
|
256
|
+
if list(path.glob(f"{self.BINARY_PREFIX}gcc*")):
|
|
257
|
+
return path
|
|
258
|
+
|
|
259
|
+
return None
|
|
260
|
+
|
|
261
|
+
def _find_binary(self, binary_name: str) -> Optional[Path]:
|
|
262
|
+
"""Find a binary in the toolchain bin directory.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
binary_name: Name of the binary (e.g., "gcc", "g++")
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Path to binary or None if not found
|
|
269
|
+
"""
|
|
270
|
+
bin_dir = self.get_bin_dir()
|
|
271
|
+
if not bin_dir:
|
|
272
|
+
return None
|
|
273
|
+
|
|
274
|
+
# Try with and without .exe extension
|
|
275
|
+
binary_path = bin_dir / f"{self.BINARY_PREFIX}{binary_name}"
|
|
276
|
+
if binary_path.exists():
|
|
277
|
+
return binary_path
|
|
278
|
+
|
|
279
|
+
binary_path_exe = bin_dir / f"{self.BINARY_PREFIX}{binary_name}.exe"
|
|
280
|
+
if binary_path_exe.exists():
|
|
281
|
+
return binary_path_exe
|
|
282
|
+
|
|
283
|
+
return None
|
|
284
|
+
|
|
285
|
+
def get_gcc_path(self) -> Optional[Path]:
|
|
286
|
+
"""Get path to GCC compiler.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
Path to gcc binary or None if not found
|
|
290
|
+
"""
|
|
291
|
+
return self._find_binary("gcc")
|
|
292
|
+
|
|
293
|
+
def get_gxx_path(self) -> Optional[Path]:
|
|
294
|
+
"""Get path to G++ compiler.
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
Path to g++ binary or None if not found
|
|
298
|
+
"""
|
|
299
|
+
return self._find_binary("g++")
|
|
300
|
+
|
|
301
|
+
def get_ar_path(self) -> Optional[Path]:
|
|
302
|
+
"""Get path to archiver (ar).
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
Path to ar binary or None if not found
|
|
306
|
+
"""
|
|
307
|
+
return self._find_binary("ar")
|
|
308
|
+
|
|
309
|
+
def get_objcopy_path(self) -> Optional[Path]:
|
|
310
|
+
"""Get path to objcopy utility.
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
Path to objcopy binary or None if not found
|
|
314
|
+
"""
|
|
315
|
+
return self._find_binary("objcopy")
|
|
316
|
+
|
|
317
|
+
def get_size_path(self) -> Optional[Path]:
|
|
318
|
+
"""Get path to size utility.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
Path to size binary or None if not found
|
|
322
|
+
"""
|
|
323
|
+
return self._find_binary("size")
|
|
324
|
+
|
|
325
|
+
def get_objdump_path(self) -> Optional[Path]:
|
|
326
|
+
"""Get path to objdump utility.
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
Path to objdump binary or None if not found
|
|
330
|
+
"""
|
|
331
|
+
return self._find_binary("objdump")
|
|
332
|
+
|
|
333
|
+
def get_elf2uf2_path(self) -> Optional[Path]:
|
|
334
|
+
"""Get path to elf2uf2 utility (if available).
|
|
335
|
+
|
|
336
|
+
Note: elf2uf2 is typically provided by the Pico SDK, not the toolchain.
|
|
337
|
+
This method is here for API compatibility but will likely return None.
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
Path to elf2uf2 binary or None if not found
|
|
341
|
+
"""
|
|
342
|
+
# Check if elf2uf2 exists in the toolchain bin directory
|
|
343
|
+
bin_dir = self.get_bin_dir()
|
|
344
|
+
if not bin_dir:
|
|
345
|
+
return None
|
|
346
|
+
|
|
347
|
+
# Try with and without .exe extension
|
|
348
|
+
elf2uf2_path = bin_dir / "elf2uf2"
|
|
349
|
+
if elf2uf2_path.exists():
|
|
350
|
+
return elf2uf2_path
|
|
351
|
+
|
|
352
|
+
elf2uf2_path_exe = bin_dir / "elf2uf2.exe"
|
|
353
|
+
if elf2uf2_path_exe.exists():
|
|
354
|
+
return elf2uf2_path_exe
|
|
355
|
+
|
|
356
|
+
return None
|
|
357
|
+
|
|
358
|
+
def get_all_tool_paths(self) -> Dict[str, Optional[Path]]:
|
|
359
|
+
"""Get paths to all common toolchain binaries.
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
Dictionary mapping tool names to their paths
|
|
363
|
+
"""
|
|
364
|
+
return {
|
|
365
|
+
"gcc": self.get_gcc_path(),
|
|
366
|
+
"g++": self.get_gxx_path(),
|
|
367
|
+
"ar": self.get_ar_path(),
|
|
368
|
+
"objcopy": self.get_objcopy_path(),
|
|
369
|
+
"size": self.get_size_path(),
|
|
370
|
+
"objdump": self.get_objdump_path(),
|
|
371
|
+
"elf2uf2": self.get_elf2uf2_path(),
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
def get_all_tools(self) -> Dict[str, Path]:
|
|
375
|
+
"""Get paths to all required tools (IToolchain interface).
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
Dictionary mapping tool names to their paths (non-None only)
|
|
379
|
+
|
|
380
|
+
Raises:
|
|
381
|
+
ToolchainErrorRP2040: If any required tool is not found
|
|
382
|
+
"""
|
|
383
|
+
all_tools = self.get_all_tool_paths()
|
|
384
|
+
|
|
385
|
+
# Filter out None values and verify all required tools exist
|
|
386
|
+
# Note: elf2uf2 is optional, as it may be provided by the framework
|
|
387
|
+
required_tools = ["gcc", "g++", "ar", "objcopy", "size"]
|
|
388
|
+
result = {}
|
|
389
|
+
for name, path in all_tools.items():
|
|
390
|
+
if name in required_tools and path is None:
|
|
391
|
+
raise ToolchainErrorRP2040(f"Required tool '{name}' not found in toolchain")
|
|
392
|
+
if path is not None:
|
|
393
|
+
result[name] = path
|
|
394
|
+
|
|
395
|
+
return result
|
|
396
|
+
|
|
397
|
+
def get_toolchain_info(self) -> Dict[str, Any]:
|
|
398
|
+
"""Get information about the installed toolchain.
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
Dictionary with toolchain information
|
|
402
|
+
"""
|
|
403
|
+
info = {
|
|
404
|
+
"type": "arm-none-eabi",
|
|
405
|
+
"version": self.version,
|
|
406
|
+
"path": str(self.toolchain_path),
|
|
407
|
+
"url": self.toolchain_url,
|
|
408
|
+
"installed": self.is_installed(),
|
|
409
|
+
"binary_prefix": self.BINARY_PREFIX,
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if self.is_installed():
|
|
413
|
+
info["bin_dir"] = str(self.get_bin_dir())
|
|
414
|
+
info["tools"] = {name: str(path) if path else None for name, path in self.get_all_tool_paths().items()}
|
|
415
|
+
|
|
416
|
+
return info
|
|
417
|
+
|
|
418
|
+
# Implement IPackage interface
|
|
419
|
+
def ensure_package(self) -> Path:
|
|
420
|
+
"""Ensure package is downloaded and extracted.
|
|
421
|
+
|
|
422
|
+
Returns:
|
|
423
|
+
Path to the extracted package directory
|
|
424
|
+
|
|
425
|
+
Raises:
|
|
426
|
+
PackageError: If download or extraction fails
|
|
427
|
+
"""
|
|
428
|
+
return self.ensure_toolchain()
|
|
429
|
+
|
|
430
|
+
def get_package_info(self) -> Dict[str, Any]:
|
|
431
|
+
"""Get information about the package.
|
|
432
|
+
|
|
433
|
+
Returns:
|
|
434
|
+
Dictionary with package metadata (version, path, etc.)
|
|
435
|
+
"""
|
|
436
|
+
return self.get_toolchain_info()
|