Skip to content

Commit

Permalink
Create mach bootstrap based on Mozilla's mozboot bootstrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
UK992 committed Sep 7, 2016
1 parent dd33be4 commit fc35555
Show file tree
Hide file tree
Showing 9 changed files with 340 additions and 7 deletions.
24 changes: 23 additions & 1 deletion python/servo/bootstrap_commands.py
Expand Up @@ -19,6 +19,7 @@
import sys
import StringIO
import tarfile
import zipfile
import urllib2

from mach.decorators import (
Expand Down Expand Up @@ -101,7 +102,10 @@ def download_bytes(desc, src):


def extract(src, dst, movedir=None):
tarfile.open(src).extractall(dst)
if src.endswith(".zip"):
zipfile.ZipFile(src).extractall(dst)
else:
tarfile.open(src).extractall(dst)

if movedir:
for f in os.listdir(movedir):
Expand All @@ -126,6 +130,24 @@ def env(self):
else:
print("export LD_LIBRARY_PATH=%s" % env["LD_LIBRARY_PATH"])

@Command('bootstrap',
description='Install required packages for building.',
category='bootstrap')
@CommandArgument('--interactive', "-i",
action='store_true',
help='Need to answer any (Y/n) interactive prompts.')
@CommandArgument('--android',
action='store_true',
help='Install required packages for Android')
@CommandArgument('--force', '-f',
action='store_true',
help='Force reinstall packages')
def bootstrap(self, android=False, interactive=False, force=False):
from servo.bootstrapper.bootstrap import Bootstrapper

bootstrapper = Bootstrapper()
bootstrapper.bootstrap(android=android, interactive=interactive, force=force)

@Command('bootstrap-rust',
description='Download the Rust compiler',
category='bootstrap')
Expand Down
3 changes: 3 additions & 0 deletions python/servo/bootstrapper/__init__.py
@@ -0,0 +1,3 @@
# 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/.
62 changes: 62 additions & 0 deletions python/servo/bootstrapper/base.py
@@ -0,0 +1,62 @@
# 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/.

from __future__ import print_function, unicode_literals

import distutils
import subprocess


class BaseBootstrapper(object):
"""Base class for system bootstrappers."""

def __init__(self, interactive=False):
self.package_manager_updated = False
self.interactive = interactive

def ensure_system_packages(self):
'''
Check for missing packages.
'''
raise NotImplementedError('%s must implement ensure_system_packages()' %
__name__)

def install_system_packages(self):
'''
Install packages required to build Servo.
'''
raise NotImplementedError('%s must implement install_system_packages()' %
__name__)

def install_mobile_android_packages(self):
'''
Install packages required to build Servo for Android.
'''
raise NotImplementedError('Cannot bootstrap Servo for Android: '
'%s does not yet implement install_mobile_android_packages()'
% __name__)

def which(self, name):
"""Python implementation of which.
It returns the path of an executable or None if it couldn't be found.
"""
return distutils.spawn.find_executable(name)

def check_output(self, *args, **kwargs):
"""Run subprocess.check_output."""
return subprocess.check_output(*args, **kwargs)

def _ensure_package_manager_updated(self):
if self.package_manager_updated:
return

self._update_package_manager()
self.package_manager_updated = True

def _update_package_manager(self):
"""Updates the package manager's manifests/package list.
This should be defined in child classes.
"""
41 changes: 41 additions & 0 deletions python/servo/bootstrapper/bootstrap.py
@@ -0,0 +1,41 @@
# 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/.

from __future__ import print_function

import sys

from windows_gnu import WindowsGnuBootstrapper
from windows_msvc import WindowsMsvcBootstrapper


class Bootstrapper(object):
"""Main class that performs system bootstrap."""

def __init__(self):
self.instance = None
cls = None
args = {}

if sys.platform.startswith('msys'):
cls = WindowsGnuBootstrapper

elif sys.platform.startswith('win32'):
cls = WindowsMsvcBootstrapper

if cls is None:
sys.exit('Bootstrap support is not yet available for your OS.')

self.instance = cls(**args)

def bootstrap(self, android=False, interactive=False, force=False):
self.instance.interactive = interactive
self.instance.force = force

if android:
self.instance.install_mobile_android_packages()
elif force:
self.instance.install_system_packages()
else:
self.instance.ensure_system_packages()
28 changes: 28 additions & 0 deletions python/servo/bootstrapper/packages.py
@@ -0,0 +1,28 @@
# 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/.

# Listed all packages for different platforms in one file

WINDOWS_GNU = [
"mingw-w64-x86_64-toolchain",
"mingw-w64-x86_64-freetype",
"mingw-w64-x86_64-icu",
"mingw-w64-x86_64-nspr",
"mingw-w64-x86_64-ca-certificates",
"mingw-w64-x86_64-expat",
"mingw-w64-x86_64-cmake",
"tar",
"diffutils",
"patch",
"patchutils",
"make",
"python2-setuptools",
]

WINDOWS_MSVC = [
"cmake-3.6.1",
"ninja-1.7.1",
"openssl-1.0.1t-vs2015",
"moztools-0.0.1-5",
]
75 changes: 75 additions & 0 deletions python/servo/bootstrapper/windows_gnu.py
@@ -0,0 +1,75 @@
# 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/.

import sys
import subprocess

from base import BaseBootstrapper
from packages import WINDOWS_GNU as deps


class WindowsGnuBootstrapper(BaseBootstrapper):
'''Bootstrapper for msys2 based environments for building in Windows.'''

def __init__(self, **kwargs):
BaseBootstrapper.__init__(self, **kwargs)

if not self.which('pacman'):
raise NotImplementedError('The Windows bootstrapper only works with msys2 with pacman. Get msys2 at '
'http://msys2.github.io/')

def ensure_system_packages(self):
install_packages = []
for p in deps:
command = ['pacman', '-Qs', p]
if self.run_check(command):
install_packages += [p]
if install_packages:
install_packages(install_packages)

def install_system_packages(self, packages=deps):
self._ensure_package_manager_updated()
self.pacman_install(*packages)

def install_mobile_android_packages(self):
sys.exit('We do not support building Android on Windows. Sorry!')

def _update_package_manager(self):
self.pacman_update()

def run(self, command):
subprocess.check_call(command, stdin=sys.stdin)

def run_check(self, command):
return subprocess.call(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

def pacman_update(self):
command = ['pacman', '--sync', '--refresh']
self.run(command)

def pacman_upgrade(self):
command = ['pacman', '--sync', '--refresh', '--sysupgrade']
self.run(command)

def pacman_install(self, *packages):
command = ['pacman', '--sync']
if not self.force:
command.append('--needed')
if not self.interactive:
command.append('--noconfirm')
command.extend(packages)
self.run(command)

# downgrade GCC to 5.4.0-1
gcc_type = ["gcc", "gcc-ada", "gcc-fortran", "gcc-libgfortran", "gcc-libs", "gcc-objc"]
gcc_version = "5.4.0-1"
mingw_url = "http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-{}-{}-any.pkg.tar.xz"
gcc_list = []
for gcc in gcc_type:
gcc_list += [mingw_url.format(gcc, gcc_version)]
downgrade_command = ['pacman', '-U']
if not self.interactive:
downgrade_command.append('--noconfirm')
downgrade_command.extend(gcc_list)
self.run(downgrade_command)
86 changes: 86 additions & 0 deletions python/servo/bootstrapper/windows_msvc.py
@@ -0,0 +1,86 @@
# 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/.

import os
import sys
import shutil
from distutils import spawn

from base import BaseBootstrapper
from packages import WINDOWS_MSVC as deps


class WindowsMsvcBootstrapper(BaseBootstrapper):
'''Bootstrapper for MSVC building on Windows.'''

def __init__(self, **kwargs):
BaseBootstrapper.__init__(self, **kwargs)

def ensure_system_packages(self):
self.install_system_packages()

def install_system_packages(self, packages=deps):
from servo.bootstrap_commands import extract, download_file

deps_dir = os.path.join(".servo", "msvc-dependencies")
deps_url = "https://servo-rust.s3.amazonaws.com/msvc-deps/"
first_run = True

if self.force:
if os.path.isdir(deps_dir):
shutil.rmtree(deps_dir)

if not os.path.isdir(deps_dir):
os.makedirs(deps_dir)

# Read file with installed dependencies, if exist
installed_deps_file = os.path.join(deps_dir, "installed-dependencies.txt")
if os.path.exists(installed_deps_file):
installed_deps = [l.strip() for l in open(installed_deps_file)]
else:
installed_deps = []

# list of dependencies that need to be updated
update_deps = list(set(packages) - set(installed_deps))

for dep in packages:
dep_name = dep.split("-")[0]

# Don't download CMake if already exists in PATH
if dep_name == "cmake":
if spawn.find_executable(dep_name):
continue

dep_dir = os.path.join(deps_dir, dep_name)
# if not installed or need to be updated
if not os.path.exists(dep_dir) or dep in update_deps:
if first_run:
print "Installing missing MSVC dependencies..."
first_run = False

dep_version_dir = os.path.join(deps_dir, dep)

if os.path.exists(dep_version_dir):
shutil.rmtree(dep_version_dir)

dep_zip = dep_version_dir + ".zip"
if not os.path.isfile(dep_zip):
download_file(dep, "%s%s.zip" % (deps_url, dep), dep_zip)

print "Extracting %s..." % dep,
extract(dep_zip, deps_dir)
print "done"

# Delete directory if exist
if os.path.exists(dep_dir):
shutil.rmtree(dep_dir)
os.rename(dep_version_dir, dep_dir)

# Write in installed-dependencies.txt file
with open(installed_deps_file, 'w') as installed_file:
for line in packages:
installed_file.write(line + "\n")

def install_mobile_android_packages(self):
sys.exit('We do not support building Android on Windows. Sorry!')
8 changes: 3 additions & 5 deletions python/servo/build_commands.py
Expand Up @@ -257,16 +257,14 @@ def build(self, target=None, release=False, dev=False, jobs=None,
# On windows, copy in our manifest
shutil.copy(path.join(self.get_top_dir(), "components", "servo", "servo.exe.manifest"),
servo_exe_dir)
if "msvc" in host_triple():
if "msvc" in (target or host_triple()):
msvc_x64 = "64" if "x86_64" in (target or host_triple()) else ""
# on msvc builds, use editbin to change the subsystem to windows
call(["editbin", "/nologo", "/subsystem:windows", path.join(servo_exe_dir, "servo.exe")],
verbose=verbose)
# on msvc, we need to copy in some DLLs in to the servo.exe dir
for ssl_lib in ["ssleay32md.dll", "libeay32md.dll"]:
shutil.copy(path.join(os.getenv('OPENSSL_LIB_DIR'), "../bin64", ssl_lib),
servo_exe_dir)
for ffmpeg_lib in ["avutil-55.dll", "avformat-57.dll", "avcodec-57.dll", "swresample-2.dll"]:
shutil.copy(path.join(os.getenv('FFMPEG_LIB_DIR'), "../bin", ffmpeg_lib),
shutil.copy(path.join(env['OPENSSL_LIB_DIR'], "../bin" + msvc_x64, ssl_lib),
servo_exe_dir)

elif sys.platform == "darwin":
Expand Down

0 comments on commit fc35555

Please sign in to comment.