From ee82ad59b43a6d747d636604ace143ac9e868e1c Mon Sep 17 00:00:00 2001 From: mhkrebs <25705611+mhkrebs@users.noreply.github.com> Date: Sun, 8 Jun 2025 01:33:51 -0700 Subject: [PATCH 1/2] Fix matching of "components" dir when there's a symlink in the path to .platformio compile_source_files() uses a relative path for the object if the source file is within the "components" tree. It checks the path string with .startswith(), though, and that can fail if the paths point to the same file but look different due to symlinks. In my case, it saw two different source paths in target-__idf_efuse-5f3f9f6e3513e0903efa.json: 1. /space/home/user/.platformio/packages/framework-espidf/components/efuse/esp32c6/esp_efuse_fields.c 2. /space/home/user/.platformio/packages/framework-espidf/components/efuse/src/esp_efuse_fields.c But my home directory uses a symlink, so components_dir was: - /home/user/.platformio/packages/framework-espidf/components This resulted in attempting to build the same object file for both: *** Multiple ways to build the same target were specified for: /space/home/user/git/project/esphome/.esphome/build/device/.pioenvs/device/esp_efuse_fields.c.o (from ['/space/home/user/.platformio/packages/framework-espidf/components/efuse/esp32c6/esp_efuse_fields.c'] and from ['/space/home/user/.platformio/packages/framework-espidf/components/efuse/src/esp_efuse_fields.c']) File "/home/user/.platformio/platforms/espressif32/builder/frameworks/espidf.py", line 773, in compile_source_files This fix simply resolves any symlinks in components_dir before using it for the comparison. --- builder/frameworks/espidf.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/builder/frameworks/espidf.py b/builder/frameworks/espidf.py index a939c6889..857550a46 100644 --- a/builder/frameworks/espidf.py +++ b/builder/frameworks/espidf.py @@ -28,6 +28,7 @@ import os import re import platform as sys_platform +from pathlib import Path import click import semantic_version @@ -760,7 +761,12 @@ def compile_source_files( ): build_envs = prepare_build_envs(config, default_env, debug_allowed) objects = [] - components_dir = fs.to_unix_path(os.path.join(FRAMEWORK_DIR, "components")) + # The source "path" will have had any symlinks resolved, so resolve any + # symlinks in components_dir in order for the .startswith() to work as + # expected below. + components_dir = str( + Path(fs.to_unix_path(os.path.join(FRAMEWORK_DIR, "components"))).resolve() + ) for source in config.get("sources", []): if source["path"].endswith(".rule"): continue From 435b7708128640f417902970c97a571b2ff1f96d Mon Sep 17 00:00:00 2001 From: mhkrebs <25705611+mhkrebs@users.noreply.github.com> Date: Tue, 17 Jun 2025 01:08:49 -0700 Subject: [PATCH 2/2] Update my fix to work on Windows My original fix resolved links in `components_dir`, but apparently the source paths might not be resolved themselves (at least on Windows). This fix simply resolves links in both before doing the comparison. --- builder/frameworks/espidf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/frameworks/espidf.py b/builder/frameworks/espidf.py index 857550a46..378e6044f 100644 --- a/builder/frameworks/espidf.py +++ b/builder/frameworks/espidf.py @@ -781,7 +781,7 @@ def compile_source_files( src_path = os.path.join(project_src_dir, src_path) obj_path = os.path.join("$BUILD_DIR", prepend_dir or "") - if src_path.lower().startswith(components_dir.lower()): + if str(Path(src_path).resolve()).lower().startswith(components_dir.lower()): obj_path = os.path.join( obj_path, os.path.relpath(src_path, components_dir) )