Fix usermod libArchive setting

Monkey-patch PlatformIO to intercept the build process after library
dependencies are loaded, but before the build is fully analyzed.  This
lets us enforce libArchive=False for usermods without making that
setting global across all libraries.

The rest of the fixup code is integrated at the same call site for
simplicity.
This commit is contained in:
Will Miles 2025-01-13 21:26:15 -05:00
parent 869e275e48
commit 0b8721c25e
3 changed files with 37 additions and 25 deletions

View File

@ -1,17 +0,0 @@
Import('env')
# Patch up each usermod's include folders to include anything referenced by wled
# This is because usermods need to include wled.h
lib_builders = env.GetLibBuilders()
um_deps = [dep for dep in lib_builders if "/usermods" in dep.src_dir]
other_deps = [dep for dep in lib_builders if "/usermods" not in dep.src_dir]
for um in um_deps:
# Add include paths for all non-usermod dependencies
for dep in other_deps:
for dir in dep.get_include_dirs():
um.env.PrependUnique(CPPPATH=dir)
# Add the wled folder to the include path
um.env.PrependUnique(CPPPATH=env["PROJECT_SRC_DIR"])
#raise RuntimeError("debug")

View File

@ -1,17 +1,19 @@
Import('env')
import os
from pathlib import Path # For OS-agnostic path manipulation
def find_usermod(mod_dir: str, mod: str):
usermod_dir = Path(env["PROJECT_DIR"]) / "usermods"
def find_usermod(mod: str):
"""Locate this library in the usermods folder.
We do this to avoid needing to rename a bunch of folders;
this could be removed later
"""
# Check name match
mp = f"{mod_dir}/{mod}"
if os.path.exists(mp):
mp = usermod_dir / mod
if mp.exists():
return mp
mp = f"{mod_dir}/usermod_v2_{mod}"
if os.path.exists(mp):
mp = usermod_dir / f"usermod_v2_{mod}"
if mp.exists():
return mp
raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!")
@ -21,6 +23,34 @@ if usermods:
deps = env.GetProjectOption('lib_deps')
src_dir = proj.get("platformio", "src_dir")
src_dir = src_dir.replace('\\','/')
mod_paths = {mod: find_usermod(f"{src_dir}/../usermods", mod) for mod in usermods.split(" ")}
mod_paths = {mod: find_usermod(mod) for mod in usermods.split(" ")}
usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()]
proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods)
# Monkey-patch ConfigureProjectLibBuilder to mark up the dependencies
# Save the old value
cpl = env.ConfigureProjectLibBuilder
# Our new wrapper
def cpl_wrapper(env):
result = cpl.clone(env)()
# Update usermod properties
lib_builders = env.GetLibBuilders()
um_deps = [dep for dep in lib_builders if usermod_dir in Path(dep.src_dir).parents]
other_deps = [dep for dep in lib_builders if usermod_dir not in Path(dep.src_dir).parents]
for um in um_deps:
# Add include paths for all non-usermod dependencies
for dep in other_deps:
for dir in dep.get_include_dirs():
um.env.PrependUnique(CPPPATH=dir)
# Add the wled folder to the include path
um.env.PrependUnique(CPPPATH=env["PROJECT_SRC_DIR"])
# Make sure we link directly, not through an archive
# Archives drop the .dtor table section we need
build = um._manifest.get("build", {})
build["libArchive"] = False
um._manifest["build"] = build
return result
# Replace the old one with ours
env.AddMethod(cpl_wrapper, "ConfigureProjectLibBuilder")

View File

@ -115,7 +115,6 @@ extra_scripts =
post:pio-scripts/strip-floats.py
pre:pio-scripts/user_config_copy.py
pre:pio-scripts/load_usermods.py
post:pio-scripts/fixup_usermods.py
pre:pio-scripts/build_ui.py
; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging)