From 3c07f2572b32622fc4a45fc1992ac206d7357f88 Mon Sep 17 00:00:00 2001 From: Julianne Swinoga Date: Sun, 24 Aug 2025 15:32:53 -0400 Subject: [PATCH 1/2] Refactor get_pio_environments to use ConfigParser --- OATFWGUI/gui_logic.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/OATFWGUI/gui_logic.py b/OATFWGUI/gui_logic.py index 820951c..88b90f4 100644 --- a/OATFWGUI/gui_logic.py +++ b/OATFWGUI/gui_logic.py @@ -1,3 +1,4 @@ +import configparser import re import logging import sys @@ -31,12 +32,9 @@ def read_platformio_ini_file(logic_state: LogicState) -> List[str]: def get_pio_environments(ini_lines: List[str]) -> List[PioEnv]: - environment_lines = [ini_line for ini_line in ini_lines if ini_line.startswith('[env:')] - raw_pio_envs = [] - for environment_line in environment_lines: - match = re.search(r'\[env:(.+)\]', environment_line) - if match: - raw_pio_envs.append(match.group(1)) + platformio_ini = configparser.ConfigParser() + platformio_ini.read_string(''.join(ini_lines)) + raw_pio_envs = [s.split(':', maxsplit=1)[1] for s in platformio_ini.sections() if s.startswith('env:')] log.info(f'Found pio environments: {raw_pio_envs}') # we don't want to build native From 8c8971da41e0ca8c8b65128950e557c449e6cad8 Mon Sep 17 00:00:00 2001 From: Julianne Swinoga Date: Sun, 24 Aug 2025 15:33:30 -0400 Subject: [PATCH 2/2] Fix esp32 32kB path length problem with middleware script --- OATFWGUI/gui_logic.py | 16 +++++++ OATFWGUI/pre_script_esp32_iprefix.py | 68 ++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 OATFWGUI/pre_script_esp32_iprefix.py diff --git a/OATFWGUI/gui_logic.py b/OATFWGUI/gui_logic.py index 88b90f4..491f4e7 100644 --- a/OATFWGUI/gui_logic.py +++ b/OATFWGUI/gui_logic.py @@ -326,6 +326,21 @@ def build_fw(self): self.main_app.wSpn_build.setState(BusyIndicatorState.BAD) return + # TODO: should probably refactor the hot patch logic to use ConfigParser... + platformio_ini = configparser.ConfigParser() + platformio_ini.read(Path(self.logic_state.fw_dir, 'platformio.ini')) + ini_extra_scripts = platformio_ini['env']['extra_scripts'] + log.info(f'Extra scripts={ini_extra_scripts}') + if not 'iprefix' in ini_extra_scripts and not self.logic_state.env_is_avr_based(): + # Make sure base firmware doesn't already have the iprefix script + # AND + # Shouldn't be harmful, but it's a bit weird so we only do this on + # esp32 boards. Assume that anything not AVR based is esp32 :S + pre_script_path = Path(get_install_dir(), 'OATFWGUI', 'pre_script_esp32_iprefix.py') + env_vars = {'PLATFORMIO_EXTRA_SCRIPTS': f'pre:{pre_script_path.absolute()}'} + else: + env_vars = {} + external_processes['platformio'].start( ['run', '--environment', self.logic_state.pio_env, @@ -333,6 +348,7 @@ def build_fw(self): '--verbose' ], self.pio_build_finished, + env_vars=env_vars, ) @Slot() diff --git a/OATFWGUI/pre_script_esp32_iprefix.py b/OATFWGUI/pre_script_esp32_iprefix.py new file mode 100644 index 0000000..f1c1a46 --- /dev/null +++ b/OATFWGUI/pre_script_esp32_iprefix.py @@ -0,0 +1,68 @@ +import os + +Import("env") + + +def cprint(*args, **kwargs): + print(f'modify_test.py:', *args, **kwargs) + + +def remove_prefix(text: str, prefix: str) -> str: + if text.startswith(prefix): + return text[len(prefix):] + return text + + +def use_iprefix_for_esp32_framework(env, node): + """ + The esp32 arduino framework + (https://registry.platformio.org/platforms/platformio/espressif32) has too + many -I includes, which can easily go over the 32kB Windows process command + line limit. I consider this a bug in the framework, but we can fix it with + this platformio middleware by using GCCs + https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html#index-iwithprefixbefore, + which allows us to set a -iprefix once, then reference that prefix when + doing an -I include using -iwithprefixbefore. See + https://github.com/OpenAstroTech/OATFWGUI/issues/62 for more details. + """ + if 'INCPREFIX' in env and env['INCPREFIX'] != '-I': + cprint(f"Warning: ignoring weird prefix for {node.get_abspath()}, {env['INCPREFIX']}") + return node + + orig_include_paths = { + 'framework': [], + 'other': [], + } + for include_path in env['CPPPATH']: + if 'framework-arduinoespressif32' in include_path: + orig_include_paths['framework'].append(include_path) + else: + orig_include_paths['other'].append(include_path) + + # Find the common path for the framework, add on the path separator (since commonpath leaves it off) + common_path_prefix = os.path.commonpath(orig_include_paths['framework']) + os.sep + if len(common_path_prefix) < len('iwithprefixbefore'): + # Only continue with replacement if we'll actually see a + # reduction in the command length + return node + + new_framework_include_paths = [] + for orig_include_path in orig_include_paths['framework']: + new_framework_include_paths.append(remove_prefix(orig_include_path, common_path_prefix)) + + cprint(f'{node.get_abspath()} prefix is {common_path_prefix}') + + # If just a normal list of strings, SCONS will quote the string if it has spaces + # We don't want that, so we use a list of list of strings + iprefix_list = [['-iprefix', common_path_prefix]] + iprefixbefore_list = [['-iwithprefixbefore', f_i] for f_i in new_framework_include_paths] + normal_include_list = [['-I', o_i] for o_i in orig_include_paths['other']] + return env.Object( + node, + CCFLAGS=env['CCFLAGS'] + iprefix_list + iprefixbefore_list + normal_include_list, + INCPREFIX=None, + CPPPATH=None, + ) + + +env.AddBuildMiddleware(use_iprefix_for_esp32_framework)