Skip to content
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7a0aa25
refactor espidf.py with path
Jason2866 Sep 3, 2025
7283c55
Fix cache check for Arduino libraries
Jason2866 Sep 4, 2025
41ef65a
Update lib_ignore to exclude 'ble' for ESP32 boards
Jason2866 Sep 4, 2025
7f1b4e1
Update platformio.ini to ignore 'ble' library
Jason2866 Sep 4, 2025
56104c9
Add Arduino TinyUSB library support in component manager
Jason2866 Sep 4, 2025
13e7ee6
remove assert from code model check
Jason2866 Sep 4, 2025
d762d39
remove another assert
Jason2866 Sep 4, 2025
1985e31
Remove unsetting of IDF_TOOLS_PATH in espidf.py
Jason2866 Sep 4, 2025
c19ed74
Refactor component_manager.py to use pathlib
Jason2866 Sep 4, 2025
6acbe37
Implement component ignore handling and improve error messages
Jason2866 Sep 4, 2025
fbaab58
Refactor path handling to use pathlib
Jason2866 Sep 4, 2025
5fe26f6
Refactor file path handling to use pathlib
Jason2866 Sep 4, 2025
c44641e
Refactor path handling to use pathlib
Jason2866 Sep 4, 2025
0650fc7
Refactor file paths to use pathlib
Jason2866 Sep 4, 2025
79b170d
Refactor path handling to use Path objects
Jason2866 Sep 4, 2025
2eab540
Fix formatting for CMAKE_DIR in espidf.py
Jason2866 Sep 4, 2025
a8cb3fd
Fix formatting in upload command
Jason2866 Sep 4, 2025
82f30fc
Refactor find_lib_deps to use a set for ignores (more reliable)
Jason2866 Sep 4, 2025
9faaa9e
Fix formatting in UPLOADER path assignment
Jason2866 Sep 4, 2025
8a45838
Update examples by removing components
Jason2866 Sep 4, 2025
625b8a7
Align custom_component_remove entries in platformio.ini
Jason2866 Sep 4, 2025
f4bf033
Add network_provisioning to custom_component_remove
Jason2866 Sep 4, 2025
c4218bc
Add some more libs to lib_ignore
Jason2866 Sep 4, 2025
77bc425
Specify exception types in lib_ignore processing
Jason2866 Sep 5, 2025
5b43aea
Refactor file handling for custom_sdkconfig
Jason2866 Sep 5, 2025
2b3b2ca
revert custom_sdkconfig file detection
Jason2866 Sep 5, 2025
90e5e09
Improve error handling for Ninja build file and Python path find
Jason2866 Sep 5, 2025
cb86688
project link script and improve extra images handling
Jason2866 Sep 5, 2025
ada05db
Improve object path resolution in espidf.py
Jason2866 Sep 5, 2025
838e072
Refactor string formatting to be whitespace safe in path
Jason2866 Sep 5, 2025
355ca44
Refactor file paths to use f-strings
Jason2866 Sep 5, 2025
e00157c
Fix file extraction and null byte handling
Jason2866 Sep 5, 2025
b83440e
Refactor Arduino libraries path assignment
Jason2866 Sep 5, 2025
c00e566
no str in function string
Jason2866 Sep 5, 2025
2165443
Refactor arduino_libs_mcu assignment for clarity
Jason2866 Sep 5, 2025
54ece58
Handle case when ald is not defined
Jason2866 Sep 5, 2025
85ab51f
Update embedded file handling in _embed_files.py
Jason2866 Sep 5, 2025
9217fbb
Escape TARGET and SOURCES variables in command
Jason2866 Sep 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 18 additions & 22 deletions builder/frameworks/_embed_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

import shutil
from os import SEEK_CUR, SEEK_END
from os.path import basename, isfile, join
from os.path import basename, isfile
from pathlib import Path

from SCons.Script import Builder

Expand All @@ -33,7 +34,7 @@ def extract_files(cppdefines, files_type):
result = []
files = env.GetProjectOption("board_build.%s" % files_type, "").splitlines()
if files:
result.extend([join("$PROJECT_DIR", f.strip()) for f in files if f])
result.extend([str(Path("$PROJECT_DIR") / f.strip()) for f in files if f.strip()])
else:
files_define = "COMPONENT_" + files_type.upper()
for define in cppdefines:
Expand All @@ -53,9 +54,10 @@ def extract_files(cppdefines, files_type):
return []

