scripts/modinfo: add --skip-missing-deps
Add --skip-missing-deps flag that prints warnings for missing dependencies but continues without exiting with error code 1. Acked-by: Mark Cave-Ayland <mark.caveayland@nutanix.com> Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
error = False
|
||||
for dep in deps.difference(modules):
|
||||
# Collect all available module names
|
||||
available = {basename for basename, mod, _ in all_modules.values()
|
||||
if mod is not None}
|
||||
|
||||
# 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()
|
||||
|
||||
Reference in New Issue
Block a user