ballistica/tools/batools/toplevelmakefile.py
2024-04-23 13:44:40 -07:00

106 lines
3.2 KiB
Python
Executable File

# 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
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