mirror of
https://github.com/pret/pokeplatinum.git
synced 2026-10-25 18:10:40 -05:00
136 lines
4.2 KiB
Python
Executable File
136 lines
4.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
"""Generate LSF and Meson source lists from one manifest.
|
|
|
|
The manifest follows the same format as the LSF, replacing source objects and
|
|
paths to the object that Meson builds. The Meson source lists are built by a
|
|
split between .c and .s to produce appropriate inputs for configuration.
|
|
"""
|
|
|
|
import argparse
|
|
import enum
|
|
import pathlib
|
|
import re
|
|
import sys
|
|
import typing
|
|
|
|
|
|
class ManifestError(Exception):
|
|
lineno: int
|
|
|
|
def __init__(self, lineno: int, message: str):
|
|
super().__init__(message)
|
|
self.lineno = lineno
|
|
|
|
|
|
class Arguments(argparse.Namespace):
|
|
manifest: pathlib.Path = pathlib.Path(".")
|
|
prefix_dir: str = "main.nef.p"
|
|
dest_lsf: pathlib.Path = pathlib.Path("platinum.us/main.lsf")
|
|
dest_c: pathlib.Path = pathlib.Path("src/meson.build")
|
|
dest_asm: pathlib.Path = pathlib.Path("asm/meson.build")
|
|
|
|
|
|
class FileKind(enum.Enum):
|
|
c = enum.auto()
|
|
o = enum.auto()
|
|
asm = enum.auto()
|
|
|
|
|
|
class Parsed:
|
|
lsf_lines: list[str]
|
|
sources: dict[FileKind, list[pathlib.Path]]
|
|
|
|
def __init__(self):
|
|
self.lsf_lines = []
|
|
self.sources = { kind: [] for kind in FileKind }
|
|
|
|
|
|
OBJECT_RE = re.compile(r"^(\s*Object\s+)(\S+)(.*)$")
|
|
KIND_BY_EXT = {".c": FileKind.c, ".s": FileKind.asm, ".o": FileKind.o}
|
|
|
|
|
|
def parse_args() -> Arguments:
|
|
assert __doc__, "Missing docstring"
|
|
argp = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
_ = argp.add_argument("manifest", metavar="MANIFEST")
|
|
_ = argp.add_argument("--prefix-dir", metavar="PREFIX",
|
|
help="Use PREFIX as a directory prefix for source-objects in the generated LSF")
|
|
_ = argp.add_argument("--dest-lsf", metavar="OUT",
|
|
help="Write the generated LSF to OUT")
|
|
_ = argp.add_argument("--dest-c", metavar="OUT",
|
|
help="Write the generated C source-list to OUT")
|
|
_ = argp.add_argument("--dest-asm", metavar="OUT",
|
|
help="Write the generated ASM source-list to OUT")
|
|
|
|
args = Arguments()
|
|
_ = argp.parse_args(namespace=args)
|
|
return args
|
|
|
|
|
|
def parse_input(fp: typing.TextIO, prefix: str) -> Parsed:
|
|
parsed = Parsed()
|
|
seen: set[pathlib.Path] = set()
|
|
|
|
for lineno, line in enumerate(fp, 1):
|
|
match = OBJECT_RE.match(line)
|
|
if not match:
|
|
parsed.lsf_lines.append(line)
|
|
continue
|
|
|
|
path = pathlib.Path(match.group(2))
|
|
kind = KIND_BY_EXT.get(path.suffix)
|
|
|
|
# If specifying a precompiled object, assume the user knows what they're doing
|
|
if kind is FileKind.o:
|
|
parsed.lsf_lines.append(line)
|
|
continue
|
|
|
|
if kind is None:
|
|
raise ManifestError(lineno, f"{path}: unknown source type '{path.suffix}' (expected .c or .s)")
|
|
if path in seen:
|
|
raise ManifestError(lineno, f"{path}: duplicate listing")
|
|
|
|
seen.add(path)
|
|
parsed.sources[kind].append(path)
|
|
parsed.lsf_lines.append(f"{match.group(1)}{prefix}{str(path).replace('/', '_')}.o{match.group(3)}\n")
|
|
|
|
return parsed
|
|
|
|
|
|
def generate_meson(parsed: Parsed, kind: FileKind, manifest: pathlib.Path) -> str:
|
|
header = f"# Generated by tools/lsfgen from {manifest}. DO NOT EDIT!"
|
|
entries = "".join(f""" '{"/".join(path.parts[1:])}',\n""" for path in parsed.sources[kind])
|
|
variable = f"pokeplatinum_{kind.name}"
|
|
return f"{header}\n{variable} = files(\n{entries})"
|
|
|
|
|
|
def write_meson(target: pathlib.Path, parsed: Parsed, kind: FileKind, manifest: pathlib.Path) -> None:
|
|
if not parsed.sources[kind]:
|
|
return
|
|
|
|
with open(target, "w", encoding="utf-8") as fp:
|
|
_ = fp.write(generate_meson(parsed, kind, manifest))
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
|
|
with open(args.manifest, encoding="utf-8") as fp:
|
|
try:
|
|
parsed = parse_input(fp, args.prefix_dir)
|
|
except ManifestError as e:
|
|
print(f"{args.manifest}:{e.lineno}: {e}", file=sys.stderr)
|
|
return 1
|
|
|
|
with open(args.dest_lsf, "w", encoding="utf-8") as fp:
|
|
fp.writelines(parsed.lsf_lines)
|
|
|
|
write_meson(args.dest_c, parsed, FileKind.c, args.manifest)
|
|
write_meson(args.dest_asm, parsed, FileKind.asm, args.manifest)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|