@ -34,7 +34,8 @@ def parse_line(line: str) -> tuple[str, str]:
continue
return ( kind , data )
def generate ( name : str , lines : list [ str ] , enabled : set [ str ] ) - > Optional [ set [ str ] ] :
def parse_modinfo ( name : str , lines : list [ str ] , enabled : set [ str ] ) - > Optional [ dict ] :
""" Parse a modinfo file and return module metadata, or None if disabled. """
arch = " "
objs = [ ]
deps = [ ]
@ -54,21 +55,39 @@ def generate(name: str, lines: list[str], enabled: set[str]) -> Optional[set[str
# don't add a module which dependency is not enabled
# in kconfig
if data . strip ( ) not in enabled :
print ( f " /* module { data . strip ( ) } isn ' t enabled in Kconfig. */ " )
print ( " /* }, { */ " )
return None
else :
print ( " unknown: " , kind )
exit ( 1 )
print ( f ' .name = " { name } " , ' )
if arch != " " :
print ( f " .arch = { arch } , " )
print_array ( " objs " , objs )
print_array ( " deps " , deps )
print_array ( " opts " , opts )
return {
' name ' : name ,
' arch ' : arch ,
' objs ' : objs ,
' deps ' : deps ,
' opts ' : opts ,
' dep_names ' : { dep . strip ( ' " ' ) for dep in deps }
}
def generate ( modinfo : str , mod : Optional [ dict ] ,
skip_reason : Optional [ str ] ) - > None :
""" Generate C code for a module. """
print ( f " /* { modinfo } */ " )
if mod is None :
if skip_reason == " missing_deps " :
print ( " /* module has missing dependencies. */ " )
else :
print ( " /* module isn ' t enabled in Kconfig. */ " )
print ( " /* }, { */ " )
return
print ( f ' .name = " { mod [ " name " ] } " , ' )
if mod [ ' arch ' ] != " " :
print ( f " .arch = { mod [ ' arch ' ] } , " )
print_array ( " objs " , mod [ ' objs ' ] )
print_array ( " deps " , mod [ ' deps ' ] )
print_array ( " opts " , mod [ ' opts ' ] )
print ( " }, { " )
return { dep . strip ( ' " ' ) for dep in deps }
def print_pre ( ) - > None :
print ( " /* generated by scripts/modinfo-generate.py */ " )
@ -86,6 +105,8 @@ def main() -> None:
)
parser . add_argument ( ' --devices ' ,
help = ' path to config-device.mak ' )
parser . add_argument ( ' --skip-missing-deps ' , action = ' store_true ' ,
help = ' warn if a dependency is missing and continue ' )
parser . add_argument ( ' modinfo ' , nargs = ' + ' ,
help = ' modinfo files to process ' )
args = parser . parse_args ( )
@ -99,27 +120,54 @@ def main() -> None:
if config [ 1 ] . rstrip ( ) == ' y ' :
enabled . add ( config [ 0 ] [ 7 : ] ) # remove CONFIG_
deps = set ( )
modules = set ( )
print_pre ( )
# all_modules: modinfo path -> (basename, parsed module or None, skip_reason)
all_modules = { }
for modinfo in args . modinfo :
with open ( modinfo ) as f :
lines = f . readlines ( )
print ( f " /* { modinfo } */ " )
( basename , _ ) = os . path . splitext ( modinfo )
moddeps = generate ( basename , lines , enabled )
if moddeps is not None :
modules . add ( basename )
deps . update ( moddeps )
print_post ( )
mod = parse_modinfo ( basename , lines , enabled )
skip_reason = " kconfig " if mod is None else None
all_modules [ modinfo ] = ( basename , mod , skip_reason )
# Collect all available module names
available = { basename for basename , mod , _ in all_modules . values ( )
if mod is not None }
error = False
for dep in deps . difference ( modules ) :
# Collect all dependencies
all_deps = set ( )
for basename , mod , _ in all_modules . values ( ) :
if mod is not None :
all_deps . update ( mod [ ' dep_names ' ] )
# Check for missing dependencies
missing = all_deps . difference ( available )
for dep in missing :
print ( f " Dependency { dep } cannot be satisfied " , file = sys . stderr )
error = True
if error :
if missing and not args . skip_missing_deps :
exit ( 1 )
# When skipping missing deps, iteratively remove modules with
# unsatisfiable dependencies
if args . skip_missing_deps and missing :
changed = True
while changed :
changed = False
for modinfo , ( basename , mod , skip_reason ) in list ( all_modules . items ( ) ) :
if mod is None :
continue
if not mod [ ' dep_names ' ] . issubset ( available ) :
available . discard ( basename )
all_modules [ modinfo ] = ( basename , None , " missing_deps " )
changed = True
# generate output
print_pre ( )
for modinfo in args . modinfo :
( basename , mod , skip_reason ) = all_modules [ modinfo ]
generate ( modinfo , mod , skip_reason )
print_post ( )
if __name__ == " __main__ " :
main ( )