70
70
ZEPHYR_BASE = Path (__file__ ).parents [4 ]
71
71
72
72
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 ]]:
74
74
"""Load Kconfig"""
75
75
with TemporaryDirectory () as td :
76
76
modules = zephyr_module .parse_modules (ZEPHYR_BASE )
77
77
78
78
# generate Kconfig.modules file
79
79
kconfig = ""
80
+ sysbuild_kconfig = ""
80
81
for module in modules :
81
82
kconfig += zephyr_module .process_kconfig (module .project , module .meta )
83
+ sysbuild_kconfig += zephyr_module .process_sysbuildkconfig (module .project , module .meta )
82
84
83
85
with open (Path (td ) / "Kconfig.modules" , "w" ) as f :
84
86
f .write (kconfig )
85
87
88
+ with open (Path (td ) / "Kconfig.sysbuild.modules" , "w" ) as f :
89
+ f .write (sysbuild_kconfig )
90
+
86
91
# generate dummy Kconfig.dts file
87
92
kconfig = ""
88
93
@@ -145,6 +150,13 @@ def kconfig_load(app: Sphinx) -> tuple[kconfiglib.Kconfig, dict[str, str]]:
145
150
os .environ ["BOARD" ] = "boards"
146
151
os .environ ["KCONFIG_BOARD_DIR" ] = str (Path (td ) / "boards" )
147
152
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
+
148
160
# insert external Kconfigs to the environment
149
161
module_paths = dict ()
150
162
for module in modules :
@@ -172,7 +184,7 @@ def kconfig_load(app: Sphinx) -> tuple[kconfiglib.Kconfig, dict[str, str]]:
172
184
if kconfig .exists ():
173
185
os .environ [f"ZEPHYR_{ name_var } _KCONFIG" ] = str (kconfig )
174
186
175
- return kconfiglib .Kconfig (ZEPHYR_BASE / "Kconfig" ), module_paths
187
+ return kconfiglib .Kconfig (ZEPHYR_BASE / "Kconfig" ), sysbuild_output , module_paths
176
188
177
189
178
190
class KconfigSearchNode (nodes .Element ):
@@ -332,13 +344,15 @@ def add_option(self, option):
332
344
333
345
334
346
def sc_fmt (sc ):
347
+ prefix = os .environ ["CONFIG_" ]
348
+
335
349
if isinstance (sc , kconfiglib .Symbol ):
336
350
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>'
338
352
elif isinstance (sc , kconfiglib .Choice ):
339
353
if not sc .name :
340
354
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>>'
342
356
343
357
return kconfiglib .standard_sc_expr_str (sc )
344
358
@@ -350,137 +364,139 @@ def kconfig_build_resources(app: Sphinx) -> None:
350
364
return
351
365
352
366
with progress_message ("Building Kconfig database..." ):
353
- kconfig , module_paths = kconfig_load (app )
367
+ kconfig , sysbuild_kconfig , module_paths = kconfig_load (app )
354
368
db = list ()
355
369
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 :
368
378
continue
369
379
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
+ }
435
499
)
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
- )
484
500
485
501
app .env .kconfig_db = db # type: ignore
486
502
0 commit comments