#!/usr/bin/env python3 # Copyright 2015 Ben Vanik. All Rights Reserved. """Premake trampoline script. """ __author__ = 'ben.vanik@gmail.com (Ben Vanik)' import json import os import subprocess import sys import re self_path = os.path.dirname(os.path.abspath(__file__)) root_path = os.path.join(self_path, '..', '..') premake_path = os.path.join(root_path, 'third_party', 'premake-core') def main(): # First try the freshly-built premake. premake5_bin = os.path.join(premake_path, 'bin', 'release', 'premake5') if not has_bin(premake5_bin): # No fresh build, so fallback to checked in copy (which we may not have). premake5_bin = os.path.join(self_path, 'bin', 'premake5') if not has_bin(premake5_bin): # Still no valid binary, so build it. print('premake5 executable not found, attempting build...') build_premake() premake5_bin = os.path.join(premake_path, 'bin', 'release', 'premake5') if not has_bin(premake5_bin): # Nope, boned. print('ERROR: cannot build premake5 executable.') sys.exit(1) # Ensure the submodule has been checked out. if not os.path.exists(os.path.join(premake_path, 'scripts', 'package.lua')): print('third_party/premake-core was not present; run xb setup...') sys.exit(1) return if sys.platform == 'win32': # Append the executable extension on windows. premake5_bin = premake5_bin + '.exe' return_code = shell_call([ premake5_bin, '--scripts=%s' % (premake_path), ] + sys.argv[1:], throw_on_error=False) sys.exit(return_code) def build_premake(): """Builds premake from source. """ cwd = os.getcwd() try: os.chdir(premake_path) if sys.platform == 'darwin': subprocess.call([ 'make', '-f', 'Bootstrap.mak', 'osx', ], shell=False) elif sys.platform == 'win32': # Grab Visual Studio version and execute shell to set up environment. vs_version = import_vs_environment() if vs_version is None: print('ERROR: Visual Studio not found!') sys.exit(1) return subprocess.call([ 'nmake', '-f', 'Bootstrap.mak', 'windows', ], shell=False) else: subprocess.call([ 'make', '-f', 'Bootstrap.mak', 'linux', ], shell=False) finally: os.chdir(cwd) pass def has_bin(bin): """Checks whether the given binary is present. """ for path in os.environ["PATH"].split(os.pathsep): if sys.platform == 'win32': exe_file = os.path.join(path, bin + '.exe') if os.path.isfile(exe_file) and os.access(exe_file, os.X_OK): return True else: path = path.strip('"') exe_file = os.path.join(path, bin) if os.path.isfile(exe_file) and os.access(exe_file, os.X_OK): return True return None def shell_call(command, throw_on_error=True, stdout_path=None): """Executes a shell command. Args: command: Command to execute, as a list of parameters. throw_on_error: Whether to throw an error or return the status code. stdout_path: File path to write stdout output to. Returns: If throw_on_error is False the status code of the call will be returned. """ stdout_file = None if stdout_path: stdout_file = open(stdout_path, 'w') result = 0 try: if throw_on_error: result = 1 subprocess.check_call(command, shell=False, stdout=stdout_file) result = 0 else: result = subprocess.call(command, shell=False, stdout=stdout_file) finally: if stdout_file: stdout_file.close() return result def import_vs_environment(): """Finds the installed Visual Studio version and imports interesting environment variables into os.environ. Returns: A version such as 2015 or None if no installation is found. """ version = 0 install_path = None env_tool_args = None vswhere = subprocess.check_output('third_party/vswhere/vswhere.exe -version "[15,)" -latest -format json', shell=False, universal_newlines=True) if vswhere: 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: if 'VS140COMNTOOLS' in os.environ: version = 2015 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: return None import_subprocess_environment(env_tool_args) os.environ['VSVERSION'] = str(version) return version def import_subprocess_environment(args): popen = subprocess.Popen( args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) variables, _ = popen.communicate() envvars_to_save = ( 'devenvdir', 'include', 'lib', 'libpath', 'path', 'pathext', 'systemroot', 'temp', 'tmp', 'windowssdkdir', ) for line in variables.splitlines(): for envvar in envvars_to_save: if re.match(envvar + '=', line.lower()): var, setting = line.split('=', 1) if envvar == 'path': setting = os.path.dirname(sys.executable) + os.pathsep + setting os.environ[var.upper()] = setting break def git_submodule_update(): """Runs a full recursive git submodule init and update. Older versions of git do not support 'update --init --recursive'. We could check and run it on versions that do support it and speed things up a bit. """ if True: shell_call([ 'git', 'submodule', 'update', '--init', '--recursive', ]) else: shell_call([ 'git', 'submodule', 'init', ]) shell_call([ 'git', 'submodule', 'foreach', '--recursive', 'git', 'submodule', 'init', ]) shell_call([ 'git', 'submodule', 'update', '--recursive', ]) if __name__ == '__main__': main()