11Import ('env' )
2- import os .path
32from collections import deque
43from pathlib import Path # For OS-agnostic path manipulation
5- from platformio .package .manager .library import LibraryPackageManager
4+ from click import secho
5+ from SCons .Script import Exit
6+ from platformio .builder .tools .piolib import LibBuilderBase
67
7- usermod_dir = Path (env ["PROJECT_DIR" ]) / "usermods"
8- all_usermods = [f for f in usermod_dir .iterdir () if f .is_dir () and f .joinpath ('library.json' ).exists ()]
8+ usermod_dir = Path (env ["PROJECT_DIR" ]).resolve () / "usermods"
99
10- if env ['PIOENV' ] == "usermods" :
11- # Add all usermods
12- env .GetProjectConfig ().set (f"env:usermods" , 'custom_usermods' , " " .join ([f .name for f in all_usermods ]))
13-
14- def find_usermod (mod : str ):
10+ # Utility functions
11+ def find_usermod (mod : str ) -> Path :
1512 """Locate this library in the usermods folder.
1613 We do this to avoid needing to rename a bunch of folders;
1714 this could be removed later
@@ -22,51 +19,36 @@ def find_usermod(mod: str):
2219 return mp
2320 mp = usermod_dir / f"{ mod } _v2"
2421 if mp .exists ():
25- return mp
22+ return mp
2623 mp = usermod_dir / f"usermod_v2_{ mod } "
2724 if mp .exists ():
2825 return mp
2926 raise RuntimeError (f"Couldn't locate module { mod } in usermods directory!" )
3027
28+ def is_wled_module (dep : LibBuilderBase ) -> bool :
29+ """Returns true if the specified library is a wled module
30+ """
31+ return usermod_dir in Path (dep .src_dir ).parents or str (dep .name ).startswith ("wled-" )
32+
33+ ## Script starts here
34+ # Process usermod option
3135usermods = env .GetProjectOption ("custom_usermods" ,"" )
36+
37+ # Handle "all usermods" case
38+ if usermods == '*' :
39+ usermods = [f .name for f in usermod_dir .iterdir () if f .is_dir () and f .joinpath ('library.json' ).exists ()]
40+ else :
41+ usermods = usermods .split ()
42+
3243if usermods :
3344 # Inject usermods in to project lib_deps
34- proj = env .GetProjectConfig ()
35- deps = env .GetProjectOption ('lib_deps' )
36- src_dir = proj .get ("platformio" , "src_dir" )
37- src_dir = src_dir .replace ('\\ ' ,'/' )
38- mod_paths = {mod : find_usermod (mod ) for mod in usermods .split ()}
39- usermods = [f"{ mod } = symlink://{ path } " for mod , path in mod_paths .items ()]
40- proj .set ("env:" + env ['PIOENV' ], 'lib_deps' , deps + usermods )
41- # Force usermods to be installed in to the environment build state before the LDF runs
42- # Otherwise we won't be able to see them until it's too late to change their paths for LDF
43- # Logic is largely borrowed from PlaformIO internals
44- not_found_specs = []
45- for spec in usermods :
46- found = False
47- for storage_dir in env .GetLibSourceDirs ():
48- #print(f"Checking {storage_dir} for {spec}")
49- lm = LibraryPackageManager (storage_dir )
50- if lm .get_package (spec ):
51- #print("Found!")
52- found = True
53- break
54- if not found :
55- #print("Missing!")
56- not_found_specs .append (spec )
57- if not_found_specs :
58- lm = LibraryPackageManager (
59- env .subst (os .path .join ("$PROJECT_LIBDEPS_DIR" , "$PIOENV" ))
60- )
61- for spec in not_found_specs :
62- #print(f"LU: forcing install of {spec}")
63- lm .install (spec )
64-
45+ symlinks = [f"symlink://{ find_usermod (mod ).resolve ()} " for mod in usermods ]
46+ env .GetProjectConfig ().set ("env:" + env ['PIOENV' ], 'lib_deps' , env .GetProjectOption ('lib_deps' ) + symlinks )
6547
6648# Utility function for assembling usermod include paths
6749def cached_add_includes (dep , dep_cache : set , includes : deque ):
6850 """ Add dep's include paths to includes if it's not in the cache """
69- if dep not in dep_cache :
51+ if dep not in dep_cache :
7052 dep_cache .add (dep )
7153 for include in dep .get_include_dirs ():
7254 if include not in includes :
@@ -82,13 +64,6 @@ def cached_add_includes(dep, dep_cache: set, includes: deque):
8264
8365# Our new wrapper
8466def wrapped_ConfigureProjectLibBuilder (xenv ):
85- # Update usermod properties
86- # Set libArchive before build actions are added
87- for um in (um for um in xenv .GetLibBuilders () if usermod_dir in Path (um .src_dir ).parents ):
88- build = um ._manifest .get ("build" , {})
89- build ["libArchive" ] = False
90- um ._manifest ["build" ] = build
91-
9267 # Call the wrapped function
9368 result = old_ConfigureProjectLibBuilder .clone (xenv )()
9469
@@ -102,12 +77,25 @@ def wrapped_ConfigureProjectLibBuilder(xenv):
10277 for dep in result .depbuilders :
10378 cached_add_includes (dep , processed_deps , extra_include_dirs )
10479
105- for um in [dep for dep in result .depbuilders if usermod_dir in Path (dep .src_dir ).parents ]:
106- # Add the wled folder to the include path
107- um .env .PrependUnique (CPPPATH = wled_dir )
108- # Add WLED's own dependencies
109- for dir in extra_include_dirs :
110- um .env .PrependUnique (CPPPATH = dir )
80+ broken_usermods = []
81+ for dep in result .depbuilders :
82+ if is_wled_module (dep ):
83+ # Add the wled folder to the include path
84+ dep .env .PrependUnique (CPPPATH = str (wled_dir ))
85+ # Add WLED's own dependencies
86+ for dir in extra_include_dirs :
87+ dep .env .PrependUnique (CPPPATH = str (dir ))
88+ # Enforce that libArchive is not set; we must link them directly to the executable
89+ if dep .lib_archive :
90+ broken_usermods .append (dep )
91+
92+ if broken_usermods :
93+ broken_usermods = [usermod .name for usermod in broken_usermods ]
94+ secho (
95+ f"ERROR: libArchive=false is missing on usermod(s) { ' ' .join (broken_usermods )} -- modules will not compile in correctly" ,
96+ fg = "red" ,
97+ err = True )
98+ Exit (1 )
11199
112100 return result
113101
0 commit comments