[tools/build/premake.py] Formatting

This commit is contained in:
Margen67 2025-07-29 01:46:45 -07:00
parent 7f7e4fd381
commit 3b3c41ab2a

View file

@ -5,123 +5,120 @@
"""Premake trampoline script. """Premake trampoline script.
""" """
__author__ = 'ben.vanik@gmail.com (Ben Vanik)' __author__ = "ben.vanik@gmail.com (Ben Vanik)"
import json from json import loads as jsonloads
import os import os
import shutil from shutil import rmtree
import subprocess import subprocess
import sys import sys
import re
self_path = os.path.dirname(os.path.abspath(__file__)) self_path = os.path.dirname(os.path.abspath(__file__))
root_path = os.path.join(self_path, '..', '..') root_path = os.path.join(self_path, "..", "..")
premake_submodule_path = os.path.join(root_path, 'third_party', 'premake-core') premake_submodule_path = os.path.join(root_path, "third_party", "premake-core")
premake_path = premake_submodule_path premake_path = premake_submodule_path
def setup_premake_path_override(): def setup_premake_path_override():
global premake_path global premake_path
premake_path = premake_submodule_path premake_path = premake_submodule_path
if sys.platform == 'linux': if sys.platform == "linux":
# On Android, the repository may be cloned to the external storage, which # On Android, the repository may be cloned to the external storage, which
# doesn't support executables in it. # doesn't support executables in it.
# In this case, premake-core needs to be checked out in the internal # In this case, premake-core needs to be checked out in the internal
# storage, which supports executables, with all the permissions as set in # storage, which supports executables, with all the permissions as set in
# its repository. # its repository.
# On Termux, the home directory is in the internal storage - use it for # On Termux, the home directory is in the internal storage - use it for
# executing. # executing.
# If xenia-build.py doesn't have execute permissions, Xenia is in the external # If xenia-build.py doesn't have execute permissions, Xenia is in the external
# storage now. # storage now.
try: try:
popen = subprocess.Popen( popen = subprocess.Popen(
['uname', '-o'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, ["uname", "-o"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
universal_newlines=True) text=True)
if popen.communicate()[0] == 'Android\n': if popen.communicate()[0] == "Android\n":
xb_file = os.path.join(root_path, 'xenia-build.py') xb_file = os.path.join(root_path, "xenia-build.py")
if (os.path.isfile(xb_file) and not os.access(xb_file, os.X_OK) and if (os.path.isfile(xb_file) and not os.access(xb_file, os.X_OK) and
'HOME' in os.environ): "HOME" in os.environ):
premake_path = os.path.join( premake_path = os.path.join(os.environ["HOME"], ".xenia-build", "premake-core")
os.environ['HOME'], '.xenia-build', 'premake-core') except Exception:
except Exception: pass
pass
setup_premake_path_override() setup_premake_path_override()
def main(): def main():
# First try the freshly-built premake. # First try the freshly-built premake.
premake5_bin = os.path.join(premake_path, 'bin', 'release', 'premake5') premake5_bin = os.path.join(premake_path, "bin", "release", "premake5")
if not has_bin(premake5_bin): if not has_bin(premake5_bin):
# No fresh build, so fallback to checked in copy (which we may not have). # No fresh build, so fallback to checked in copy (which we may not have).
premake5_bin = os.path.join(self_path, 'bin', 'premake5') premake5_bin = os.path.join(self_path, "bin", "premake5")
if not has_bin(premake5_bin): if not has_bin(premake5_bin):
# Still no valid binary, so build it. # Still no valid binary, so build it.
print('premake5 executable not found, attempting build...') print("premake5 executable not found, attempting build...")
build_premake() build_premake()
premake5_bin = os.path.join(premake_path, 'bin', 'release', 'premake5') premake5_bin = os.path.join(premake_path, "bin", "release", "premake5")
if not has_bin(premake5_bin): if not has_bin(premake5_bin):
# Nope, boned. # Nope, boned.
print('ERROR: cannot build premake5 executable.') print("ERROR: cannot build premake5 executable.")
sys.exit(1) sys.exit(1)
# Ensure the submodule has been checked out. # Ensure the submodule has been checked out.
if not os.path.exists(os.path.join(premake_path, 'scripts', 'package.lua')): if not os.path.exists(os.path.join(premake_path, "scripts", "package.lua")):
print('third_party/premake-core was not present; run xb setup...') print("third_party/premake-core was not present; run xb setup...")
sys.exit(1) sys.exit(1)
return
if sys.platform == 'win32': if sys.platform == "win32":
# Append the executable extension on windows. # Append the executable extension on windows.
premake5_bin = premake5_bin + '.exe' premake5_bin += ".exe"
return_code = shell_call([ return_code = shell_call([
premake5_bin, premake5_bin,
'--scripts=%s' % (premake_path), f"--scripts={premake_path}",
] + sys.argv[1:], ] + sys.argv[1:],
throw_on_error=False) throw_on_error=False)
sys.exit(return_code) sys.exit(return_code)
def build_premake(): def build_premake():
"""Builds premake from source. """Builds premake from source.
""" """
# Ensure that on Android, premake-core is in the internal storage. # Ensure that on Android, premake-core is in the internal storage.
clone_premake_to_internal_storage() clone_premake_to_internal_storage()
cwd = os.getcwd() cwd = os.getcwd()
try: try:
os.chdir(premake_path) os.chdir(premake_path)
if sys.platform == 'darwin': if sys.platform == "darwin":
subprocess.call([ subprocess.call([
'make', "make",
'-f', 'Bootstrap.mak', "-f", "Bootstrap.mak",
'osx', "osx",
], shell=False) ])
elif sys.platform == 'win32': elif sys.platform == "win32":
# Grab Visual Studio version and execute shell to set up environment. # Grab Visual Studio version and execute shell to set up environment.
vs_version = import_vs_environment() vs_version = import_vs_environment()
if vs_version is None: if not vs_version:
print('ERROR: Visual Studio not found!') print("ERROR: Visual Studio not found!")
sys.exit(1) sys.exit(1)
return return
subprocess.call([ subprocess.call([
'nmake', "nmake",
'-f', 'Bootstrap.mak', "-f", "Bootstrap.mak",
'windows', "windows",
], shell=False) ])
else: else:
subprocess.call([ subprocess.call([
'make', "make",
'-f', 'Bootstrap.mak', "-f", "Bootstrap.mak",
'linux', "linux",
], shell=False) ])
finally: finally:
os.chdir(cwd) os.chdir(cwd)
pass pass
def clone_premake_to_internal_storage(): def clone_premake_to_internal_storage():
@ -130,138 +127,146 @@ def clone_premake_to_internal_storage():
# premake_path is initialized to a value different than premake_submodule_path # premake_path is initialized to a value different than premake_submodule_path
# if running from the Android external storage, and may not exist yet. # if running from the Android external storage, and may not exist yet.
if premake_path == premake_submodule_path: if premake_path == premake_submodule_path:
return return
# Ensure the submodule has been checked out. # Ensure the submodule has been checked out.
if not os.path.exists( if not os.path.exists(
os.path.join(premake_submodule_path, 'scripts', 'package.lua')): os.path.join(premake_submodule_path, "scripts", "package.lua")):
print('third_party/premake-core was not present; run xb setup...') print("third_party/premake-core was not present; run xb setup...")
sys.exit(1) sys.exit(1)
return
# Create or refresh premake-core in the internal storage. # Create or refresh premake-core in the internal storage.
print('Cloning premake5 to the internal storage...') print("Cloning premake5 to the internal storage...")
shutil.rmtree(premake_path, ignore_errors=True) rmtree(premake_path, ignore_errors=True)
os.makedirs(premake_path) os.makedirs(premake_path)
shell_call([ shell_call([
'git', "git",
'clone', "clone",
'--recurse-submodules', "--depth=1",
premake_submodule_path, premake_submodule_path,
premake_path, premake_path,
]) ])
def has_bin(bin): def has_bin(bin):
"""Checks whether the given binary is present. """Checks whether the given binary is present.
""" """
for path in os.environ["PATH"].split(os.pathsep): for path in os.environ["PATH"].split(os.pathsep):
if sys.platform == 'win32': if sys.platform == "win32":
exe_file = os.path.join(path, bin + '.exe') exe_file = os.path.join(path, f"{bin}.exe")
if os.path.isfile(exe_file) and os.access(exe_file, os.X_OK): if os.path.isfile(exe_file) and os.access(exe_file, os.X_OK):
return True return True
else: else:
path = path.strip('"') path = path.strip("\"")
exe_file = os.path.join(path, bin) exe_file = os.path.join(path, bin)
if os.path.isfile(exe_file) and os.access(exe_file, os.X_OK): if os.path.isfile(exe_file) and os.access(exe_file, os.X_OK):
return True return True
return None return None
def shell_call(command, throw_on_error=True, stdout_path=None, stderr_path=None, shell=False): def shell_call(command, throw_on_error=True, stdout_path=None, stderr_path=None, shell=False):
"""Executes a shell command. """Executes a shell command.
Args: Args:
command: Command to execute, as a list of parameters. command: Command to execute, as a list of parameters.
throw_on_error: Whether to throw an error or return the status code. throw_on_error: Whether to throw an error or return the status code.
stdout_path: File path to write stdout output to. stdout_path: File path to write stdout output to.
stderr_path: File path to write stderr output to. stderr_path: File path to write stderr output to.
Returns: Returns:
If throw_on_error is False the status code of the call will be returned. If throw_on_error is False the status code of the call will be returned.
""" """
stdout_file = None stdout_file = None
if stdout_path: if stdout_path:
stdout_file = open(stdout_path, 'w') stdout_file = open(stdout_path, "w")
stderr_file = None stderr_file = None
if stderr_path: if stderr_path:
stderr_file = open(stderr_path, 'w') stderr_file = open(stderr_path, "w")
result = 0 result = 0
try: try:
if throw_on_error: if throw_on_error:
result = 1 result = 1
subprocess.check_call(command, shell=shell, stdout=stdout_file, stderr=stderr_file) subprocess.check_call(command, shell=shell, stdout=stdout_file, stderr=stderr_file)
result = 0 result = 0
else: else:
result = subprocess.call(command, shell=shell, stdout=stdout_file, stderr=stderr_file) result = subprocess.call(command, shell=shell, stdout=stdout_file, stderr=stderr_file)
finally: finally:
if stdout_file: if stdout_file:
stdout_file.close() stdout_file.close()
if stderr_file: if stderr_file:
stderr_file.close() stderr_file.close()
return result return result
def import_vs_environment(): def import_vs_environment():
"""Finds the installed Visual Studio version and imports """Finds the installed Visual Studio version and imports
interesting environment variables into os.environ. interesting environment variables into os.environ.
Returns: Returns:
A version such as 2015 or None if no installation is found. A version such as 2022 or None if no installation is found.
""" """
version = 0
install_path = None
env_tool_args = None
vswhere = subprocess.check_output('tools/vswhere/vswhere.exe -version "[15,)" -latest -format json -utf8', shell=False, universal_newlines=True, encoding="utf-8") if sys.platform != "win32":
if vswhere: return None
vswhere = json.loads(vswhere)
if vswhere and len(vswhere) > 0:
version = int(vswhere[0].get("catalog", {}).get("productLineVersion", 2017))
install_path = vswhere[0].get("installationPath", None)
if version < 2017: version = None
if 'VS140COMNTOOLS' in os.environ: install_path = None
version = 2015 env_tool_args = None
vcvars_path = os.environ['VS140COMNTOOLS']
vcvars_path = os.path.join(tools_path, '..\\..\\vc\\vcvarsall.bat')
env_tool_args = [vcvars_path, 'x64', '&&', 'set']
else:
vsdevcmd_path = os.path.join(install_path, 'Common7\\Tools\\VsDevCmd.bat')
env_tool_args = [vsdevcmd_path, '-arch=amd64', '-host_arch=amd64']
if version == 0: vswhere = subprocess.check_output(
return None "tools/vswhere/vswhere.exe -version \"[17,)\" -latest -prerelease -format json -utf8 -products"
" Microsoft.VisualStudio.Product.Enterprise"
" Microsoft.VisualStudio.Product.Professional"
" Microsoft.VisualStudio.Product.Community"
" Microsoft.VisualStudio.Product.BuildTools",
encoding="utf-8",
)
if vswhere:
vswhere = jsonloads(vswhere)
if vswhere and len(vswhere) > 0:
version = int(vswhere[0].get("catalog", {}).get("productLineVersion", 2022))
install_path = vswhere[0].get("installationPath", None)
import_subprocess_environment(env_tool_args) vsdevcmd_path = os.path.join(install_path, "Common7", "Tools", "VsDevCmd.bat")
os.environ['VSVERSION'] = str(version) if os.access(vsdevcmd_path, os.X_OK):
return version env_tool_args = [vsdevcmd_path, "-arch=amd64", "-host_arch=amd64", "&&", "set"]
else:
vcvars_path = os.path.join(install_path, "VC", "Auxiliary", "Build", "vcvarsall.bat")
env_tool_args = [vcvars_path, "x64", "&&", "set"]
if not version:
return None
import_subprocess_environment(env_tool_args)
os.environ["VSVERSION"] = f"{version}"
return version
def import_subprocess_environment(args): def import_subprocess_environment(args):
popen = subprocess.Popen( popen = subprocess.Popen(
args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
variables, _ = popen.communicate() variables, _ = popen.communicate()
envvars_to_save = ( envvars_to_save = (
'devenvdir', "devenvdir",
'include', "include",
'lib', "lib",
'libpath', "libpath",
'path', "path",
'pathext', "pathext",
'systemroot', "systemroot",
'temp', "temp",
'tmp', "tmp",
'windowssdkdir', "vcinstalldir",
) "windowssdkdir",
for line in variables.splitlines(): )
for envvar in envvars_to_save: for line in variables.splitlines():
if re.match(envvar + '=', line.lower()): for envvar in envvars_to_save:
var, setting = line.split('=', 1) if f"{envvar}=" in line.lower():
if envvar == 'path': var, setting = line.split("=", 1)
setting = os.path.dirname(sys.executable) + os.pathsep + setting if envvar == "path":
os.environ[var.upper()] = setting setting = f"{os.path.dirname(sys.executable)}{os.pathsep}{setting}"
break os.environ[var.upper()] = setting
break
if __name__ == '__main__': if __name__ == "__main__":
main() main()