for f in value.split(":"):
f = f.strip()
if not f:
continue
result.append(join("$PROJECT_DIR", f))
result.append(str(Path("$PROJECT_DIR") / f))

for f in result:
if not isfile(env.subst(f)):
Expand All @@ -76,10 +78,14 @@ def prepare_file(source, target, env):
shutil.copy(filepath, filepath + ".piobkp")

with open(filepath, "rb+") as fp:
fp.seek(-1, SEEK_END)
if fp.read(1) != "\0":
fp.seek(0, SEEK_CUR)
fp.seek(0, SEEK_END)
size = fp.tell()
if size == 0:
fp.write(b"\0")
else:
fp.seek(-1, SEEK_END)
if fp.read(1) != b"\0":
fp.write(b"\0")


def revert_original_file(source, target, env):
Expand All @@ -91,16 +97,16 @@ def revert_original_file(source, target, env):
def embed_files(files, files_type):
for f in files:
filename = basename(f) + ".txt.o"
file_target = env.TxtToBin(join("$BUILD_DIR", filename), f)
file_target = env.TxtToBin(str(Path("$BUILD_DIR") / filename), f)
env.Depends("$PIOMAINPROG", file_target)
if files_type == "embed_txtfiles":
env.AddPreAction(file_target, prepare_file)
env.AddPostAction(file_target, revert_original_file)
env.AppendUnique(PIOBUILDFILES=[env.File(join("$BUILD_DIR", filename))])
env.AppendUnique(PIOBUILDFILES=[env.File(str(Path("$BUILD_DIR") / filename))])


def transform_to_asm(target, source, env):
files = [join("$BUILD_DIR", s.name + ".S") for s in source]
files = [str(Path("$BUILD_DIR") / (s.name + ".S")) for s in source]
return files, source


