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.
- fbuild/__init__.py +0 -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_state.py +325 -0
- fbuild/build/build_utils.py +98 -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 +612 -0
- fbuild/build/configurable_linker.py +637 -0
- fbuild/build/flag_builder.py +186 -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 +656 -0
- fbuild/build/orchestrator_esp32.py +797 -0
- fbuild/build/orchestrator_teensy.py +543 -0
- fbuild/build/source_compilation_orchestrator.py +220 -0
- fbuild/build/source_scanner.py +516 -0
- fbuild/cli.py +566 -0
- fbuild/cli_utils.py +312 -0
- fbuild/config/__init__.py +16 -0
- fbuild/config/board_config.py +457 -0
- fbuild/config/board_loader.py +92 -0
- fbuild/config/ini_parser.py +209 -0
- fbuild/config/mcu_specs.py +88 -0
- fbuild/daemon/__init__.py +34 -0
- fbuild/daemon/client.py +929 -0
- fbuild/daemon/compilation_queue.py +293 -0
- fbuild/daemon/daemon.py +474 -0
- fbuild/daemon/daemon_context.py +196 -0
- fbuild/daemon/error_collector.py +263 -0
- fbuild/daemon/file_cache.py +332 -0
- fbuild/daemon/lock_manager.py +270 -0
- fbuild/daemon/logging_utils.py +149 -0
- fbuild/daemon/messages.py +301 -0
- fbuild/daemon/operation_registry.py +288 -0
- fbuild/daemon/process_tracker.py +366 -0
- fbuild/daemon/processors/__init__.py +12 -0
- fbuild/daemon/processors/build_processor.py +157 -0
- fbuild/daemon/processors/deploy_processor.py +327 -0
- fbuild/daemon/processors/monitor_processor.py +146 -0
- fbuild/daemon/request_processor.py +401 -0
- fbuild/daemon/status_manager.py +216 -0
- fbuild/daemon/subprocess_manager.py +316 -0
- fbuild/deploy/__init__.py +17 -0
- fbuild/deploy/deployer.py +67 -0
- fbuild/deploy/deployer_esp32.py +314 -0
- fbuild/deploy/monitor.py +495 -0
- fbuild/interrupt_utils.py +34 -0
- fbuild/packages/__init__.py +53 -0
- fbuild/packages/archive_utils.py +1098 -0
- fbuild/packages/arduino_core.py +412 -0
- fbuild/packages/cache.py +249 -0
- fbuild/packages/downloader.py +366 -0
- fbuild/packages/framework_esp32.py +538 -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 +413 -0
- fbuild/packages/package.py +163 -0
- fbuild/packages/platform_esp32.py +383 -0
- fbuild/packages/platform_teensy.py +312 -0
- fbuild/packages/platform_utils.py +131 -0
- fbuild/packages/platformio_registry.py +325 -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 +484 -0
- fbuild/packages/toolchain_metadata.py +185 -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-1.1.0.dist-info/METADATA +447 -0
- fbuild-1.1.0.dist-info/RECORD +93 -0
- fbuild-1.1.0.dist-info/WHEEL +5 -0
- fbuild-1.1.0.dist-info/entry_points.txt +5 -0
- fbuild-1.1.0.dist-info/licenses/LICENSE +21 -0
- fbuild-1.1.0.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,538 @@
|
|
|
1
|
+
"""ESP32 Framework Management.
|
|
2
|
+
|
|
3
|
+
This module handles downloading, extracting, and managing the Arduino-ESP32 framework
|
|
4
|
+
and ESP-IDF libraries needed for ESP32 builds.
|
|
5
|
+
|
|
6
|
+
Framework Download Process:
|
|
7
|
+
1. Download Arduino-ESP32 core (framework-arduinoespressif32)
|
|
8
|
+
2. Download ESP-IDF precompiled libraries (framework-arduinoespressif32-libs)
|
|
9
|
+
3. Extract both archives (.tar.xz format)
|
|
10
|
+
4. Provide access to cores/, variants/, libraries/, and tools/
|
|
11
|
+
|
|
12
|
+
Framework Structure (after extraction):
|
|
13
|
+
framework-arduinoespressif32/
|
|
14
|
+
├── cores/
|
|
15
|
+
│ └── esp32/ # Arduino core implementation
|
|
16
|
+
│ ├── Arduino.h
|
|
17
|
+
│ ├── main.cpp
|
|
18
|
+
│ ├── wiring.c
|
|
19
|
+
│ └── ...
|
|
20
|
+
├── variants/
|
|
21
|
+
│ └── esp32c6/ # Board-specific variant
|
|
22
|
+
│ ├── pins_arduino.h
|
|
23
|
+
│ └── ...
|
|
24
|
+
├── libraries/ # Built-in libraries (Wire, SPI, WiFi, etc.)
|
|
25
|
+
│ ├── WiFi/
|
|
26
|
+
│ ├── Wire/
|
|
27
|
+
│ ├── SPI/
|
|
28
|
+
│ └── ...
|
|
29
|
+
├── tools/ # Build tools and SDKs
|
|
30
|
+
│ └── sdk/
|
|
31
|
+
│ └── esp32c6/
|
|
32
|
+
│ ├── include/ # ESP-IDF headers
|
|
33
|
+
│ └── lib/ # Precompiled libraries
|
|
34
|
+
└── package.json # Framework metadata
|
|
35
|
+
|
|
36
|
+
ESP-IDF Libraries Structure:
|
|
37
|
+
framework-arduinoespressif32-libs/
|
|
38
|
+
└── esp32c6/
|
|
39
|
+
├── include/ # ESP-IDF headers
|
|
40
|
+
│ ├── esp_system/
|
|
41
|
+
│ ├── freertos/
|
|
42
|
+
│ └── ...
|
|
43
|
+
└── lib/ # Precompiled .a libraries
|
|
44
|
+
├── libesp_system.a
|
|
45
|
+
├── libfreertos.a
|
|
46
|
+
└── ...
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
import _thread
|
|
50
|
+
import json
|
|
51
|
+
from pathlib import Path
|
|
52
|
+
from typing import Any, Dict, List, Optional
|
|
53
|
+
|
|
54
|
+
from .archive_utils import ArchiveExtractor, URLVersionExtractor
|
|
55
|
+
from .cache import Cache
|
|
56
|
+
from .downloader import DownloadError, ExtractionError
|
|
57
|
+
from .header_trampoline_cache import HeaderTrampolineCache
|
|
58
|
+
from .package import IFramework, PackageError
|
|
59
|
+
from .sdk_utils import SDKPathResolver
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class FrameworkErrorESP32(PackageError):
|
|
63
|
+
"""Raised when ESP32 framework operations fail."""
|
|
64
|
+
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class FrameworkESP32(IFramework):
|
|
69
|
+
"""Manages ESP32 framework download, extraction, and access.
|
|
70
|
+
|
|
71
|
+
This class handles the Arduino-ESP32 framework which includes:
|
|
72
|
+
- Arduino core for ESP32 family (cores/, variants/)
|
|
73
|
+
- Built-in Arduino libraries (WiFi, Wire, SPI, etc.)
|
|
74
|
+
- ESP-IDF precompiled libraries
|
|
75
|
+
- Tools and SDKs for ESP32 development
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
def __init__(
|
|
79
|
+
self,
|
|
80
|
+
cache: Cache,
|
|
81
|
+
framework_url: str,
|
|
82
|
+
libs_url: str,
|
|
83
|
+
skeleton_lib_url: Optional[str] = None,
|
|
84
|
+
show_progress: bool = True,
|
|
85
|
+
):
|
|
86
|
+
"""Initialize ESP32 framework manager.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
cache: Cache manager instance
|
|
90
|
+
framework_url: URL to Arduino-ESP32 core package (.tar.xz)
|
|
91
|
+
libs_url: URL to ESP-IDF precompiled libraries (.tar.xz)
|
|
92
|
+
skeleton_lib_url: Optional URL to MCU-specific skeleton library
|
|
93
|
+
show_progress: Whether to show download/extraction progress
|
|
94
|
+
"""
|
|
95
|
+
self.cache = cache
|
|
96
|
+
self.framework_url = framework_url
|
|
97
|
+
self.libs_url = libs_url
|
|
98
|
+
self.skeleton_lib_url = skeleton_lib_url
|
|
99
|
+
self.show_progress = show_progress
|
|
100
|
+
self.archive_extractor = ArchiveExtractor(show_progress=show_progress)
|
|
101
|
+
|
|
102
|
+
# Extract version from URL (e.g., "3.3.4" from release tag)
|
|
103
|
+
self.version = URLVersionExtractor.extract_version_from_url(framework_url, prefix="esp32-")
|
|
104
|
+
|
|
105
|
+
# Get framework paths from cache
|
|
106
|
+
# We'll use a combined hash for all URLs to keep them together
|
|
107
|
+
combined_url = f"{framework_url}|{libs_url}|{skeleton_lib_url or ''}"
|
|
108
|
+
self.framework_path = cache.get_platform_path(combined_url, self.version)
|
|
109
|
+
|
|
110
|
+
def ensure_package(self) -> Path:
|
|
111
|
+
"""Ensure framework is downloaded and extracted.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Path to the extracted framework directory
|
|
115
|
+
|
|
116
|
+
Raises:
|
|
117
|
+
FrameworkErrorESP32: If download or extraction fails
|
|
118
|
+
"""
|
|
119
|
+
return self.ensure_framework()
|
|
120
|
+
|
|
121
|
+
def ensure_framework(self) -> Path:
|
|
122
|
+
"""Ensure framework is downloaded and extracted.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Path to the extracted framework directory
|
|
126
|
+
|
|
127
|
+
Raises:
|
|
128
|
+
FrameworkErrorESP32: If download or extraction fails
|
|
129
|
+
"""
|
|
130
|
+
if self.is_installed():
|
|
131
|
+
if self.show_progress:
|
|
132
|
+
print(f"Using cached ESP32 framework {self.version}")
|
|
133
|
+
return self.framework_path
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
if self.show_progress:
|
|
137
|
+
print(f"Downloading ESP32 framework {self.version}...")
|
|
138
|
+
|
|
139
|
+
# Download and extract framework package
|
|
140
|
+
self.cache.ensure_directories()
|
|
141
|
+
|
|
142
|
+
# Create framework directory
|
|
143
|
+
self.framework_path.mkdir(parents=True, exist_ok=True)
|
|
144
|
+
|
|
145
|
+
# Download and extract Arduino core
|
|
146
|
+
self.archive_extractor.download_and_extract(self.framework_url, self.framework_path, "Arduino-ESP32 core")
|
|
147
|
+
|
|
148
|
+
# Download and extract ESP-IDF libraries (if URL is not empty)
|
|
149
|
+
if self.libs_url:
|
|
150
|
+
self.archive_extractor.download_and_extract(
|
|
151
|
+
self.libs_url,
|
|
152
|
+
self.framework_path / "tools" / "sdk",
|
|
153
|
+
"ESP-IDF libraries",
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Download and extract skeleton library if provided
|
|
157
|
+
if self.skeleton_lib_url:
|
|
158
|
+
if self.show_progress:
|
|
159
|
+
print("Downloading skeleton library...")
|
|
160
|
+
self.archive_extractor.download_and_extract(
|
|
161
|
+
self.skeleton_lib_url,
|
|
162
|
+
self.framework_path / "tools" / "sdk",
|
|
163
|
+
"Skeleton library",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
if self.show_progress:
|
|
167
|
+
print(f"ESP32 framework installed to {self.framework_path}")
|
|
168
|
+
|
|
169
|
+
# Post-install: Generate header trampolines for all MCU variants
|
|
170
|
+
# This pre-generates trampoline caches to avoid Windows command-line length issues
|
|
171
|
+
self._post_install_generate_trampolines()
|
|
172
|
+
|
|
173
|
+
return self.framework_path
|
|
174
|
+
|
|
175
|
+
except (DownloadError, ExtractionError) as e:
|
|
176
|
+
raise FrameworkErrorESP32(f"Failed to install ESP32 framework: {e}")
|
|
177
|
+
except KeyboardInterrupt as ke:
|
|
178
|
+
from fbuild.interrupt_utils import handle_keyboard_interrupt_properly
|
|
179
|
+
|
|
180
|
+
handle_keyboard_interrupt_properly(ke)
|
|
181
|
+
raise # Never reached, but satisfies type checker
|
|
182
|
+
except Exception as e:
|
|
183
|
+
raise FrameworkErrorESP32(f"Unexpected error installing framework: {e}")
|
|
184
|
+
|
|
185
|
+
def _post_install_generate_trampolines(self) -> None:
|
|
186
|
+
"""Generate header trampolines for all MCU variants after framework installation.
|
|
187
|
+
|
|
188
|
+
This post-install step pre-generates trampoline caches for all ESP32 MCU variants
|
|
189
|
+
found in the SDK. This ensures that Windows builds with sccache don't hit the
|
|
190
|
+
32K command-line length limit due to excessive -I arguments.
|
|
191
|
+
|
|
192
|
+
The trampolines are generated once at framework install time rather than at
|
|
193
|
+
every compile time, improving build performance.
|
|
194
|
+
"""
|
|
195
|
+
import platform as platform_module
|
|
196
|
+
|
|
197
|
+
# Only generate trampolines on Windows
|
|
198
|
+
if platform_module.system() != "Windows":
|
|
199
|
+
if self.show_progress:
|
|
200
|
+
print("[trampolines] Skipping post-install generation (not Windows)")
|
|
201
|
+
return
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
if self.show_progress:
|
|
205
|
+
print("[trampolines] Post-install: Generating header trampoline caches...")
|
|
206
|
+
|
|
207
|
+
# Find all MCU variants in the SDK
|
|
208
|
+
sdk_dir = self.get_sdk_dir()
|
|
209
|
+
if not sdk_dir.exists():
|
|
210
|
+
if self.show_progress:
|
|
211
|
+
print("[trampolines] Warning: SDK directory not found, skipping")
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
# Look for MCU-specific directories
|
|
215
|
+
mcu_variants = []
|
|
216
|
+
for item in sdk_dir.iterdir():
|
|
217
|
+
if item.is_dir() and item.name.startswith("esp32"):
|
|
218
|
+
mcu_variants.append(item.name)
|
|
219
|
+
|
|
220
|
+
if not mcu_variants:
|
|
221
|
+
if self.show_progress:
|
|
222
|
+
print("[trampolines] Warning: No MCU variants found in SDK")
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
if self.show_progress:
|
|
226
|
+
print(f"[trampolines] Found {len(mcu_variants)} MCU variant(s): {', '.join(mcu_variants)}")
|
|
227
|
+
|
|
228
|
+
# Generate trampolines for each MCU variant
|
|
229
|
+
trampoline_cache = HeaderTrampolineCache(show_progress=self.show_progress)
|
|
230
|
+
|
|
231
|
+
# Exclude ESP-IDF headers that use relative paths or #include_next that break trampolines
|
|
232
|
+
exclude_patterns = [
|
|
233
|
+
"newlib/platform_include", # Uses #include_next which breaks trampolines
|
|
234
|
+
"newlib\\platform_include", # Windows path variant
|
|
235
|
+
"/bt/", # Bluetooth SDK uses relative paths between bt/include and bt/controller
|
|
236
|
+
"\\bt\\", # Windows path variant
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
for mcu in mcu_variants:
|
|
240
|
+
try:
|
|
241
|
+
# Get SDK include paths for this MCU
|
|
242
|
+
include_paths = self.get_sdk_includes(mcu)
|
|
243
|
+
|
|
244
|
+
if self.show_progress:
|
|
245
|
+
print(f"[trampolines] Generating cache for {mcu} ({len(include_paths)} include paths)...")
|
|
246
|
+
|
|
247
|
+
# Generate trampolines with exclusions (this will create C:/inc/NNN directories)
|
|
248
|
+
trampoline_paths = trampoline_cache.generate_trampolines(include_paths, exclude_patterns=exclude_patterns)
|
|
249
|
+
|
|
250
|
+
if self.show_progress:
|
|
251
|
+
print(f"[trampolines] Generated {len(trampoline_paths)} trampoline directories for {mcu}")
|
|
252
|
+
|
|
253
|
+
except KeyboardInterrupt:
|
|
254
|
+
_thread.interrupt_main()
|
|
255
|
+
raise
|
|
256
|
+
except Exception as e:
|
|
257
|
+
if self.show_progress:
|
|
258
|
+
print(f"[trampolines] Warning: Failed to generate trampolines for {mcu}: {e}")
|
|
259
|
+
continue
|
|
260
|
+
|
|
261
|
+
if self.show_progress:
|
|
262
|
+
print("[trampolines] Post-install generation complete")
|
|
263
|
+
|
|
264
|
+
except KeyboardInterrupt:
|
|
265
|
+
_thread.interrupt_main()
|
|
266
|
+
raise
|
|
267
|
+
except Exception as e:
|
|
268
|
+
# Don't fail the entire installation if trampoline generation fails
|
|
269
|
+
if self.show_progress:
|
|
270
|
+
print(f"[trampolines] Warning: Post-install generation failed: {e}")
|
|
271
|
+
|
|
272
|
+
def is_installed(self) -> bool:
|
|
273
|
+
"""Check if framework is already installed.
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
True if framework directory exists with key files
|
|
277
|
+
"""
|
|
278
|
+
if not self.framework_path.exists():
|
|
279
|
+
return False
|
|
280
|
+
|
|
281
|
+
# Verify essential framework directories exist
|
|
282
|
+
required_paths = [
|
|
283
|
+
self.framework_path / "cores",
|
|
284
|
+
self.framework_path / "variants",
|
|
285
|
+
self.framework_path / "tools" / "sdk",
|
|
286
|
+
]
|
|
287
|
+
|
|
288
|
+
return all(p.exists() for p in required_paths)
|
|
289
|
+
|
|
290
|
+
def get_cores_dir(self) -> Path:
|
|
291
|
+
"""Get path to cores directory.
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
Path to cores directory containing Arduino core implementation
|
|
295
|
+
"""
|
|
296
|
+
return self.framework_path / "cores"
|
|
297
|
+
|
|
298
|
+
def get_core_dir(self, core_name: str = "esp32") -> Path:
|
|
299
|
+
"""Get path to specific core directory.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
core_name: Core name (default: "esp32")
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
Path to the core directory
|
|
306
|
+
|
|
307
|
+
Raises:
|
|
308
|
+
FrameworkErrorESP32: If core directory doesn't exist
|
|
309
|
+
"""
|
|
310
|
+
core_path = self.get_cores_dir() / core_name
|
|
311
|
+
if not core_path.exists():
|
|
312
|
+
raise FrameworkErrorESP32(f"Core '{core_name}' not found at {core_path}")
|
|
313
|
+
return core_path
|
|
314
|
+
|
|
315
|
+
def get_variants_dir(self) -> Path:
|
|
316
|
+
"""Get path to variants directory.
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
Path to variants directory containing board-specific configurations
|
|
320
|
+
"""
|
|
321
|
+
return self.framework_path / "variants"
|
|
322
|
+
|
|
323
|
+
def get_variant_dir(self, variant_name: str) -> Path:
|
|
324
|
+
"""Get path to specific variant directory.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
variant_name: Variant name (e.g., "esp32c6")
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
Path to the variant directory
|
|
331
|
+
|
|
332
|
+
Raises:
|
|
333
|
+
FrameworkErrorESP32: If variant directory doesn't exist
|
|
334
|
+
"""
|
|
335
|
+
variant_path = self.get_variants_dir() / variant_name
|
|
336
|
+
if not variant_path.exists():
|
|
337
|
+
raise FrameworkErrorESP32(f"Variant '{variant_name}' not found at {variant_path}")
|
|
338
|
+
return variant_path
|
|
339
|
+
|
|
340
|
+
def get_libraries_dir(self) -> Path:
|
|
341
|
+
"""Get path to built-in libraries directory.
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
Path to libraries directory
|
|
345
|
+
"""
|
|
346
|
+
return self.framework_path / "libraries"
|
|
347
|
+
|
|
348
|
+
def list_libraries(self) -> List[str]:
|
|
349
|
+
"""List all available built-in libraries.
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
List of library names
|
|
353
|
+
"""
|
|
354
|
+
libs_dir = self.get_libraries_dir()
|
|
355
|
+
if not libs_dir.exists():
|
|
356
|
+
return []
|
|
357
|
+
|
|
358
|
+
return [d.name for d in libs_dir.iterdir() if d.is_dir() and not d.name.startswith(".")]
|
|
359
|
+
|
|
360
|
+
def get_library_dir(self, library_name: str) -> Optional[Path]:
|
|
361
|
+
"""Get path to a specific library.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
library_name: Library name (e.g., "WiFi", "Wire")
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
Path to library directory or None if not found
|
|
368
|
+
"""
|
|
369
|
+
lib_path = self.get_libraries_dir() / library_name
|
|
370
|
+
return lib_path if lib_path.exists() else None
|
|
371
|
+
|
|
372
|
+
def get_sdk_dir(self) -> Path:
|
|
373
|
+
"""Get path to ESP-IDF SDK directory.
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
Path to SDK directory containing ESP-IDF headers and libraries
|
|
377
|
+
"""
|
|
378
|
+
return self.framework_path / "tools" / "sdk"
|
|
379
|
+
|
|
380
|
+
def get_sdk_includes(self, mcu: str) -> List[Path]:
|
|
381
|
+
"""Get list of ESP-IDF include directories for a specific MCU.
|
|
382
|
+
|
|
383
|
+
This method reads the SDK's own includes file which lists the exact
|
|
384
|
+
include paths used by ESP-IDF, avoiding C++ stdlib conflicts that
|
|
385
|
+
occur when recursively discovering paths.
|
|
386
|
+
|
|
387
|
+
Args:
|
|
388
|
+
mcu: MCU type (e.g., "esp32c6", "esp32s3")
|
|
389
|
+
|
|
390
|
+
Returns:
|
|
391
|
+
List of include directory paths (305 paths for esp32c6)
|
|
392
|
+
"""
|
|
393
|
+
sdk_resolver = SDKPathResolver(self.get_sdk_dir(), self.show_progress)
|
|
394
|
+
return sdk_resolver.get_sdk_includes(mcu)
|
|
395
|
+
|
|
396
|
+
def get_sdk_libs(self, mcu: str, flash_mode: str = "qio") -> List[Path]:
|
|
397
|
+
"""Get list of ESP-IDF precompiled libraries for a specific MCU.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
mcu: MCU type (e.g., "esp32c6", "esp32s3")
|
|
401
|
+
flash_mode: Flash mode (e.g., "qio", "dio") - determines flash library variant
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
List of .a library file paths
|
|
405
|
+
"""
|
|
406
|
+
sdk_resolver = SDKPathResolver(self.get_sdk_dir(), self.show_progress)
|
|
407
|
+
return sdk_resolver.get_sdk_libs(mcu, flash_mode)
|
|
408
|
+
|
|
409
|
+
def get_sdk_flags_dir(self, mcu: str) -> Path:
|
|
410
|
+
"""Get path to SDK flags directory for a specific MCU.
|
|
411
|
+
|
|
412
|
+
Args:
|
|
413
|
+
mcu: MCU type (e.g., "esp32c6", "esp32s3")
|
|
414
|
+
|
|
415
|
+
Returns:
|
|
416
|
+
Path to flags directory
|
|
417
|
+
"""
|
|
418
|
+
sdk_resolver = SDKPathResolver(self.get_sdk_dir(), self.show_progress)
|
|
419
|
+
return sdk_resolver.get_sdk_flags_dir(mcu)
|
|
420
|
+
|
|
421
|
+
def get_tools_dir(self) -> Path:
|
|
422
|
+
"""Get path to tools directory.
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
Path to tools directory
|
|
426
|
+
"""
|
|
427
|
+
return self.framework_path / "tools"
|
|
428
|
+
|
|
429
|
+
def get_package_json(self) -> Dict[str, Any]:
|
|
430
|
+
"""Load and parse package.json metadata.
|
|
431
|
+
|
|
432
|
+
Returns:
|
|
433
|
+
Dictionary containing package metadata
|
|
434
|
+
|
|
435
|
+
Raises:
|
|
436
|
+
FrameworkErrorESP32: If package.json doesn't exist or is invalid
|
|
437
|
+
"""
|
|
438
|
+
package_json_path = self.framework_path / "package.json"
|
|
439
|
+
|
|
440
|
+
if not package_json_path.exists():
|
|
441
|
+
raise FrameworkErrorESP32(f"package.json not found at {package_json_path}. " + "Ensure framework is downloaded first.")
|
|
442
|
+
|
|
443
|
+
try:
|
|
444
|
+
with open(package_json_path, "r", encoding="utf-8") as f:
|
|
445
|
+
return json.load(f)
|
|
446
|
+
except json.JSONDecodeError as e:
|
|
447
|
+
raise FrameworkErrorESP32(f"Failed to parse package.json: {e}")
|
|
448
|
+
except KeyboardInterrupt as ke:
|
|
449
|
+
from fbuild.interrupt_utils import handle_keyboard_interrupt_properly
|
|
450
|
+
|
|
451
|
+
handle_keyboard_interrupt_properly(ke)
|
|
452
|
+
raise # Never reached, but satisfies type checker
|
|
453
|
+
except Exception as e:
|
|
454
|
+
raise FrameworkErrorESP32(f"Failed to read package.json: {e}")
|
|
455
|
+
|
|
456
|
+
def list_variants(self) -> List[str]:
|
|
457
|
+
"""List all available board variants.
|
|
458
|
+
|
|
459
|
+
Returns:
|
|
460
|
+
List of variant names
|
|
461
|
+
"""
|
|
462
|
+
variants_dir = self.get_variants_dir()
|
|
463
|
+
if not variants_dir.exists():
|
|
464
|
+
return []
|
|
465
|
+
|
|
466
|
+
return [d.name for d in variants_dir.iterdir() if d.is_dir() and not d.name.startswith(".")]
|
|
467
|
+
|
|
468
|
+
def list_cores(self) -> List[str]:
|
|
469
|
+
"""List all available cores.
|
|
470
|
+
|
|
471
|
+
Returns:
|
|
472
|
+
List of core names
|
|
473
|
+
"""
|
|
474
|
+
cores_dir = self.get_cores_dir()
|
|
475
|
+
if not cores_dir.exists():
|
|
476
|
+
return []
|
|
477
|
+
|
|
478
|
+
return [d.name for d in cores_dir.iterdir() if d.is_dir() and not d.name.startswith(".")]
|
|
479
|
+
|
|
480
|
+
def get_core_sources(self, core_name: str = "esp32") -> List[Path]:
|
|
481
|
+
"""Get all source files in a core.
|
|
482
|
+
|
|
483
|
+
Args:
|
|
484
|
+
core_name: Core name (default: "esp32")
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
List of .c and .cpp source file paths
|
|
488
|
+
"""
|
|
489
|
+
core_dir = self.get_core_dir(core_name)
|
|
490
|
+
sources = []
|
|
491
|
+
sources.extend(core_dir.glob("*.c"))
|
|
492
|
+
sources.extend(core_dir.glob("*.cpp"))
|
|
493
|
+
# Also search in subdirectories
|
|
494
|
+
sources.extend(core_dir.glob("**/*.c"))
|
|
495
|
+
sources.extend(core_dir.glob("**/*.cpp"))
|
|
496
|
+
# Remove duplicates
|
|
497
|
+
return list(set(sources))
|
|
498
|
+
|
|
499
|
+
def get_package_info(self) -> Dict[str, Any]:
|
|
500
|
+
"""Get information about the installed framework.
|
|
501
|
+
|
|
502
|
+
Returns:
|
|
503
|
+
Dictionary with framework information
|
|
504
|
+
"""
|
|
505
|
+
return self.get_framework_info()
|
|
506
|
+
|
|
507
|
+
def get_framework_info(self) -> Dict[str, Any]:
|
|
508
|
+
"""Get information about the installed framework.
|
|
509
|
+
|
|
510
|
+
Returns:
|
|
511
|
+
Dictionary with framework information
|
|
512
|
+
"""
|
|
513
|
+
info = {
|
|
514
|
+
"version": self.version,
|
|
515
|
+
"path": str(self.framework_path),
|
|
516
|
+
"framework_url": self.framework_url,
|
|
517
|
+
"libs_url": self.libs_url,
|
|
518
|
+
"installed": self.is_installed(),
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if self.is_installed():
|
|
522
|
+
info["cores_dir"] = str(self.get_cores_dir())
|
|
523
|
+
info["variants_dir"] = str(self.get_variants_dir())
|
|
524
|
+
info["libraries_dir"] = str(self.get_libraries_dir())
|
|
525
|
+
info["sdk_dir"] = str(self.get_sdk_dir())
|
|
526
|
+
info["available_cores"] = self.list_cores()
|
|
527
|
+
info["available_variants"] = self.list_variants()
|
|
528
|
+
info["available_libraries"] = self.list_libraries()
|
|
529
|
+
|
|
530
|
+
# Get package information
|
|
531
|
+
try:
|
|
532
|
+
package_json = self.get_package_json()
|
|
533
|
+
info["package_version"] = package_json.get("version")
|
|
534
|
+
info["package_name"] = package_json.get("name")
|
|
535
|
+
except FrameworkErrorESP32:
|
|
536
|
+
pass
|
|
537
|
+
|
|
538
|
+
return info
|