Source code for batools.toplevelmakefile

# Released under the MIT License. See LICENSE for details.
#
"""Updates top level Makefile based on project elements present."""

from __future__ import annotations

import os
from typing import TYPE_CHECKING
import subprocess

if TYPE_CHECKING:
    pass


[docs] def generate_top_level_makefile(projroot: str, existing_data: str) -> str: """Main script entry point.""" from efrotools.project import getprojectconfig from pathlib import Path public = getprojectconfig(Path(projroot))['public'] assert isinstance(public, bool) original = existing_data # NOTE: no longer doing this; our dummy module generation stuff is # now a nice static lazybuild target. Can remove this whole file # soon if no other uses for it come up. if bool(False): lines = original.splitlines() auto_start = lines.index('# __AUTOGENERATED_DUMMY_MODULES_BEGIN__') auto_end = lines.index('# __AUTOGENERATED_DUMMY_MODULES_END__') our_lines = [ _get_dummy_module_target(projroot), ] filtered = lines[: auto_start + 1] + our_lines + lines[auto_end:] out = '\n'.join(filtered) + '\n' else: out = original return out
def _get_dummy_module_target(projroot: str) -> str: lines = ( subprocess.run( [ 'find', os.path.join(projroot, 'src/ballistica'), '-name', 'python_*', ], check=True, capture_output=True, ) .stdout.decode() .splitlines() ) targets: list[str] = [] for line in lines: fname = os.path.split(line)[1] if ( fname.startswith('python_class_') or fname.startswith('python_methods_') ) and (fname.endswith('.cc')): assert ' ' not in line assert line.startswith(projroot + '/') targets.append(line.removeprefix(projroot + '/')) # Keep our results deterministic. targets.sort() # Also require a built binary and compiled scripts for it to use. # UPDATE - scratch that. Now just trying to make it clear that # dummy-modules should not be generated as part of regular dependency # setups but rather in a dedicated pass. # targets.append('assets-cmake-scripts') # targets.append('cmake-binary') # Let's just use a single file for dependency tracking and regenerate # all dummy modules when it is dirty. There's basically no speed difference # regenerating all dummy-modules vs a single one so this keeps things # simple. It also lets us blow away any orphaned modules. dmstatepath = 'build/dummymodules/.dummy_modules_state' dmstatedir = os.path.dirname(dmstatepath) out = ( '\n# Update dummy Python modules when source files contributing to' ' them change.\n' f'{dmstatepath}: \\\n' ) # assert targets out += ' \\\n'.join(f' {target}' for target in targets) assert ' ' not in dmstatedir out += ( '\n' f'\t@tools/pcommand with_build_lock gen_dummy_modules_lock \\\n' f' rm -rf {dmstatedir} \\&\\& mkdir -p {dmstatedir} \\\n' ' \\&\\& ./tools/pcommand gen_dummy_modules \\\n' f' \\&\\& touch {dmstatepath}' ) return out # Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum