Skip to content

Commit bd947d8

Browse files
authored
make PATH_LENGTH_THRESHOLD configurable
1 parent 1249333 commit bd947d8

File tree

1 file changed

+246
-19
lines changed

1 file changed

+246
-19
lines changed

builder/frameworks/arduino.py

Lines changed: 246 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,6 @@
4343

4444
IS_WINDOWS = sys.platform.startswith("win")
4545

46-
# Include path length threshold for path shortening, only valid and needed for Windows
47-
# Windows has a path length limit of ~260 characters per path, but the total command line
48-
# length is also limited to ~32000 characters
49-
INCLUDE_PATH_LENGTH_THRESHOLD = 31500 # Total character count threshold
50-
5146
python_deps = {
5247
"wheel": ">=0.35.1",
5348
"rich-click": ">=1.8.6",
@@ -90,6 +85,219 @@ def setup_logging():
9085
'long_path_warning_shown': False
9186
}
9287

88+
def get_platform_default_threshold(mcu):
89+
"""
90+
Platform-specific bleeding edge default values for INCLUDE_PATH_LENGTH_THRESHOLD
91+
These values push the limits for maximum performance and minimal path shortening
92+
93+
Args:
94+
mcu: MCU type (esp32, esp32s2, esp32s3, etc.)
95+
96+
Returns:
97+
int: Platform-specific bleeding edge default threshold
98+
"""
99+
# Bleeding edge values - pushing Windows command line limits
100+
# Windows CMD has ~32768 character limit, we use aggressive values close to this
101+
platform_defaults = {
102+
"esp32": 45000, # Standard ESP32
103+
"esp32s2": 43000, # ESP32-S2
104+
"esp32s3": 48000, # ESP32-S3
105+
"esp32c3": 41000, # ESP32-C3
106+
"esp32c2": 38000, # ESP32-C2
107+
"esp32c6": 44000, # ESP32-C6
108+
"esp32h2": 40000, # ESP32-H2
109+
"esp32p4": 50000, # ESP32-P4
110+
}
111+
112+
default_value = platform_defaults.get(mcu, 45000) # Aggressive fallback
113+
114+
# Debug output only in verbose mode
115+
if logging.getLogger().isEnabledFor(logging.DEBUG):
116+
logging.debug(f"Bleeding edge platform default threshold for {mcu}: {default_value}")
117+
118+
return default_value
119+
120+
def validate_threshold(threshold, mcu):
121+
"""
122+
Validates threshold value with bleeding edge limits
123+
Uses aggressive boundaries for maximum performance
124+
125+
Args:
126+
threshold: Threshold value to validate
127+
mcu: MCU type for context-specific validation
128+
129+
Returns:
130+
int: Validated threshold value
131+
"""
132+
# Bleeding edge absolute limits - pushing boundaries
133+
min_threshold = 15000 # Minimum reasonable value for complex projects
134+
max_threshold = 65000 # Maximum aggressive value (beyond Windows CMD limit for testing)
135+
136+
# MCU-specific bleeding edge adjustments - all values are aggressive
137+
mcu_adjustments = {
138+
"esp32c2": {"min": 30000, "max": 40000},
139+
"esp32c3": {"min": 30000, "max": 45000},
140+
"esp32": {"min": 30000, "max": 50000},
141+
"esp32s2": {"min": 30000, "max": 50000},
142+
"esp32s3": {"min": 30000, "max": 50000},
143+
"esp32p4": {"min": 30000, "max": 55000},
144+
"esp32c6": {"min": 30000, "max": 50000},
145+
"esp32h2": {"min": 30000, "max": 40000},
146+
}
147+
148+
# Apply MCU-specific bleeding edge limits
149+
if mcu in mcu_adjustments:
150+
min_threshold = max(min_threshold, mcu_adjustments[mcu]["min"])
151+
max_threshold = min(max_threshold, mcu_adjustments[mcu]["max"])
152+
153+
original_threshold = threshold
154+
155+
if threshold < min_threshold:
156+
print(f"*** Warning: Include path threshold {threshold} too conservative for {mcu}, using bleeding edge minimum {min_threshold} ***")
157+
threshold = min_threshold
158+
elif threshold > max_threshold:
159+
print(f"*** Warning: Include path threshold {threshold} exceeds bleeding edge maximum for {mcu}, using {max_threshold} ***")
160+
threshold = max_threshold
161+
162+
# Warning for conservative values (opposite of original - warn if too low)
163+
platform_default = get_platform_default_threshold(mcu)
164+
if threshold < platform_default * 0.7: # More than 30% below bleeding edge default
165+
print(f"*** Info: Include path threshold {threshold} is conservative compared to bleeding edge default {platform_default} for {mcu} ***")
166+
print(f"*** Consider using higher values for maximum performance ***")
167+
168+
if original_threshold != threshold:
169+
logging.warning(f"Threshold adjusted from {original_threshold} to bleeding edge value {threshold} for {mcu}")
170+
171+
return threshold
172+
173+
def get_include_path_threshold(env, config, current_env_section):
174+
"""
175+
Determines Windows INCLUDE_PATH_LENGTH_THRESHOLD from various sources
176+
with priority order and bleeding edge validation
177+
178+
Priority order:
179+
1. Environment variable PLATFORMIO_INCLUDE_PATH_THRESHOLD
180+
2. Environment-specific setting in platformio.ini
181+
3. Global setting in [env] section
182+
4. Setting in [platformio] section
183+
5. MCU-specific bleeding edge default value
184+
185+
Args:
186+
env: PlatformIO Environment
187+
config: Project Configuration
188+
current_env_section: Current environment section
189+
190+
Returns:
191+
int: Validated bleeding edge threshold value
192+
"""
193+
mcu = env.BoardConfig().get("build.mcu", "esp32")
194+
default_threshold = get_platform_default_threshold(mcu)
195+
setting_name = "custom_include_path_length_threshold"
196+
197+
try:
198+
# 1. Check environment variable (highest priority)
199+
env_var = os.environ.get("PLATFORMIO_INCLUDE_PATH_THRESHOLD")
200+
if env_var:
201+
try:
202+
threshold = int(env_var)
203+
threshold = validate_threshold(threshold, mcu)
204+
print(f"*** Using environment variable bleeding edge include path threshold: {threshold} (MCU: {mcu}) ***")
205+
return threshold
206+
except ValueError:
207+
print(f"*** Warning: Invalid environment variable PLATFORMIO_INCLUDE_PATH_THRESHOLD='{env_var}', ignoring ***")
208+
209+
# 2. Check environment-specific setting
210+
if config.has_option(current_env_section, setting_name):
211+
threshold = config.getint(current_env_section, setting_name)
212+
threshold = validate_threshold(threshold, mcu)
213+
print(f"*** Using environment-specific bleeding edge include path threshold: {threshold} (MCU: {mcu}) ***")
214+
return threshold
215+
216+
# 3. Check global setting in [env] section
217+
if config.has_option("env", setting_name):
218+
threshold = config.getint("env", setting_name)
219+
threshold = validate_threshold(threshold, mcu)
220+
print(f"*** Using global [env] bleeding edge include path threshold: {threshold} (MCU: {mcu}) ***")
221+
return threshold
222+
223+
# 4. Check setting in [platformio] section
224+
if config.has_option("platformio", setting_name):
225+
threshold = config.getint("platformio", setting_name)
226+
threshold = validate_threshold(threshold, mcu)
227+
print(f"*** Using [platformio] section bleeding edge include path threshold: {threshold} (MCU: {mcu}) ***")
228+
return threshold
229+
230+
# 5. Use MCU-specific bleeding edge default value
231+
threshold = validate_threshold(default_threshold, mcu)
232+
if env.get("VERBOSE"):
233+
print(f"*** Using platform-specific bleeding edge default include path threshold: {threshold} (MCU: {mcu}) ***")
234+
235+
return threshold
236+
237+
except (ValueError, TypeError) as e:
238+
print(f"*** Warning: Invalid include path threshold value, using bleeding edge platform default {default_threshold} for {mcu}: {e} ***")
239+
return validate_threshold(default_threshold, mcu)
240+
241+
def get_threshold_info(env, config, current_env_section):
242+
"""
243+
Helper function for debug information about bleeding edge threshold configuration
244+
245+
Args:
246+
env: PlatformIO Environment
247+
config: Project Configuration
248+
current_env_section: Current environment section
249+
250+
Returns:
251+
dict: Information about threshold configuration
252+
"""
253+
mcu = env.BoardConfig().get("build.mcu", "esp32")
254+
setting_name = "custom_include_path_length_threshold"
255+
256+
info = {
257+
"mcu": mcu,
258+
"platform_default": get_platform_default_threshold(mcu),
259+
"env_variable": os.environ.get("PLATFORMIO_INCLUDE_PATH_THRESHOLD"),
260+
"env_specific": None,
261+
"global_env": None,
262+
"platformio_section": None,
263+
"final_threshold": None,
264+
"source": "bleeding_edge_platform_default",
265+
"is_bleeding_edge": True
266+
}
267+
268+
# Collect all possible sources
269+
if config.has_option(current_env_section, setting_name):
270+
try:
271+
info["env_specific"] = config.getint(current_env_section, setting_name)
272+
except ValueError:
273+
pass
274+
275+
if config.has_option("env", setting_name):
276+
try:
277+
info["global_env"] = config.getint("env", setting_name)
278+
except ValueError:
279+
pass
280+
281+
if config.has_option("platformio", setting_name):
282+
try:
283+
info["platformio_section"] = config.getint("platformio", setting_name)
284+
except ValueError:
285+
pass
286+
287+
# Determine final threshold and source
288+
info["final_threshold"] = get_include_path_threshold(env, config, current_env_section)
289+
290+
# Determine source
291+
if info["env_variable"]:
292+
info["source"] = "environment_variable"
293+
elif info["env_specific"] is not None:
294+
info["source"] = "env_specific"
295+
elif info["global_env"] is not None:
296+
info["source"] = "global_env"
297+
elif info["platformio_section"] is not None:
298+
info["source"] = "platformio_section"
299+
300+
return info
93301

94302
# Cache class for frequently used paths
95303
class PathCache:
@@ -545,7 +753,7 @@ def debug_framework_paths(env, include_count, total_length):
545753
print(f"*** FRAMEWORK_SDK_DIR: {FRAMEWORK_SDK_DIR} ***")
546754
print(f"*** SDK exists: {exists(FRAMEWORK_SDK_DIR)} ***")
547755
print(f"*** Include count: {include_count} ***")
548-
print(f"*** Total path length: {total_length} (threshold: {INCLUDE_PATH_LENGTH_THRESHOLD}) ***")
756+
print(f"*** Total path length: {total_length} ***")
549757

550758
includes = env.get("CPPPATH", [])
551759
framework_count = 0
@@ -619,31 +827,50 @@ def apply_include_shortening(env, node, includes, total_length):
619827
)
620828

621829
def smart_include_length_shorten(env, node):
622-
"""Include path shortening based on total path length threshold"""
830+
"""
831+
Include path shortening based on bleeding edge configurable threshold with enhanced MCU support
832+
Uses aggressive thresholds for maximum performance
833+
"""
623834
if IS_INTEGRATION_DUMP:
624-
# Don't shorten include paths for IDE integrations
625835
return node
626836

627837
if not IS_WINDOWS:
628838
return env.Object(node)
629839

630-
# Check long path support once
840+
# Get dynamically configurable bleeding edge threshold
841+
include_path_threshold = get_include_path_threshold(env, config, current_env_section)
842+
631843
check_and_warn_long_path_support()
632844

633845
includes = env.get("CPPPATH", [])
634846
include_count = len(includes)
635847
total_path_length = calculate_include_path_length(includes)
636848

637-
# Debug output in verbose mode
638-
debug_framework_paths(env, include_count, total_path_length)
639-
640-
# Apply shortening only if total path length exceeds threshold
641-
# This is more accurate than just counting includes, as it considers
642-
# the actual command line length impact
643-
if total_path_length <= INCLUDE_PATH_LENGTH_THRESHOLD:
644-
return env.Object(node) # Normal compilation
849+
# Debug information in verbose mode
850+
if env.get("VERBOSE"):
851+
debug_framework_paths(env, include_count, total_path_length)
852+
853+
# Extended debug information about bleeding edge threshold configuration
854+
threshold_info = get_threshold_info(env, config, current_env_section)
855+
print(f"*** Bleeding Edge Threshold Configuration Debug ***")
856+
print(f"*** MCU: {threshold_info['mcu']} ***")
857+
print(f"*** Bleeding Edge Platform Default: {threshold_info['platform_default']} ***")
858+
print(f"*** Final Bleeding Edge Threshold: {threshold_info['final_threshold']} ***")
859+
print(f"*** Source: {threshold_info['source']} ***")
860+
print(f"*** Performance Mode: Maximum Aggressive ***")
861+
if threshold_info['env_variable']:
862+
print(f"*** Env Variable: {threshold_info['env_variable']} ***")
863+
if threshold_info['env_specific']:
864+
print(f"*** Env Specific: {threshold_info['env_specific']} ***")
865+
if threshold_info['global_env']:
866+
print(f"*** Global Env: {threshold_info['global_env']} ***")
867+
if threshold_info['platformio_section']:
868+
print(f"*** PlatformIO Section: {threshold_info['platformio_section']} ***")
869+
870+
# Use the configurable and validated bleeding edge threshold
871+
if total_path_length <= include_path_threshold:
872+
return env.Object(node)
645873

646-
# Apply include path shortening
647874
return apply_include_shortening(env, node, includes, total_path_length)
648875

649876
def get_frameworks_in_current_env():
@@ -697,7 +924,7 @@ def get_frameworks_in_current_env():
697924
env.AddPostAction("checkprogsize", silent_action)
698925

699926
if IS_WINDOWS:
700-
# Smart include path optimization based on total path length
927+
# Smart include path optimization based on bleeding edge configurable threshold
701928
env.AddBuildMiddleware(smart_include_length_shorten)
702929

703930
build_script_path = join(FRAMEWORK_DIR, "tools", "pioarduino-build.py")

0 commit comments

Comments
 (0)