diff options
Diffstat (limited to 'python/servo/command_base.py')
-rw-r--r-- | python/servo/command_base.py | 192 |
1 files changed, 124 insertions, 68 deletions
diff --git a/python/servo/command_base.py b/python/servo/command_base.py index e6209b0cf23..268422fa38f 100644 --- a/python/servo/command_base.py +++ b/python/servo/command_base.py @@ -10,6 +10,7 @@ from __future__ import print_function import contextlib +from typing import Optional import distro import functools import gzip @@ -38,7 +39,7 @@ import servo.util as util from xml.etree.ElementTree import XML from servo.util import download_file, get_default_cache_dir -from mach.decorators import CommandArgument +from mach.decorators import CommandArgument, CommandArgumentGroup from mach.registrar import Registrar BIN_SUFFIX = ".exe" if sys.platform == "win32" else "" @@ -228,6 +229,10 @@ class CommandBase(object): def __init__(self, context): self.context = context + self.features = [] + self.cross_compile_target = None + self.is_uwp_build = False + self.is_android_build = False def get_env_bool(var, default): # Contents of env vars are strings by default. This returns the @@ -285,8 +290,9 @@ class CommandBase(object): self.config["android"].setdefault("sdk", "") self.config["android"].setdefault("ndk", "") self.config["android"].setdefault("toolchain", "") + # Set default android target - self.handle_android_target("armv7-linux-androideabi") + self.setup_configuration_for_android_target("armv7-linux-androideabi") _rust_toolchain = None @@ -516,12 +522,13 @@ class CommandBase(object): 'vcdir': vcinstalldir, } - def build_env(self, hosts_file_path=None, target=None, is_build=False, test_unit=False, uwp=False, features=None): + def build_env(self, hosts_file_path=None, is_build=False, test_unit=False, features=None): """Return an extended environment dictionary.""" env = os.environ.copy() if not features or "media-dummy" not in features: - servo.platform.get().set_gstreamer_environment_variables_if_necessary(env, cross_compilation_target=target) + servo.platform.get().set_gstreamer_environment_variables_if_necessary( + env, cross_compilation_target=self.cross_compile_target) if sys.platform == "win32" and type(env['PATH']) == six.text_type: # On win32, the virtualenv's activate_this.py script sometimes ends up @@ -532,7 +539,8 @@ class CommandBase(object): # it in any case. env['PATH'] = env['PATH'].encode('ascii', 'ignore') extra_path = [] - if "msvc" in (target or servo.platform.host_triple()): + effective_target = self.cross_compile_target or servo.platform.host_triple() + if "msvc" in effective_target: extra_path += [path.join(self.msvc_package_dir("cmake"), "bin")] extra_path += [path.join(self.msvc_package_dir("llvm"), "bin")] extra_path += [path.join(self.msvc_package_dir("ninja"), "bin")] @@ -540,20 +548,20 @@ class CommandBase(object): env.setdefault("CC", "clang-cl.exe") env.setdefault("CXX", "clang-cl.exe") - if uwp: + if self.is_uwp_build: env.setdefault("TARGET_CFLAGS", "") env.setdefault("TARGET_CXXFLAGS", "") env["TARGET_CFLAGS"] += " -DWINAPI_FAMILY=WINAPI_FAMILY_APP" env["TARGET_CXXFLAGS"] += " -DWINAPI_FAMILY=WINAPI_FAMILY_APP" - arch = (target or servo.platform.host_triple()).split('-')[0] + arch = effective_target.split('-')[0] vcpkg_arch = { "x86_64": "x64-windows", "i686": "x86-windows", "aarch64": "arm64-windows", } target_arch = vcpkg_arch[arch] - if uwp: + if self.is_uwp_build: target_arch += "-uwp" openssl_base_dir = path.join(self.msvc_package_dir("openssl"), target_arch) @@ -657,9 +665,10 @@ class CommandBase(object): env['CCACHE'] = self.config["build"]["ccache"] # Ensure Rust uses hard floats and SIMD on ARM devices - if target: - if target.startswith('arm') or target.startswith('aarch64'): - env['RUSTFLAGS'] = env.get('RUSTFLAGS', "") + " -C target-feature=+neon" + if self.cross_compile_target and ( + self.cross_compile_target.startswith('arm') + or self.cross_compile_target.startswith('aarch64')): + env['RUSTFLAGS'] = env.get('RUSTFLAGS', "") + " -C target-feature=+neon" env['RUSTFLAGS'] = env.get('RUSTFLAGS', "") + " -W unused-extern-crates" @@ -708,107 +717,151 @@ class CommandBase(object): return env @staticmethod - def build_like_command_arguments(decorated_function): + def build_like_command_arguments(original_function): decorators = [ + CommandArgumentGroup('Cross Compilation'), CommandArgument( '--target', '-t', + group="Cross Compilation", default=None, help='Cross compile for given target platform', ), CommandArgument( - '--media-stack', - default=None, - choices=["gstreamer", "dummy"], - help='Which media stack to use', + '--android', default=None, action='store_true', + help='Build for Android. If --target is not specified, this ' + 'will choose a default target architecture.', ), CommandArgument( - '--android', - default=None, + '--uwp', + group="Cross Compilation", action='store_true', - help='Build for Android', + help='Build for HoloLens (x64)'), + CommandArgument('--win-arm64', action='store_true', help="Use arm64 Windows target"), + CommandArgumentGroup('Feature Selection'), + CommandArgument( + '--features', default=None, group="Feature Selection", nargs='+', + help='Space-separated list of features to also build', + ), + CommandArgument( + '--media-stack', default=None, group="Feature Selection", + choices=["gstreamer", "dummy"], help='Which media stack to use', ), CommandArgument( '--libsimpleservo', default=None, + group="Feature Selection", action='store_true', help='Build the libsimpleservo library instead of the servo executable', ), CommandArgument( - '--features', - default=None, - help='Space-separated list of features to also build', - nargs='+', - ), - CommandArgument( '--debug-mozjs', - default=None, + default=False, + group="Feature Selection", action='store_true', help='Enable debug assertions in mozjs', ), CommandArgument( '--with-debug-assertions', - default=None, + default=False, + group="Feature Selection", action='store_true', help='Enable debug assertions in release', ), CommandArgument( '--with-frame-pointer', - default=None, + default=None, group="Feature Selection", action='store_true', help='Build with frame pointer enabled, used by the background hang monitor.', ), - CommandArgument('--with-layout-2020', '--layout-2020', default=None, action='store_true'), - CommandArgument('--with-layout-2013', '--layout-2013', default=None, action='store_true'), - CommandArgument('--without-wgl', default=None, action='store_true'), + CommandArgument( + '--with-layout-2020', '--layout-2020', + group="Feature Selection", default=None, action='store_true'), + CommandArgument( + '--with-layout-2013', '--layout-2013', group="Feature Selection", default=None, action='store_true'), + CommandArgument('--without-wgl', group="Feature Selection", default=None, action='store_true'), ] + def configuration_decorator(self, *args, **kwargs): + self.configure_cross_compilation( + kwargs['target'], kwargs['android'], + kwargs['uwp'], kwargs['win_arm64']) + + self.features = kwargs.get("features", None) or [] + self.configure_media_stack(kwargs['media_stack']) + original_function(self, *args, **kwargs) + + decorators.reverse() + decorated_function = configuration_decorator for decorator in decorators: decorated_function = decorator(decorated_function) return decorated_function - def pick_target_triple(self, target, android): + def configure_cross_compilation( + self, + cross_compile_target: Optional[str], + android: Optional[str], + uwp: Optional[str], + win_arm64: Optional[str]): + # Force the UWP-enabled target if the convenience UWP flags are passed. + if uwp and not cross_compile_target: + if win_arm64: + cross_compile_target = 'aarch64-uwp-windows-msvc' + else: + cross_compile_target = 'x86_64-uwp-windows-msvc' + if android is None: android = self.config["build"]["android"] - if target and android: - assert self.handle_android_target(target) - if android and not target: - target = self.config["android"]["target"] - if target and not android: - android = self.handle_android_target(target) - return target, android - - # A guess about which platforms should use the gstreamer media stack - def pick_media_stack(self, media_stack, target): + if android: + if not cross_compile_target: + cross_compile_target = self.config["android"]["target"] + assert cross_compile_target + assert self.setup_configuration_for_android_target(cross_compile_target) + elif cross_compile_target: + # If a target was specified, it might also be an android target, + # so set up the configuration in that case. + self.setup_configuration_for_android_target(cross_compile_target) + + self.cross_compile_target = cross_compile_target + self.is_uwp_build = uwp or (cross_compile_target and "uwp" in cross_compile_target) + self.is_android_build = (cross_compile_target and "android" in cross_compile_target) + + if self.cross_compile_target: + print(f"Targeting '{self.cross_compile_target}' for cross-compilation") + + def configure_media_stack(self, media_stack: Optional[str]): + """Determine what media stack to use based on the value of the build target + platform and the value of the '--media-stack' command-line argument. + The chosen media stack is written into the `features` instance variable.""" if not media_stack: if self.config["build"]["media-stack"] != "auto": media_stack = self.config["build"]["media-stack"] + assert media_stack elif ( - not target - or ("armv7" in target and "android" in target) - or "x86_64" in target - or "uwp" in target + not self.cross_compile_target + or ("armv7" in self.cross_compile_target and self.is_android_build) + or "x86_64" in self.cross_compile_target + or "uwp" in self.cross_compile_target ): media_stack = "gstreamer" else: media_stack = "dummy" - return ["media-" + media_stack] + self.features += ["media-" + media_stack] def run_cargo_build_like_command( self, command, cargo_args, env=None, verbose=False, - target=None, android=False, libsimpleservo=False, - features=None, debug_mozjs=False, with_debug_assertions=False, + libsimpleservo=False, + debug_mozjs=False, with_debug_assertions=False, with_frame_pointer=False, without_wgl=False, with_layout_2020=False, with_layout_2013=False, - uwp=False, media_stack=None, + **_kwargs ): env = env or self.build_env() - target, android = self.pick_target_triple(target, android) args = [] if "--manifest-path" not in cargo_args: - if libsimpleservo or android: - if android: + if libsimpleservo or self.is_android_build: + if self.is_android_build: api = "jniapi" else: api = "capi" @@ -819,19 +872,17 @@ class CommandBase(object): "--manifest-path", path.join(self.context.topdir, "ports", port, "Cargo.toml"), ] - if target: - args += ["--target", target] - - if features is None: # If we're passed a list, mutate it even if it's empty - features = [] + if self.cross_compile_target: + args += ["--target", self.cross_compile_target] + features = list(self.features) if "-p" not in cargo_args: # We're building specific package, that may not have features if self.config["build"]["debug-mozjs"] or debug_mozjs: features.append("debugmozjs") features.append("native-bluetooth") - if uwp: + if self.is_uwp_build: features.append("no-wgl") features.append("uwp") else: @@ -856,7 +907,7 @@ class CommandBase(object): assert "--features" not in cargo_args args += ["--features", " ".join(features)] - if target and 'uwp' in target: + if self.is_uwp_build: cargo_args += ["-Z", "build-std"] return self.call_rustup_run(["cargo", command] + args + cargo_args, env=env, verbose=verbose) @@ -880,7 +931,10 @@ class CommandBase(object): return sdk_adb return "emulator" - def handle_android_target(self, target): + def setup_configuration_for_android_target(self, target: str): + """If cross-compilation targets Android, configure the Android + build by writing the appropriate toolchain configuration values + into the stored configuration.""" if target == "armv7-linux-androideabi": self.config["android"]["platform"] = "android-21" self.config["android"]["target"] = target @@ -908,13 +962,12 @@ class CommandBase(object): return True return False - def ensure_bootstrapped(self, target=None, rustup_components=None): + def ensure_bootstrapped(self, rustup_components=None): if self.context.bootstrapped: return - target_platform = target or servo.platform.host_triple() - # Always check if all needed MSVC dependencies are installed + target_platform = self.cross_compile_target or servo.platform.host_triple() if "msvc" in target_platform: Registrar.dispatch("bootstrap", context=self.context) @@ -943,10 +996,13 @@ class CommandBase(object): if component.encode("utf-8") not in installed: check_call(["rustup", "component", "add", "--toolchain", toolchain, component]) - if target and "uwp" not in target and target.encode("utf-8") not in check_output( - ["rustup", "target", "list", "--installed", "--toolchain", toolchain] - ): - check_call(["rustup", "target", "add", "--toolchain", toolchain, target]) + needs_toolchain_install = self.cross_compile_target \ + and not self.is_uwp_build \ + and self.cross_compile_target.encode("utf-8") not in check_output( + ["rustup", "target", "list", "--installed", "--toolchain", toolchain] + ) + if needs_toolchain_install: + check_call(["rustup", "target", "add", "--toolchain", toolchain, self.cross_compile_target]) self.context.bootstrapped = True |