Expand Down Expand Up @@ -133,22 +139,12 @@ def transform_to_asm(target, source, env):
action=env.VerboseAction(
" ".join(
[
join(
env.PioPlatform().get_package_dir("tool-cmake") or "",
"bin",
"cmake",
),
f'"{Path(env.PioPlatform().get_package_dir("tool-cmake") or "") / "bin" / "cmake"}"',
"-DDATA_FILE=$SOURCE",
"-DSOURCE_FILE=$TARGET",
"-DFILE_TYPE=$FILE_TYPE",
"-P",
join(
env.PioPlatform().get_package_dir("framework-espidf") or "",
"tools",
"cmake",
"scripts",
"data_file_embed_asm.cmake",
),
f'"{Path(env.PioPlatform().get_package_dir("framework-espidf") or "") / "tools" / "cmake" / "scripts" / "data_file_embed_asm.cmake"}"',
]
),
"Generating assembly for $TARGET",
Expand All @@ -171,7 +167,7 @@ def transform_to_asm(target, source, env):
files = extract_files(flags, files_type)
if "espidf" in env.subst("$PIOFRAMEWORK"):
env.Requires(
join("$BUILD_DIR", "${PROGNAME}.elf"),
str(Path("$BUILD_DIR") / "${PROGNAME}.elf"),
env.FileToAsm(
files,
FILE_TYPE="TEXT" if files_type == "embed_txtfiles" else "BINARY",
Expand Down
19 changes: 8 additions & 11 deletions builder/frameworks/arduino.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@
from SCons.Script import DefaultEnvironment, SConscript
from platformio import fs
from platformio.package.manager.tool import ToolPackageManager

IS_WINDOWS = sys.platform.startswith("win")
from platformio.compat import IS_WINDOWS

# Constants for better performance
UNICORE_FLAGS = {
Expand Down Expand Up @@ -73,7 +72,7 @@ def get_platform_default_threshold(mcu):
"esp32": 32000, # Standard ESP32
"esp32s2": 32000, # ESP32-S2
"esp32s3": 32766, # ESP32-S3
"esp32c3": 30000, # ESP32-C3
"esp32c3": 32000, # ESP32-C3
"esp32c2": 32000, # ESP32-C2
"esp32c6": 31600, # ESP32-C6
"esp32h2": 32000, # ESP32-H2
Expand Down Expand Up @@ -311,7 +310,7 @@ def framework_lib_dir(self):
def sdk_dir(self):
if self._sdk_dir is None:
self._sdk_dir = fs.to_unix_path(
join(self.framework_lib_dir, self.mcu, "include")
str(Path(self.framework_lib_dir) / self.mcu / "include")
)
return self._sdk_dir

Expand Down Expand Up @@ -507,7 +506,7 @@ def safe_remove_sdkconfig_files():
envs = [section.replace("env:", "") for section in config.sections()
if section.startswith("env:")]
for env_name in envs:
file_path = join(project_dir, f"sdkconfig.{env_name}")
file_path = str(Path(project_dir) / f"sdkconfig.{env_name}")
if exists(file_path):
safe_delete_file(file_path)

Expand Down Expand Up @@ -566,9 +565,7 @@ def safe_remove_sdkconfig_files():

SConscript("_embed_files.py", exports="env")

flag_any_custom_sdkconfig = exists(join(
platform.get_package_dir("framework-arduinoespressif32-libs"),
"sdkconfig"))
flag_any_custom_sdkconfig = exists(str(Path(FRAMEWORK_LIB_DIR) / "sdkconfig"))


def has_unicore_flags():
Expand Down Expand Up @@ -599,7 +596,7 @@ def matching_custom_sdkconfig():
if not flag_any_custom_sdkconfig:
return True, cust_sdk_is_present

last_sdkconfig_path = join(project_dir, "sdkconfig.defaults")
last_sdkconfig_path = str(Path(project_dir) / "sdkconfig.defaults")
if not exists(last_sdkconfig_path):
return False, cust_sdk_is_present

Expand Down Expand Up @@ -901,12 +898,12 @@ def get_frameworks_in_current_env():
component_manager = ComponentManager(env)
component_manager.handle_component_settings()
silent_action = env.Action(component_manager.restore_pioarduino_build_py)
# hack to silence scons command output
# silence scons command output
silent_action.strfunction = lambda target, source, env: ''
env.AddPostAction("checkprogsize", silent_action)

if IS_WINDOWS:
env.AddBuildMiddleware(smart_include_length_shorten)

build_script_path = join(FRAMEWORK_DIR, "tools", "pioarduino-build.py")
build_script_path = str(Path(FRAMEWORK_DIR) / "tools" / "pioarduino-build.py")
SConscript(build_script_path)
81 changes: 51 additions & 30 deletions builder/frameworks/component_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import re
import yaml
from yaml import SafeLoader
from os.path import join
from pathlib import Path
from typing import Set, Optional, Dict, Any, List, Tuple


Expand Down Expand Up @@ -49,8 +49,12 @@ def __init__(self, env):
self.project_src_dir = env.subst("$PROJECT_SRC_DIR")
# Get Arduino framework installation directory
self.arduino_framework_dir = self.platform.get_package_dir("framework-arduinoespressif32")
# Get Arduino libraries installation directory
ald = self.platform.get_package_dir("framework-arduinoespressif32-libs")
# Get MCU-specific Arduino libraries directory
self.arduino_libs_mcu = join(self.platform.get_package_dir("framework-arduinoespressif32-libs"), self.mcu)
self.arduino_libs_mcu = (
str(Path(ald) / self.mcu) if ald else ""
)


class ComponentLogger:
Expand Down Expand Up @@ -228,13 +232,14 @@ def _get_or_create_component_yml(self) -> str:
Absolute path to the component YAML file
"""
# Try Arduino framework first
framework_yml = join(self.config.arduino_framework_dir, "idf_component.yml")
if os.path.exists(framework_yml):
afd = self.config.arduino_framework_dir
framework_yml = str(Path(afd) / "idf_component.yml") if afd else ""
if framework_yml and os.path.exists(framework_yml):
self._create_backup(framework_yml)
return framework_yml

# Try project source directory
project_yml = join(self.config.project_src_dir, "idf_component.yml")
project_yml = str(Path(self.config.project_src_dir) / "idf_component.yml")
if os.path.exists(project_yml):
self._create_backup(project_yml)
return project_yml
Expand Down Expand Up @@ -416,9 +421,12 @@ def _backup_pioarduino_build_py(self) -> None:
"""
if "arduino" not in self.config.env.subst("$PIOFRAMEWORK"):
return

build_py_path = join(self.config.arduino_libs_mcu, "pioarduino-build.py")
backup_path = join(self.config.arduino_libs_mcu, f"pioarduino-build.py.{self.config.mcu}")

if not self.config.arduino_libs_mcu:
return

build_py_path = str(Path(self.config.arduino_libs_mcu) / "pioarduino-build.py")
backup_path = str(Path(self.config.arduino_libs_mcu) / f"pioarduino-build.py.{self.config.mcu}")

if os.path.exists(build_py_path) and not os.path.exists(backup_path):
shutil.copy2(build_py_path, backup_path)
Expand Down Expand Up @@ -446,7 +454,7 @@ def _remove_include_directory(self, component: str) -> None:
Args:
component: Component name in filesystem format
"""
include_path = join(self.config.arduino_libs_mcu, "include", component)
include_path = str(Path(self.config.arduino_libs_mcu) / "include" / component)

if os.path.exists(include_path):
shutil.rmtree(include_path)
Expand All @@ -459,7 +467,7 @@ def _remove_cpppath_entries(self) -> None:
for all components that were removed from the project. Uses
multiple regex patterns to catch different include path formats.
"""
build_py_path = join(self.config.arduino_libs_mcu, "pioarduino-build.py")
build_py_path = str(Path(self.config.arduino_libs_mcu) / "pioarduino-build.py")

if not os.path.exists(build_py_path):
return
Expand Down Expand Up @@ -577,7 +585,9 @@ def _get_lib_ignore_entries(self) -> List[str]:
'spi_flash', # Flash memory access
'esp_timer', # Timer functions
'esp_event', # Event system
'log' # Logging system
'log', # Logging system
'arduino_tinyusb', # Arduino TinyUSB library
'tinyusb' # TinyUSB library
]

filtered_entries = []
Expand Down Expand Up @@ -665,14 +675,17 @@ def _get_arduino_core_libraries(self) -> Dict[str, str]:
libraries_mapping = {}

# Path to Arduino Core Libraries
arduino_libs_dir = join(self.config.arduino_framework_dir, "libraries")
afd = self.config.arduino_framework_dir
if not afd:
return libraries_mapping
arduino_libs_dir = str(Path(afd).resolve() / "libraries")

if not os.path.exists(arduino_libs_dir):
return libraries_mapping

try:
for entry in os.listdir(arduino_libs_dir):
lib_path = join(arduino_libs_dir, entry)
lib_path = str(Path(arduino_libs_dir) / entry)
if os.path.isdir(lib_path):
lib_name = self._get_library_name_from_properties(lib_path)
if lib_name:
Expand All @@ -697,7 +710,7 @@ def _get_library_name_from_properties(self, lib_dir: str) -> Optional[str]:
Returns:
Official library name or None if not found or readable
"""
prop_path = join(lib_dir, "library.properties")
prop_path = str(Path(lib_dir) / "library.properties")
if not os.path.isfile(prop_path):
return None

Expand Down Expand Up @@ -808,7 +821,10 @@ def _map_library_to_include_path(self, lib_name: str, dir_name: str) -> str:
'esptouch': 'esp_smartconfig',
'ping': 'lwip',
'netif': 'lwip',
'tcpip': 'lwip'
'tcpip': 'lwip',
'usb': 'arduino_tinyusb',
'tinyusb': 'arduino_tinyusb',
'arduino_tinyusb': 'arduino_tinyusb'
}

# Check extended mapping first
Expand Down Expand Up @@ -837,7 +853,7 @@ def _convert_lib_name_to_include(self, lib_name: str) -> str:
Converted include directory name for path removal
"""
# Load Arduino Core Libraries on first call
if not hasattr(self, '_arduino_libraries_cache'):
if self._arduino_libraries_cache is None:
self._arduino_libraries_cache = self._get_arduino_core_libraries()

lib_name_lower = lib_name.lower()
Expand Down Expand Up @@ -886,7 +902,7 @@ def _remove_ignored_lib_includes(self) -> None:
components when dependencies are detected. Uses multiple regex
patterns to catch different include path formats.
"""
build_py_path = join(self.config.arduino_libs_mcu, "pioarduino-build.py")
build_py_path = str(Path(self.config.arduino_libs_mcu) / "pioarduino-build.py")

if not os.path.exists(build_py_path):
self.logger.log_change("Build file not found")
Expand Down Expand Up @@ -925,7 +941,10 @@ def _remove_ignored_lib_includes(self) -> None:
rf'.*"[^"]*{re.escape(lib_name)}[^"]*include[^"]*"[^,\n]*,?\n',
rf'.*join\([^)]*"include"[^)]*"{re.escape(lib_name)}"[^)]*\),?\n',
rf'.*"{re.escape(lib_name)}/include"[^,\n]*,?\n',
rf'\s*"[^"]*/{re.escape(lib_name)}/[^"]*",?\n'
rf'\s*"[^"]*[\\/]{re.escape(lib_name)}[\\/][^"]*",?\n',
# pathlib-style: Path(...)/"include"/"<name>"
rf'.*Path\([^)]*\)\s*/\s*"include"\s*/\s*"{re.escape(lib_name)}"[^,\n]*,?\n',
rf'.*Path\([^)]*{re.escape(lib_name)}[^)]*\)\s*/\s*"include"[^,\n]*,?\n'
]

removed_count = 0
Expand Down Expand Up @@ -987,8 +1006,10 @@ def _backup_pioarduino_build_py(self) -> None:
if "arduino" not in self.config.env.subst("$PIOFRAMEWORK"):
return

build_py_path = join(self.config.arduino_libs_mcu, "pioarduino-build.py")
backup_path = join(self.config.arduino_libs_mcu, f"pioarduino-build.py.{self.config.mcu}")
if not self.config.arduino_libs_mcu:
return
build_py_path = str(Path(self.config.arduino_libs_mcu) / "pioarduino-build.py")
backup_path = str(Path(self.config.arduino_libs_mcu) / f"pioarduino-build.py.{self.config.mcu}")

if os.path.exists(build_py_path) and not os.path.exists(backup_path):
shutil.copy2(build_py_path, backup_path)
Expand All @@ -1002,7 +1023,7 @@ class BackupManager:
framework build scripts, ensuring that original files can be restored
when needed or when builds are cleaned.
"""

def __init__(self, config: ComponentManagerConfig):
"""
Initialize the backup manager with configuration access.
Expand All @@ -1014,7 +1035,7 @@ def __init__(self, config: ComponentManagerConfig):
config: Configuration manager instance providing access to paths
"""
self.config = config

def backup_pioarduino_build_py(self) -> None:
"""
Create backup of the original pioarduino-build.py file.
Expand All @@ -1025,13 +1046,13 @@ def backup_pioarduino_build_py(self) -> None:
"""
if "arduino" not in self.config.env.subst("$PIOFRAMEWORK"):
return
build_py_path = join(self.config.arduino_libs_mcu, "pioarduino-build.py")
backup_path = join(self.config.arduino_libs_mcu, f"pioarduino-build.py.{self.config.mcu}")

build_py_path = str(Path(self.config.arduino_libs_mcu) / "pioarduino-build.py")
backup_path = str(Path(self.config.arduino_libs_mcu) / f"pioarduino-build.py.{self.config.mcu}")

if os.path.exists(build_py_path) and not os.path.exists(backup_path):
shutil.copy2(build_py_path, backup_path)

def restore_pioarduino_build_py(self, target=None, source=None, env=None) -> None:
"""
Restore the original pioarduino-build.py from backup.
Expand All @@ -1045,9 +1066,9 @@ def restore_pioarduino_build_py(self, target=None, source=None, env=None) -> Non
source: Build source (unused, for PlatformIO compatibility)
env: Environment (unused, for PlatformIO compatibility)
"""
build_py_path = join(self.config.arduino_libs_mcu, "pioarduino-build.py")
backup_path = join(self.config.arduino_libs_mcu, f"pioarduino-build.py.{self.config.mcu}")
build_py_path = str(Path(self.config.arduino_libs_mcu) / "pioarduino-build.py")
backup_path = str(Path(self.config.arduino_libs_mcu) / f"pioarduino-build.py.{self.config.mcu}")

if os.path.exists(backup_path):
shutil.copy2(backup_path, build_py_path)
os.remove(backup_path)
Expand Down
Loading