mirror of
https://github.com/servo/servo.git
synced 2025-07-02 21:13:39 +01:00
189 lines
7.3 KiB
Bash
Executable file
189 lines
7.3 KiB
Bash
Executable file
#!/bin/sh
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
# The beginning of this script is both valid shell and valid python,
|
|
# such that the script starts with the shell and is reexecuted with
|
|
# the right python.
|
|
''':' && if [ ! -z "$MSYSTEM" ] ; then exec python "$0" "$@" ; else which python2.7 > /dev/null 2> /dev/null && exec python2.7 "$0" "$@" || exec python "$0" "$@" ; fi
|
|
'''
|
|
|
|
from __future__ import print_function, unicode_literals
|
|
|
|
import itertools
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
def main(args):
|
|
topdir = os.path.abspath(os.path.dirname(sys.argv[0]))
|
|
sys.path.insert(0, os.path.join(topdir, "python"))
|
|
import mach_bootstrap
|
|
mach = mach_bootstrap.bootstrap(topdir)
|
|
sys.exit(mach.run(sys.argv[1:]))
|
|
|
|
def validate_pair(ob):
|
|
if not (len(ob) == 2):
|
|
print("Unexpected result:", ob, file=sys.stderr)
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
def consume(iter):
|
|
try:
|
|
while True: next(iter)
|
|
except StopIteration:
|
|
pass
|
|
|
|
def get_environment_from_batch_command(env_cmd, initial=None):
|
|
"""
|
|
Take a command (either a single command or list of arguments)
|
|
and return the environment created after running that command.
|
|
Note that if the command must be a batch file or .cmd file, or the
|
|
changes to the environment will not be captured.
|
|
If initial is supplied, it is used as the initial environment passed
|
|
to the child process.
|
|
"""
|
|
if not isinstance(env_cmd, (list, tuple)):
|
|
env_cmd = [env_cmd]
|
|
# Construct the command that will alter the environment.
|
|
env_cmd = subprocess.list2cmdline(env_cmd)
|
|
# Create a tag so we can tell in the output when the proc is done.
|
|
tag = 'END OF BATCH COMMAND'
|
|
# Construct a cmd.exe command to do accomplish this.
|
|
cmd = 'cmd.exe /s /c "{env_cmd} && echo "{tag}" && set"'.format(**vars())
|
|
# Launch the process.
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=initial)
|
|
# Parse the output sent to stdout.
|
|
lines = proc.stdout
|
|
# Consume whatever output occurs until the tag is reached.
|
|
consume(itertools.takewhile(lambda l: tag not in l, lines))
|
|
# Define a way to handle each KEY=VALUE line.
|
|
handle_line = lambda l: l.rstrip().split('=',1)
|
|
# Parse key/values into pairs.
|
|
pairs = map(handle_line, lines)
|
|
# Make sure the pairs are valid.
|
|
valid_pairs = filter(validate_pair, pairs)
|
|
# Construct a dictionary of the pairs.
|
|
result = dict(valid_pairs)
|
|
# Let the process finish.
|
|
proc.communicate()
|
|
return result
|
|
|
|
def get_vs_env(vs_version, arch):
|
|
"""
|
|
Returns the env object for VS building environment.
|
|
The vs_version can be strings like "[15.0,16.0)", meaning 2017, but not the next version.
|
|
The arch has to be one of "x86", "amd64", "arm", "x86_amd64", "x86_arm", "amd64_x86",
|
|
"amd64_arm", e.g. the args passed to vcvarsall.bat.
|
|
"""
|
|
|
|
# vswhere can't handle spaces, like "[15.0, 16.0)" should become "[15.0,16.0)"
|
|
vs_version = vs_version.replace(" ", "")
|
|
|
|
# Find visual studio
|
|
proc = subprocess.Popen(
|
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe "
|
|
"-property installationPath "
|
|
"-requires Microsoft.VisualStudio.Component.VC.CoreIde "
|
|
"-format value "
|
|
"-version {0}".format(vs_version),
|
|
stdout=subprocess.PIPE)
|
|
|
|
location = proc.stdout.readline().rstrip()
|
|
# Launch the process.
|
|
vsvarsall = "{0}\\VC\\Auxiliary\\Build\\vcvarsall.bat".format(location)
|
|
|
|
return get_environment_from_batch_command([vsvarsall, arch])
|
|
|
|
def import_vs_env():
|
|
if sys.platform != 'win32':
|
|
return
|
|
|
|
if ('PROGRAMFILES(X86)' in os.environ) == False:
|
|
print('32-bit Windows is currently unsupported.')
|
|
sys.exit(-1)
|
|
|
|
arch = 'x64'
|
|
if os.path.isfile("C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe"):
|
|
env = get_vs_env('[15.0,16.0)', arch)
|
|
os.environ.update(env)
|
|
elif 'VS140COMNTOOLS' in os.environ:
|
|
vs14vsvarsall = os.path.abspath(os.path.join(os.environ['VS140COMNTOOLS'], '..\\..\\VC\\vcvarsall.bat'))
|
|
env = get_environment_from_batch_command([vs14vsvarsall, arch])
|
|
os.environ.update(env)
|
|
else:
|
|
print("Visual Studio 2017 is not installed.\nDownload and install Visual Studio 2017 from https://www.visualstudio.com/")
|
|
sys.exit(-1)
|
|
|
|
if __name__ == '__main__':
|
|
sys.dont_write_bytecode = True
|
|
import_vs_env()
|
|
|
|
if sys.platform == 'win32':
|
|
# This is a complete hack to work around the fact that Windows
|
|
# multiprocessing needs to import the original module (ie: this
|
|
# file), but only works if it has a .py extension.
|
|
#
|
|
# We do this by a sort of two-level function interposing. The first
|
|
# level interposes forking.get_command_line() with our version defined
|
|
# in my_get_command_line(). Our version of get_command_line will
|
|
# replace the command string with the contents of the fork_interpose()
|
|
# function to be used in the subprocess.
|
|
#
|
|
# The subprocess then gets an interposed imp.find_module(), which we
|
|
# hack up to find 'mach' without the .py extension, since we already
|
|
# know where it is (it's us!). If we're not looking for 'mach', then
|
|
# the original find_module will suffice.
|
|
#
|
|
# See also: http://bugs.python.org/issue19946
|
|
# And: https://bugzilla.mozilla.org/show_bug.cgi?id=914563
|
|
import inspect
|
|
from multiprocessing import forking
|
|
global orig_command_line
|
|
|
|
def fork_interpose():
|
|
import imp
|
|
import os
|
|
import sys
|
|
orig_find_module = imp.find_module
|
|
def my_find_module(name, dirs):
|
|
if name == 'mach':
|
|
path = os.path.join(dirs[0], 'mach')
|
|
f = open(path)
|
|
return (f, path, ('', 'r', imp.PY_SOURCE))
|
|
return orig_find_module(name, dirs)
|
|
|
|
# Don't allow writing bytecode file for mach module.
|
|
orig_load_module = imp.load_module
|
|
def my_load_module(name, file, path, description):
|
|
# multiprocess.forking invokes imp.load_module manually and
|
|
# hard-codes the name __parents_main__ as the module name.
|
|
if name == '__parents_main__':
|
|
old_bytecode = sys.dont_write_bytecode
|
|
sys.dont_write_bytecode = True
|
|
try:
|
|
return orig_load_module(name, file, path, description)
|
|
finally:
|
|
sys.dont_write_bytecode = old_bytecode
|
|
|
|
return orig_load_module(name, file, path, description)
|
|
|
|
imp.find_module = my_find_module
|
|
imp.load_module = my_load_module
|
|
from multiprocessing.forking import main; main()
|
|
|
|
def my_get_command_line():
|
|
fork_code, lineno = inspect.getsourcelines(fork_interpose)
|
|
# Remove the first line (for 'def fork_interpose():') and the three
|
|
# levels of indentation (12 spaces).
|
|
fork_string = ''.join(x[12:] for x in fork_code[1:])
|
|
cmdline = orig_command_line()
|
|
cmdline[2] = fork_string
|
|
return cmdline
|
|
orig_command_line = forking.get_command_line
|
|
forking.get_command_line = my_get_command_line
|
|
|
|
main(sys.argv)
|