@@ -77,6 +77,69 @@ def load_extensions_map(map_path):
7777 return extensions_map
7878
7979
80+ def load_remove_extensions_map (map_path ):
81+ """
82+ Load remove extensions mapping file (blacklist).
83+
84+ Format: BOARD_NAME:branch1:branch2:...:REMOVE_EXTENSIONS="ext1,ext2"
85+ Returns dict: {(BOARD, BRANCH): set(["ext1", "ext2"])}
86+ If branches are empty (just ::), applies to all branches for that board.
87+ Extensions in this set are removed from both auto-added and manual extensions.
88+ """
89+ remove_map = {}
90+
91+ if not Path (map_path ).exists ():
92+ return remove_map
93+
94+ with open (map_path , 'r' ) as f :
95+ for line in f :
96+ line = line .strip ()
97+ # Skip comments and empty lines
98+ if not line or line .startswith ('#' ):
99+ continue
100+
101+ # Parse line: BOARD:branch1:branch2:...:REMOVE_EXTENSIONS="..."
102+ if '::REMOVE_EXTENSIONS=' not in line :
103+ continue
104+
105+ try :
106+ # Split on REMOVE_EXTENSIONS
107+ parts = line .split ('REMOVE_EXTENSIONS=' )
108+ if len (parts ) != 2 :
109+ continue
110+
111+ # Parse board and branches
112+ board_part = parts [0 ].rstrip (':' )
113+ extensions = parts [1 ].strip ('"' )
114+
115+ # Split by : to get board and branches
116+ if ':' in board_part :
117+ board_branches = board_part .split (':' )
118+ board = board_branches [0 ]
119+ branches = [b for b in board_branches [1 :] if b ] # Filter empty strings
120+ else :
121+ board = board_part
122+ branches = []
123+
124+ # Convert to set for easy removal
125+ ext_set = {ext .strip () for ext in extensions .split (',' ) if ext .strip ()}
126+
127+ # Store mapping
128+ if branches :
129+ # Specific branches
130+ for branch in branches :
131+ remove_map [(board , branch )] = ext_set
132+ else :
133+ # All branches - use empty branch as wildcard
134+ remove_map [(board , '' )] = ext_set
135+
136+ except Exception as e :
137+ print (f"Warning: Failed to parse line: { line } ({ e } )" , file = sys .stderr )
138+ continue
139+
140+ return remove_map
141+
142+
80143def load_manual_overrides (base_path ):
81144 """
82145 Load manual target overrides from .manual files.
@@ -203,11 +266,12 @@ def is_fast_hardware(entry):
203266 return True
204267
205268
206- def get_soc_extensions (entry , extensions_map = None ):
269+ def get_soc_extensions (entry , extensions_map = None , remove_extensions_map = None ):
207270 """
208271 Determine if board needs v4l2loopback-dkms and mesa-vpu extensions.
209272 For fast HDMI boards, automatically adds these extensions.
210273 Also merges manual extensions from the extensions map.
274+ Removes extensions specified in remove_extensions_map.
211275 Returns a comma-separated string of extensions or empty string.
212276 """
213277 inventory = entry .get ('in' , {}).get ('inventory' , {})
@@ -239,16 +303,31 @@ def get_soc_extensions(entry, extensions_map=None):
239303 if ext and ext not in extensions :
240304 extensions .append (ext )
241305
306+ # Remove extensions specified in remove_extensions_map
307+ if remove_extensions_map :
308+ remove_ext = None
309+ # Check for specific (board, branch) match
310+ if (board , branch ) in remove_extensions_map :
311+ remove_ext = remove_extensions_map [(board , branch )]
312+ # Check for wildcard (board, '') match
313+ elif (board , '' ) in remove_extensions_map :
314+ remove_ext = remove_extensions_map [(board , '' )]
315+
316+ if remove_ext :
317+ # Filter out extensions in the remove list
318+ extensions = [ext for ext in extensions if ext not in remove_ext ]
319+
242320 return ',' .join (extensions ) if extensions else ''
243321
244322
245- def extract_boards_by_support_level (image_info , extensions_map = None , blacklist = None ):
323+ def extract_boards_by_support_level (image_info , extensions_map = None , remove_extensions_map = None , blacklist = None ):
246324 """
247325 Extract and categorize boards by support level.
248326
249327 Args:
250328 image_info: Image information data
251329 extensions_map: Optional extensions mapping
330+ remove_extensions_map: Optional remove extensions mapping
252331 blacklist: Optional set of board names to exclude
253332
254333 Returns:
@@ -294,7 +373,7 @@ def extract_boards_by_support_level(image_info, extensions_map=None, blacklist=N
294373 'arch' : arch ,
295374 'entry' : entry ,
296375 'has_desktop_variant' : build_desktop == 'yes' ,
297- 'extensions' : get_soc_extensions (entry , extensions_map ),
376+ 'extensions' : get_soc_extensions (entry , extensions_map , remove_extensions_map ),
298377 'is_fast' : is_fast_hardware (entry )
299378 }
300379 else :
@@ -1416,8 +1495,10 @@ def main():
14161495
14171496 output_dir .mkdir (parents = True , exist_ok = True )
14181497
1419- # Load extensions map (optional) - look in output directory first , then script directory
1498+ # Load extensions map (optional) - look in output directory, then release-targets , then script directory
14201499 extensions_map_path = output_dir / 'targets-extensions.map'
1500+ if not extensions_map_path .exists ():
1501+ extensions_map_path = Path (__file__ ).parent .parent / 'release-targets' / 'targets-extensions.map'
14211502 if not extensions_map_path .exists ():
14221503 extensions_map_path = Path (__file__ ).parent / 'targets-extensions.map'
14231504 print (f"Loading extensions map from { extensions_map_path } ..." , file = sys .stderr )
@@ -1427,6 +1508,19 @@ def main():
14271508 else :
14281509 print (" No extensions map found or empty" , file = sys .stderr )
14291510
1511+ # Load remove extensions map (optional) - look in output directory, then release-targets, then script directory
1512+ remove_extensions_map_path = output_dir / 'targets-extensions.map.blacklist'
1513+ if not remove_extensions_map_path .exists ():
1514+ remove_extensions_map_path = Path (__file__ ).parent .parent / 'release-targets' / 'targets-extensions.map.blacklist'
1515+ if not remove_extensions_map_path .exists ():
1516+ remove_extensions_map_path = Path (__file__ ).parent / 'targets-extensions.map.blacklist'
1517+ print (f"Loading remove extensions map from { remove_extensions_map_path } ..." , file = sys .stderr )
1518+ remove_extensions_map = load_remove_extensions_map (remove_extensions_map_path )
1519+ if remove_extensions_map :
1520+ print (f" Loaded { len (remove_extensions_map )} remove extension rules" , file = sys .stderr )
1521+ else :
1522+ print (" No remove extensions map found or empty" , file = sys .stderr )
1523+
14301524 # Load image info
14311525 print (f"Loading { json_path } ..." , file = sys .stderr )
14321526 image_info = load_image_info (json_path )
@@ -1439,7 +1533,7 @@ def main():
14391533 apps_path = output_dir / 'targets-release-apps.yaml'
14401534 blacklist_apps = load_blacklist (str (apps_path ))
14411535 manual_apps = load_manual_overrides (str (apps_path ))
1442- conf_wip_boards_apps , _ = extract_boards_by_support_level (image_info , extensions_map , blacklist_apps )
1536+ conf_wip_boards_apps , _ = extract_boards_by_support_level (image_info , extensions_map , remove_extensions_map , blacklist_apps )
14431537 print (f" apps: { len (conf_wip_boards_apps )} boards after blacklist" , file = sys .stderr )
14441538 apps_yaml = generate_apps_yaml (conf_wip_boards_apps , manual_apps )
14451539 apps_path .write_text (apps_yaml )
@@ -1449,7 +1543,7 @@ def main():
14491543 stable_path = output_dir / 'targets-release-standard-support.yaml'
14501544 blacklist_stable = load_blacklist (str (stable_path ))
14511545 manual_stable = load_manual_overrides (str (stable_path ))
1452- conf_wip_boards_stable , _ = extract_boards_by_support_level (image_info , extensions_map , blacklist_stable )
1546+ conf_wip_boards_stable , _ = extract_boards_by_support_level (image_info , extensions_map , remove_extensions_map , blacklist_stable )
14531547 print (f" stable: { len (conf_wip_boards_stable )} boards after blacklist" , file = sys .stderr )
14541548 stable_yaml = generate_stable_yaml (conf_wip_boards_stable , manual_stable )
14551549 stable_path .write_text (stable_yaml )
@@ -1459,7 +1553,7 @@ def main():
14591553 nightly_path = output_dir / 'targets-release-nightly.yaml'
14601554 blacklist_nightly = load_blacklist (str (nightly_path ))
14611555 manual_nightly = load_manual_overrides (str (nightly_path ))
1462- conf_wip_boards_nightly , _ = extract_boards_by_support_level (image_info , extensions_map , blacklist_nightly )
1556+ conf_wip_boards_nightly , _ = extract_boards_by_support_level (image_info , extensions_map , remove_extensions_map , blacklist_nightly )
14631557 print (f" nightly: { len (conf_wip_boards_nightly )} boards after blacklist" , file = sys .stderr )
14641558 nightly_yaml = generate_nightly_yaml (conf_wip_boards_nightly , manual_nightly )
14651559 nightly_path .write_text (nightly_yaml )
@@ -1469,7 +1563,7 @@ def main():
14691563 community_path = output_dir / 'targets-release-community-maintained.yaml'
14701564 blacklist_community = load_blacklist (str (community_path ))
14711565 manual_community = load_manual_overrides (str (community_path ))
1472- _ , csc_tvb_boards_community = extract_boards_by_support_level (image_info , extensions_map , blacklist_community )
1566+ _ , csc_tvb_boards_community = extract_boards_by_support_level (image_info , extensions_map , remove_extensions_map , blacklist_community )
14731567 print (f" community: { len (csc_tvb_boards_community )} boards after blacklist" , file = sys .stderr )
14741568 community_yaml = generate_community_yaml (csc_tvb_boards_community , manual_community )
14751569 community_path .write_text (community_yaml )
0 commit comments