diff --git a/builder/frameworks/arduino.py b/builder/frameworks/arduino.py index 3ff6de9fd..3eb65ccfa 100644 --- a/builder/frameworks/arduino.py +++ b/builder/frameworks/arduino.py @@ -532,6 +532,7 @@ def safe_remove_sdkconfig_files(): flag_custom_component_remove = False flag_custom_component_add = False flag_lib_ignore = False +flag_lto = False if mcu == "esp32c2": flag_custom_sdkconfig = True @@ -598,6 +599,10 @@ def has_psram_config(): if has_unicore_flags(): build_unflags += " -ustart_app_other_cores" + # Check for enabling LTO for Arduino HybridCompile part by unflagging -fno-lto + if '-fno-lto' in build_unflags: + flag_lto = True + new_build_unflags = build_unflags.split() env.Replace(BUILD_UNFLAGS=new_build_unflags) @@ -916,6 +921,13 @@ def get_frameworks_in_current_env(): from component_manager import ComponentManager component_manager = ComponentManager(env) component_manager.handle_component_settings() + + # Handle LTO flags if flag_lto is set + if flag_lto: + # First remove existing -fno-lto flags, then add LTO flags + component_manager.remove_no_lto_flags() + component_manager.add_lto_flags() + silent_action = env.Action(component_manager.restore_pioarduino_build_py) # silence scons command output silent_action.strfunction = lambda target, source, env: '' diff --git a/builder/frameworks/component_manager.py b/builder/frameworks/component_manager.py index 5a34e8bde..c73a6e18c 100644 --- a/builder/frameworks/component_manager.py +++ b/builder/frameworks/component_manager.py @@ -1271,3 +1271,109 @@ def print_changes_summary(self) -> None: session, useful for build reporting and debugging. """ self.logger.print_changes_summary() + + def remove_no_lto_flags(self) -> bool: + """ + Remove all -fno-lto flags from pioarduino-build.py. + + Removes all occurrences of -fno-lto from CCFLAGS, CFLAGS, CXXFLAGS, + and LINKFLAGS in the Arduino build script. + + Returns: + bool: True if successful, False otherwise + """ + build_py_path = str(Path(self.config.arduino_libs_mcu) / "pioarduino-build.py") + + if not os.path.exists(build_py_path): + print(f"Warning: pioarduino-build.py not found at {build_py_path}") + return False + + try: + with open(build_py_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Remove all -fno-lto flags + modified_content = re.sub(r'["\']?-fno-lto["\']?,?\s*', '', content) + + # Clean up any resulting empty strings or double commas + modified_content = re.sub(r',\s*,', ',', modified_content) + modified_content = re.sub(r'\[\s*,', '[', modified_content) + modified_content = re.sub(r',\s*\]', ']', modified_content) + + with open(build_py_path, 'w', encoding='utf-8') as f: + f.write(modified_content) + + return True + + except (IOError, OSError) as e: + print(f"Error removing -fno-lto flags: {e}") + return False + + def add_lto_flags(self) -> bool: + """ + Add LTO flags to pioarduino-build.py. + + Adds -flto=auto to CCFLAGS, CFLAGS, CXXFLAGS and -flto to LINKFLAGS + in the Arduino build script. Flags are inserted right after the opening bracket. + + Returns: + bool: True if successful, False otherwise + """ + build_py_path = str(Path(self.config.arduino_libs_mcu) / "pioarduino-build.py") + + if not os.path.exists(build_py_path): + print(f"Warning: pioarduino-build.py not found at {build_py_path}") + return False + + try: + with open(build_py_path, 'r', encoding='utf-8') as f: + content = f.read() + + modified = False + + # Add -flto=auto to CCFLAGS right after the opening bracket + if 'CCFLAGS=[' in content: + ccflags_start = content.find('CCFLAGS=[') + ccflags_section_start = ccflags_start + len('CCFLAGS=[') + content = (content[:ccflags_section_start] + + '\n "-flto=auto",' + + content[ccflags_section_start:]) + modified = True + + # Add -flto=auto to CFLAGS right after the opening bracket + if 'CFLAGS=[' in content: + cflags_start = content.find('CFLAGS=[') + cflags_section_start = cflags_start + len('CFLAGS=[') + content = (content[:cflags_section_start] + + '\n "-flto=auto",' + + content[cflags_section_start:]) + modified = True + + # Add -flto=auto to CXXFLAGS right after the opening bracket + if 'CXXFLAGS=[' in content: + cxxflags_start = content.find('CXXFLAGS=[') + cxxflags_section_start = cxxflags_start + len('CXXFLAGS=[') + content = (content[:cxxflags_section_start] + + '\n "-flto=auto",' + + content[cxxflags_section_start:]) + modified = True + + # Add -flto to LINKFLAGS right after the opening bracket + if 'LINKFLAGS=[' in content: + linkflags_start = content.find('LINKFLAGS=[') + linkflags_section_start = linkflags_start + len('LINKFLAGS=[') + content = (content[:linkflags_section_start] + + '\n "-flto",' + + content[linkflags_section_start:]) + modified = True + + if modified: + with open(build_py_path, 'w', encoding='utf-8') as f: + f.write(content) + + print("*** Added LTO flags for Arduino compile ***") + return True + + except (IOError, OSError) as e: + print(f"Error adding LTO flags: {e}") + return False diff --git a/examples/tasmota_platformio_override.ini b/examples/tasmota_platformio_override.ini index 4ba00f20b..af8b88c5d 100644 --- a/examples/tasmota_platformio_override.ini +++ b/examples/tasmota_platformio_override.ini @@ -10,6 +10,7 @@ board = esp32 build_flags = ${env:tasmota32_base.build_flags} -DHTTPCLIENT_NOSECURE -DUPDATE_NOCRYPT +build_unflags = -fno-lto lib_ignore = ${env:tasmota32_base.lib_ignore} Micro-RTSP epdiy