7070ZEPHYR_BASE = Path (__file__ ).parents [4 ]
7171
7272
73- def kconfig_load (app : Sphinx ) -> tuple [kconfiglib .Kconfig , dict [str , str ]]:
73+ def kconfig_load (app : Sphinx ) -> tuple [kconfiglib .Kconfig , kconfiglib . Kconfig , dict [str , str ]]:
7474 """Load Kconfig"""
7575 with TemporaryDirectory () as td :
7676 modules = zephyr_module .parse_modules (ZEPHYR_BASE )
7777
7878 # generate Kconfig.modules file
7979 kconfig = ""
80+ sysbuild_kconfig = ""
8081 for module in modules :
8182 kconfig += zephyr_module .process_kconfig (module .project , module .meta )
83+ sysbuild_kconfig += zephyr_module .process_sysbuildkconfig (module .project , module .meta )
8284
8385 with open (Path (td ) / "Kconfig.modules" , "w" ) as f :
8486 f .write (kconfig )
8587
88+ with open (Path (td ) / "Kconfig.sysbuild.modules" , "w" ) as f :
89+ f .write (sysbuild_kconfig )
90+
8691 # generate dummy Kconfig.dts file
8792 kconfig = ""
8893
@@ -145,6 +150,13 @@ def kconfig_load(app: Sphinx) -> tuple[kconfiglib.Kconfig, dict[str, str]]:
145150 os .environ ["BOARD" ] = "boards"
146151 os .environ ["KCONFIG_BOARD_DIR" ] = str (Path (td ) / "boards" )
147152
153+ # Sysbuild runs first
154+ os .environ ["CONFIG_" ] = "SB_CONFIG_"
155+ sysbuild_output = kconfiglib .Kconfig (ZEPHYR_BASE / "share" / "sysbuild" / "Kconfig" )
156+
157+ # Normal Kconfig runs second
158+ os .environ ["CONFIG_" ] = "CONFIG_"
159+
148160 # insert external Kconfigs to the environment
149161 module_paths = dict ()
150162 for module in modules :
@@ -172,7 +184,7 @@ def kconfig_load(app: Sphinx) -> tuple[kconfiglib.Kconfig, dict[str, str]]:
172184 if kconfig .exists ():
173185 os .environ [f"ZEPHYR_{ name_var } _KCONFIG" ] = str (kconfig )
174186
175- return kconfiglib .Kconfig (ZEPHYR_BASE / "Kconfig" ), module_paths
187+ return kconfiglib .Kconfig (ZEPHYR_BASE / "Kconfig" ), sysbuild_output , module_paths
176188
177189
178190class KconfigSearchNode (nodes .Element ):
@@ -332,13 +344,15 @@ def add_option(self, option):
332344
333345
334346def sc_fmt (sc ):
347+ prefix = os .environ ["CONFIG_" ]
348+
335349 if isinstance (sc , kconfiglib .Symbol ):
336350 if sc .nodes :
337- return f'<a href="#CONFIG_ { sc .name } ">CONFIG_ { sc .name } </a>'
351+ return f'<a href="#{ prefix } { sc .name } ">{ prefix } { sc .name } </a>'
338352 elif isinstance (sc , kconfiglib .Choice ):
339353 if not sc .name :
340354 return "<choice>"
341- return f'<choice <a href="#CONFIG_ { sc .name } ">CONFIG_ { sc .name } </a>>'
355+ return f'<choice <a href="#{ prefix } { sc .name } ">{ prefix } { sc .name } </a>>'
342356
343357 return kconfiglib .standard_sc_expr_str (sc )
344358
@@ -350,137 +364,139 @@ def kconfig_build_resources(app: Sphinx) -> None:
350364 return
351365
352366 with progress_message ("Building Kconfig database..." ):
353- kconfig , module_paths = kconfig_load (app )
367+ kconfig , sysbuild_kconfig , module_paths = kconfig_load (app )
354368 db = list ()
355369
356- for sc in sorted (
357- chain (kconfig .unique_defined_syms , kconfig .unique_choices ),
358- key = lambda sc : sc .name if sc .name else "" ,
359- ):
360- # skip nameless symbols
361- if not sc .name :
362- continue
363-
364- # store alternative defaults (from defconfig files)
365- alt_defaults = list ()
366- for node in sc .nodes :
367- if "defconfig" not in node .filename :
370+ for kconfig_obj in [kconfig , sysbuild_kconfig ]:
371+ os .environ ["CONFIG_" ] = kconfig_obj .config_prefix
372+ for sc in sorted (
373+ chain (kconfig_obj .unique_defined_syms , kconfig_obj .unique_choices ),
374+ key = lambda sc : sc .name if sc .name else "" ,
375+ ):
376+ # skip nameless symbols
377+ if not sc .name :
368378 continue
369379
370- for value , cond in node .orig_defaults :
371- fmt = kconfiglib .expr_str (value , sc_fmt )
372- if cond is not sc .kconfig .y :
373- fmt += f" if { kconfiglib .expr_str (cond , sc_fmt )} "
374- alt_defaults .append ([fmt , node .filename ])
375-
376- # build list of symbols that select/imply the current one
377- # note: all reverse dependencies are ORed together, and conditionals
378- # (e.g. select/imply A if B) turns into A && B. So we first split
379- # by OR to include all entries, and we split each one by AND to just
380- # take the first entry.
381- selected_by = list ()
382- if isinstance (sc , kconfiglib .Symbol ) and sc .rev_dep != sc .kconfig .n :
383- for select in kconfiglib .split_expr (sc .rev_dep , kconfiglib .OR ):
384- sym = kconfiglib .split_expr (select , kconfiglib .AND )[0 ]
385- selected_by .append (f"CONFIG_{ sym .name } " )
386-
387- implied_by = list ()
388- if isinstance (sc , kconfiglib .Symbol ) and sc .weak_rev_dep != sc .kconfig .n :
389- for select in kconfiglib .split_expr (sc .weak_rev_dep , kconfiglib .OR ):
390- sym = kconfiglib .split_expr (select , kconfiglib .AND )[0 ]
391- implied_by .append (f"CONFIG_{ sym .name } " )
392-
393- # only process nodes with prompt or help
394- nodes = [node for node in sc .nodes if node .prompt or node .help ]
395-
396- inserted_paths = list ()
397- for node in nodes :
398- # avoid duplicate symbols by forcing unique paths. this can
399- # happen due to dependencies on 0, a trick used by some modules
400- path = f"{ node .filename } :{ node .linenr } "
401- if path in inserted_paths :
402- continue
403- inserted_paths .append (path )
404-
405- dependencies = None
406- if node .dep is not sc .kconfig .y :
407- dependencies = kconfiglib .expr_str (node .dep , sc_fmt )
408-
409- defaults = list ()
410- for value , cond in node .orig_defaults :
411- fmt = kconfiglib .expr_str (value , sc_fmt )
412- if cond is not sc .kconfig .y :
413- fmt += f" if { kconfiglib .expr_str (cond , sc_fmt )} "
414- defaults .append (fmt )
415-
416- selects = list ()
417- for value , cond in node .orig_selects :
418- fmt = kconfiglib .expr_str (value , sc_fmt )
419- if cond is not sc .kconfig .y :
420- fmt += f" if { kconfiglib .expr_str (cond , sc_fmt )} "
421- selects .append (fmt )
422-
423- implies = list ()
424- for value , cond in node .orig_implies :
425- fmt = kconfiglib .expr_str (value , sc_fmt )
426- if cond is not sc .kconfig .y :
427- fmt += f" if { kconfiglib .expr_str (cond , sc_fmt )} "
428- implies .append (fmt )
429-
430- ranges = list ()
431- for min , max , cond in node .orig_ranges :
432- fmt = (
433- f"[{ kconfiglib .expr_str (min , sc_fmt )} , "
434- f"{ kconfiglib .expr_str (max , sc_fmt )} ]"
380+ # store alternative defaults (from defconfig files)
381+ alt_defaults = list ()
382+ for node in sc .nodes :
383+ if "defconfig" not in str (node .filename ):
384+ continue
385+
386+ for value , cond in node .orig_defaults :
387+ fmt = kconfiglib .expr_str (value , sc_fmt )
388+ if cond is not sc .kconfig .y :
389+ fmt += f" if { kconfiglib .expr_str (cond , sc_fmt )} "
390+ alt_defaults .append ([fmt , node .filename ])
391+
392+ # build list of symbols that select/imply the current one
393+ # note: all reverse dependencies are ORed together, and conditionals
394+ # (e.g. select/imply A if B) turns into A && B. So we first split
395+ # by OR to include all entries, and we split each one by AND to just
396+ # take the first entry.
397+ selected_by = list ()
398+ if isinstance (sc , kconfiglib .Symbol ) and sc .rev_dep != sc .kconfig .n :
399+ for select in kconfiglib .split_expr (sc .rev_dep , kconfiglib .OR ):
400+ sym = kconfiglib .split_expr (select , kconfiglib .AND )[0 ]
401+ selected_by .append (f"{ kconfig_obj .config_prefix } { sym .name } " )
402+
403+ implied_by = list ()
404+ if isinstance (sc , kconfiglib .Symbol ) and sc .weak_rev_dep != sc .kconfig .n :
405+ for select in kconfiglib .split_expr (sc .weak_rev_dep , kconfiglib .OR ):
406+ sym = kconfiglib .split_expr (select , kconfiglib .AND )[0 ]
407+ implied_by .append (f"{ kconfig_obj .config_prefix } { sym .name } " )
408+
409+ # only process nodes with prompt or help
410+ nodes = [node for node in sc .nodes if node .prompt or node .help ]
411+
412+ inserted_paths = list ()
413+ for node in nodes :
414+ # avoid duplicate symbols by forcing unique paths. this can
415+ # happen due to dependencies on 0, a trick used by some modules
416+ path = f"{ node .filename } :{ node .linenr } "
417+ if path in inserted_paths :
418+ continue
419+ inserted_paths .append (path )
420+
421+ dependencies = None
422+ if node .dep is not sc .kconfig .y :
423+ dependencies = kconfiglib .expr_str (node .dep , sc_fmt )
424+
425+ defaults = list ()
426+ for value , cond in node .orig_defaults :
427+ fmt = kconfiglib .expr_str (value , sc_fmt )
428+ if cond is not sc .kconfig .y :
429+ fmt += f" if { kconfiglib .expr_str (cond , sc_fmt )} "
430+ defaults .append (fmt )
431+
432+ selects = list ()
433+ for value , cond in node .orig_selects :
434+ fmt = kconfiglib .expr_str (value , sc_fmt )
435+ if cond is not sc .kconfig .y :
436+ fmt += f" if { kconfiglib .expr_str (cond , sc_fmt )} "
437+ selects .append (fmt )
438+
439+ implies = list ()
440+ for value , cond in node .orig_implies :
441+ fmt = kconfiglib .expr_str (value , sc_fmt )
442+ if cond is not sc .kconfig .y :
443+ fmt += f" if { kconfiglib .expr_str (cond , sc_fmt )} "
444+ implies .append (fmt )
445+
446+ ranges = list ()
447+ for min , max , cond in node .orig_ranges :
448+ fmt = (
449+ f"[{ kconfiglib .expr_str (min , sc_fmt )} , "
450+ f"{ kconfiglib .expr_str (max , sc_fmt )} ]"
451+ )
452+ if cond is not sc .kconfig .y :
453+ fmt += f" if { kconfiglib .expr_str (cond , sc_fmt )} "
454+ ranges .append (fmt )
455+
456+ choices = list ()
457+ if isinstance (sc , kconfiglib .Choice ):
458+ for sym in sc .syms :
459+ choices .append (kconfiglib .expr_str (sym , sc_fmt ))
460+
461+ menupath = ""
462+ iternode = node
463+ while iternode .parent is not iternode .kconfig .top_node :
464+ iternode = iternode .parent
465+ if iternode .prompt :
466+ title = iternode .prompt [0 ]
467+ else :
468+ title = kconfiglib .standard_sc_expr_str (iternode .item )
469+ menupath = f" > { title } " + menupath
470+
471+ menupath = "(Top)" + menupath
472+
473+ filename = str (node .filename )
474+ for name , path in module_paths .items ():
475+ path += "/"
476+ if str (node .filename ).startswith (path ):
477+ filename = str (node .filename ).replace (path , f"<module:{ name } >/" )
478+ break
479+
480+ db .append (
481+ {
482+ "name" : f"{ kconfig_obj .config_prefix } { sc .name } " ,
483+ "prompt" : node .prompt [0 ] if node .prompt else None ,
484+ "type" : kconfiglib .TYPE_TO_STR [sc .type ],
485+ "help" : node .help ,
486+ "dependencies" : dependencies ,
487+ "defaults" : defaults ,
488+ "alt_defaults" : alt_defaults ,
489+ "selects" : selects ,
490+ "selected_by" : selected_by ,
491+ "implies" : implies ,
492+ "implied_by" : implied_by ,
493+ "ranges" : ranges ,
494+ "choices" : choices ,
495+ "filename" : filename ,
496+ "linenr" : node .linenr ,
497+ "menupath" : menupath ,
498+ }
435499 )
436- if cond is not sc .kconfig .y :
437- fmt += f" if { kconfiglib .expr_str (cond , sc_fmt )} "
438- ranges .append (fmt )
439-
440- choices = list ()
441- if isinstance (sc , kconfiglib .Choice ):
442- for sym in sc .syms :
443- choices .append (kconfiglib .expr_str (sym , sc_fmt ))
444-
445- menupath = ""
446- iternode = node
447- while iternode .parent is not iternode .kconfig .top_node :
448- iternode = iternode .parent
449- if iternode .prompt :
450- title = iternode .prompt [0 ]
451- else :
452- title = kconfiglib .standard_sc_expr_str (iternode .item )
453- menupath = f" > { title } " + menupath
454-
455- menupath = "(Top)" + menupath
456-
457- filename = node .filename
458- for name , path in module_paths .items ():
459- path += "/"
460- if node .filename .startswith (path ):
461- filename = node .filename .replace (path , f"<module:{ name } >/" )
462- break
463-
464- db .append (
465- {
466- "name" : f"CONFIG_{ sc .name } " ,
467- "prompt" : node .prompt [0 ] if node .prompt else None ,
468- "type" : kconfiglib .TYPE_TO_STR [sc .type ],
469- "help" : node .help ,
470- "dependencies" : dependencies ,
471- "defaults" : defaults ,
472- "alt_defaults" : alt_defaults ,
473- "selects" : selects ,
474- "selected_by" : selected_by ,
475- "implies" : implies ,
476- "implied_by" : implied_by ,
477- "ranges" : ranges ,
478- "choices" : choices ,
479- "filename" : filename ,
480- "linenr" : node .linenr ,
481- "menupath" : menupath ,
482- }
483- )
484500
485501 app .env .kconfig_db = db # type: ignore
486502
0 commit comments