Skip to content

Commit 66abb1d

Browse files
authored
Auto merge of servo#29954 - mrobinson:windows-bootstrap, r=mukilan
Windows bootstrap support <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix servo#25224 - [x] These changes do not require tests because they are just support script changes. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
2 parents 35ab311 + 633d9b0 commit 66abb1d

File tree

10 files changed

+72
-77
lines changed

10 files changed

+72
-77
lines changed

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,12 @@ manually, try the [manual build setup][manual-build].
4343

4444
- Download and run [`rustup-init.exe`](https://win.rustup.rs/) then follow the onscreen instructions.
4545
- Install [chocolatey](https://chocolatey.org/)
46-
- Run `choco install support\windows\chocolatey.config`
47-
*This will install CMake, Git, LLVM, Ninja, NuGet, Python and the Visual Studio 2019 Build Tools.*
48-
- Run `mach bootstrap-gstreamer`
46+
- Run `mach bootstrap`
47+
- *This will install CMake, Git, Ninja, NuGet, Python and the Visual Studio 2019 Build Tools
48+
via choco in an Administrator console. It can take quite a while.*
49+
- *If you already have Visual Studio 2019 installed, this may not install all necessary components.
50+
Please follow the Visual Studio 2019 installation instructions in the [manual setup][manual-build].*
51+
- Run `refreshenv`
4952

5053
See also [Windows Troubleshooting Tips][windows-tips].
5154

@@ -174,4 +177,4 @@ There are lots of mach commands you can use. You can list them with `./mach
174177
The generated documentation can be found on https://doc.servo.org/servo/index.html
175178

176179
[manual-build]: https://github.com/servo/servo/wiki/Building#manual-build-setup
177-
[windows-tips]: https://github.com/servo/servo/wiki/Building#troubleshooting-the-windows-build
180+
[windows-tips]: https://github.com/servo/servo/wiki/Building#troubleshooting-the-windows-build

python/mach_bootstrap.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,8 @@ def bootstrap_command_only(topdir):
241241
import servo.platform
242242
import servo.util
243243

244-
# We are not set up yet, so we always use the default cache directory
245-
# for the initial bootstrap.
246-
# TODO(mrobinson): Why not just run the bootstrap command in this case?
247-
248244
try:
249-
servo.platform.get().bootstrap(
250-
servo.util.get_default_cache_dir(topdir), '-f' in sys.argv)
245+
servo.platform.get().bootstrap('-f' in sys.argv or '--force' in sys.argv)
251246
except NotImplementedError as exception:
252247
print(exception)
253248
return 1

python/servo/bootstrap_commands.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def bootstrap(self, force=False):
4646
# ./mach bootstrap calls mach_bootstrap.bootstrap_command_only so that
4747
# it can install dependencies without needing mach's dependencies
4848
try:
49-
servo.platform.get().bootstrap(self.context.sharedir, force)
49+
servo.platform.get().bootstrap(force)
5050
except NotImplementedError as exception:
5151
print(exception)
5252
return 1
@@ -60,7 +60,7 @@ def bootstrap(self, force=False):
6060
help='Boostrap without confirmation')
6161
def bootstrap_gstreamer(self, force=False):
6262
try:
63-
servo.platform.get().bootstrap_gstreamer(self.context.sharedir, force)
63+
servo.platform.get().bootstrap_gstreamer(force)
6464
except NotImplementedError as exception:
6565
print(exception)
6666
return 1

python/servo/build_commands.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,11 @@ def build(self, release=False, dev=False, jobs=None, params=None, no_package=Fal
178178

179179
# Override any existing GStreamer installation with the vendored libraries.
180180
env["GSTREAMER_1_0_ROOT_" + arch['gst']] = path.join(
181-
self.msvc_package_dir("gstreamer-uwp"), arch['gst_root']
181+
servo.platform.windows.get_dependency_dir("gstreamer-uwp"), arch['gst_root']
182182
)
183183
env["PKG_CONFIG_PATH"] = path.join(
184-
self.msvc_package_dir("gstreamer-uwp"), arch['gst_root'],
185-
"lib", "pkgconfig"
184+
servo.platform.windows.get_dependency_dir("gstreamer-uwp"),
185+
arch['gst_root'], "lib", "pkgconfig"
186186
)
187187

188188
if 'windows' in host:

python/servo/command_base.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,7 @@ def get_nightly_binary_path(self, nightly_date):
476476
return self.get_executable(destination_folder)
477477

478478
def msvc_package_dir(self, package):
479-
return path.join(self.context.sharedir, "msvc-dependencies", package,
480-
servo.platform.windows.DEPENDENCIES[package])
479+
return servo.platform.windows.get_dependency_dir(package)
481480

482481
def vs_dirs(self):
483482
assert 'windows' in servo.platform.host_triple()
@@ -508,11 +507,7 @@ def build_env(self, is_build=False):
508507
extra_path = []
509508
effective_target = self.cross_compile_target or servo.platform.host_triple()
510509
if "msvc" in effective_target:
511-
extra_path += [path.join(self.msvc_package_dir("cmake"), "bin")]
512510
extra_path += [path.join(self.msvc_package_dir("llvm"), "bin")]
513-
extra_path += [path.join(self.msvc_package_dir("ninja"), "bin")]
514-
extra_path += [self.msvc_package_dir("nuget")]
515-
516511
env.setdefault("CC", "clang-cl.exe")
517512
env.setdefault("CXX", "clang-cl.exe")
518513
if self.is_uwp_build:
@@ -911,10 +906,7 @@ def ensure_bootstrapped(self, rustup_components=None):
911906
if self.context.bootstrapped:
912907
return
913908

914-
# Always check if all needed MSVC dependencies are installed
915-
target_platform = self.cross_compile_target or servo.platform.host_triple()
916-
if "msvc" in target_platform:
917-
Registrar.dispatch("bootstrap", context=self.context)
909+
servo.platform.get().passive_bootstrap()
918910

919911
if self.config["tools"]["use-rustup"]:
920912
self.ensure_rustup_version()

python/servo/platform/base.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def library_path_variable_name(self):
7575
def executable_suffix(self):
7676
return ""
7777

78-
def _platform_bootstrap(self, _cache_dir: str, _force: bool) -> bool:
78+
def _platform_bootstrap(self, _force: bool) -> bool:
7979
raise NotImplementedError("Bootstrap installation detection not yet available.")
8080

8181
def _platform_bootstrap_gstreamer(self, _force: bool) -> bool:
@@ -97,11 +97,17 @@ def is_gstreamer_installed(self, cross_compilation_target: Optional[str]) -> boo
9797
== 0
9898
)
9999

100-
def bootstrap(self, cache_dir: str, force: bool):
101-
if not self._platform_bootstrap(cache_dir, force):
100+
def bootstrap(self, force: bool):
101+
if not self._platform_bootstrap(force):
102102
print("Dependencies were already installed!")
103103

104-
def bootstrap_gstreamer(self, _cache_dir: str, force: bool):
104+
def passive_bootstrap(self) -> bool:
105+
"""A bootstrap method that is called without explicitly invoking `./mach bootstrap`
106+
but that is executed in the process of other `./mach` commands. This should be
107+
as fast as possible."""
108+
return False
109+
110+
def bootstrap_gstreamer(self, force: bool):
105111
if not self._platform_bootstrap_gstreamer(force):
106112
root = self.gstreamer_root(None)
107113
if root:

python/servo/platform/linux.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def get_distro_and_version() -> Tuple[str, str]:
9494

9595
return (distrib, version)
9696

97-
def _platform_bootstrap(self, _cache_dir: str, force: bool) -> bool:
97+
def _platform_bootstrap(self, force: bool) -> bool:
9898
if self.distro.lower() == 'nixos':
9999
print('NixOS does not need bootstrap, it will automatically enter a nix-shell')
100100
print('Just run ./mach build')

python/servo/platform/macos.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def is_gstreamer_installed(self, cross_compilation_target: Optional[str]) -> boo
5454
return False
5555
return True
5656

57-
def _platform_bootstrap(self, _cache_dir: str, force: bool) -> bool:
57+
def _platform_bootstrap(self, _force: bool) -> bool:
5858
installed_something = False
5959
try:
6060
brewfile = os.path.join(util.SERVO_ROOT, "etc", "homebrew", "Brewfile")

python/servo/platform/windows.py

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,19 @@
88
# except according to those terms.
99

1010
import os
11-
import shutil
1211
import subprocess
1312
import tempfile
1413
from typing import Optional
1514
import urllib
1615
import zipfile
17-
from distutils.version import LooseVersion
1816

19-
import six
2017
from .. import util
2118
from .base import Base
2219

2320
DEPS_URL = "https://github.com/servo/servo-build-deps/releases/download/msvc-deps/"
2421
DEPENDENCIES = {
25-
"cmake": "3.14.3",
2622
"llvm": "15.0.5",
2723
"moztools": "3.2",
28-
"ninja": "1.7.1",
29-
"nuget": "08-08-2019",
3024
"openssl": "111.3.0+1.1.1c-vs2017-2019-09-18",
3125
"gstreamer-uwp": "1.16.0.5",
3226
"openxr-loader-uwp": "1.0",
@@ -38,6 +32,11 @@
3832
DEPENDENCIES_DIR = os.path.join(util.get_target_dir(), "dependencies")
3933

4034

35+
def get_dependency_dir(package):
36+
"""Get the directory that a given Windows dependency should extract to."""
37+
return os.path.join(DEPENDENCIES_DIR, package, DEPENDENCIES[package])
38+
39+
4140
class Windows(Base):
4241
def __init__(self, triple: str):
4342
super().__init__(triple)
@@ -49,64 +48,65 @@ def executable_suffix(self):
4948
def library_path_variable_name(self):
5049
return "LIB"
5150

52-
@staticmethod
53-
def cmake_already_installed(required_version: str) -> bool:
54-
cmake_path = shutil.which("cmake")
55-
if not cmake_path:
56-
return False
57-
58-
output = subprocess.check_output([cmake_path, "--version"])
59-
cmake_version_output = six.ensure_str(output).splitlines()[0]
60-
installed_version = cmake_version_output.replace("cmake version ", "")
61-
return LooseVersion(installed_version) >= LooseVersion(required_version)
62-
6351
@classmethod
64-
def prepare_file(cls, deps_dir: str, zip_path: str, full_spec: str):
52+
def download_and_extract_dependency(cls, zip_path: str, full_spec: str):
6553
if not os.path.isfile(zip_path):
66-
zip_url = "{}{}.zip".format(DEPS_URL, urllib.parse.quote(full_spec))
54+
zip_url = f"{DEPS_URL}{urllib.parse.quote(full_spec)}.zip"
6755
util.download_file(full_spec, zip_url, zip_path)
6856

69-
print("Extracting {}...".format(full_spec), end="")
57+
zip_dir = os.path.dirname(zip_path)
58+
print(f"Extracting {full_spec} to {zip_dir}...", end="")
7059
try:
71-
util.extract(zip_path, deps_dir)
60+
util.extract(zip_path, zip_dir)
7261
except zipfile.BadZipfile:
73-
print("\nError: %s.zip is not a valid zip file, redownload..." % full_spec)
62+
print(f"\nError: {full_spec}.zip is not a valid zip file, redownload...")
7463
os.remove(zip_path)
75-
cls.prepare_file(deps_dir, zip_path, full_spec)
64+
cls.download_and_extract_dependency(zip_path, full_spec)
7665
else:
7766
print("done")
7867

79-
def _platform_bootstrap(self, cache_dir: str, _force: bool = False) -> bool:
80-
deps_dir = os.path.join(cache_dir, "msvc-dependencies")
81-
82-
def get_package_dir(package, version) -> str:
83-
return os.path.join(deps_dir, package, version)
84-
85-
to_install = {}
86-
for package, version in DEPENDENCIES.items():
87-
# Don't install CMake if it already exists in PATH
88-
if package == "cmake" and self.cmake_already_installed(version):
89-
continue
90-
91-
if not os.path.isdir(get_package_dir(package, version)):
92-
to_install[package] = version
68+
def _platform_bootstrap(self, force: bool = False) -> bool:
69+
installed_something = self.passive_bootstrap()
9370

71+
try:
72+
choco_config = os.path.join(util.SERVO_ROOT, "support", "windows", "chocolatey.config")
73+
74+
# This is the format that PowerShell wants arguments passed to it.
75+
cmd_exe_args = f"'/K','choco','install','-y','{choco_config}'"
76+
if force:
77+
cmd_exe_args += ",'-f'"
78+
79+
print(cmd_exe_args)
80+
subprocess.check_output([
81+
"powershell", "Start-Process", "-Wait", "-verb", "runAs",
82+
"cmd.exe", "-ArgumentList", f"@({cmd_exe_args})"
83+
]).decode("utf-8")
84+
except subprocess.CalledProcessError as e:
85+
print("Could not run chocolatey. Follow manual build setup instructions.")
86+
raise e
87+
88+
return installed_something
89+
90+
def passive_bootstrap(self) -> bool:
91+
"""A bootstrap method that is called without explicitly invoking `./mach bootstrap`
92+
but that is executed in the process of other `./mach` commands. This should be
93+
as fast as possible."""
94+
to_install = [package for package in DEPENDENCIES if
95+
not os.path.isdir(get_dependency_dir(package))]
9496
if not to_install:
9597
return False
9698

9799
print("Installing missing MSVC dependencies...")
98-
for package, version in to_install.items():
99-
full_spec = "{}-{}".format(package, version)
100+
for package in to_install:
101+
full_spec = "{}-{}".format(package, DEPENDENCIES[package])
100102

101-
package_dir = get_package_dir(package, version)
103+
package_dir = get_dependency_dir(package)
102104
parent_dir = os.path.dirname(package_dir)
103105
if not os.path.isdir(parent_dir):
104106
os.makedirs(parent_dir)
105107

106-
self.prepare_file(deps_dir, package_dir + ".zip", full_spec)
107-
108-
extracted_path = os.path.join(deps_dir, full_spec)
109-
os.rename(extracted_path, package_dir)
108+
self.download_and_extract_dependency(package_dir + ".zip", full_spec)
109+
os.rename(os.path.join(parent_dir, full_spec), package_dir)
110110

111111
return True
112112

support/windows/chocolatey.config

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
3-
<package id="cmake" version="3.26.4" />
3+
<package id="cmake" version="3.26.4" installArguments="ADD_CMAKE_TO_PATH=System"/>
44
<package id="git"/>
5-
<package id="llvm"/>
65
<package id="ninja"/>
76
<package id="nuget.commandline" version="6.6.0" />
87
<package id="python"/>

0 commit comments

Comments
 (0)