gecko-dev/build/moz.configure/rust.configure

243 строки
9.8 KiB
Python

# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
# Rust is required by `rust_compiler` below. We allow_missing here
# to propagate failures to the better error message there.
rustc = check_prog('RUSTC', ['rustc'], allow_missing=True)
cargo = check_prog('CARGO', ['cargo'], allow_missing=True)
@depends_if(rustc)
@checking('rustc version', lambda info: info.version)
def rustc_info(rustc):
out = check_cmd_output(rustc, '--version', '--verbose').splitlines()
info = dict((s.strip() for s in line.split(':', 1)) for line in out[1:])
return namespace(
version=Version(info.get('release', '0')),
commit=info.get('commit-hash', 'unknown'),
)
@depends_if(cargo)
@checking('cargo version', lambda info: info.version)
@imports('re')
def cargo_info(cargo):
out = check_cmd_output(cargo, '--version', '--verbose').splitlines()
info = dict((s.strip() for s in line.split(':', 1)) for line in out[1:])
version = info.get('release')
# Older versions of cargo didn't support --verbose, in which case, they
# only output a not-really-pleasant-to-parse output. Fortunately, they
# don't error out, so we can just try some regexp matching on the output
# we already got.
if version is None:
VERSION_FORMAT = r'^cargo (\d\.\d+\.\d+).*'
m = re.search(VERSION_FORMAT, out[0])
# Fail fast if cargo changes its output on us.
if not m:
die('Could not determine cargo version from output: %s', out)
version = m.group(1)
return namespace(
version=Version(version),
)
@depends(rustc_info, cargo_info)
@imports(_from='textwrap', _import='dedent')
def rust_compiler(rustc_info, cargo_info):
if not rustc_info:
die(dedent('''\
Rust compiler not found.
To compile rust language sources, you must have 'rustc' in your path.
See https://www.rust-lang.org/ for more information.
You can install rust by running './mach bootstrap'
or by directly running the installer from https://rustup.rs/
'''))
rustc_min_version = Version('1.19.0')
cargo_min_version = Version('0.{}'.format(rustc_min_version.minor + 1))
version = rustc_info.version
if version < rustc_min_version:
die(dedent('''\
Rust compiler {} is too old.
To compile Rust language sources please install at least
version {} of the 'rustc' toolchain and make sure it is
first in your path.
You can verify this by typing 'rustc --version'.
If you have the 'rustup' tool installed you can upgrade
to the latest release by typing 'rustup update'. The
installer is available from https://rustup.rs/
'''.format(version, rustc_min_version)))
if not cargo_info:
die(dedent('''\
Cargo package manager not found.
To compile Rust language sources, you must have 'cargo' in your path.
See https://www.rust-lang.org/ for more information.
You can install cargo by running './mach bootstrap'
or by directly running the installer from https://rustup.rs/
'''))
version = cargo_info.version
if version < cargo_min_version:
die(dedent('''\
Cargo package manager {} is too old.
To compile Rust language sources please install at least
version {} of 'cargo' and make sure it is first in your path.
You can verify this by typing 'cargo --version'.
''').format(version, cargo_min_version))
return True
@template
def rust_triple_alias(host_or_target):
"""Template defining the alias used for rustc's --target flag.
`host_or_target` is either `host` or `target` (the @depends functions
from init.configure).
"""
assert host_or_target in (host, target)
@depends(rustc, host_or_target, building_with_gcc, when=rust_compiler)
@imports('os')
@imports('subprocess')
@imports(_from='mozbuild.configure.util', _import='LineIO')
@imports(_from='mozbuild.shellutil', _import='quote')
@imports(_from='tempfile', _import='mkstemp')
@imports(_from='textwrap', _import='dedent')
def rust_target(rustc, host_or_target, building_with_gcc):
# Rust's --target options are similar to, but not exactly the same
# as, the autoconf-derived targets we use. An example would be that
# Rust uses distinct target triples for targetting the GNU C++ ABI
# and the MSVC C++ ABI on Win32, whereas autoconf has a single
# triple and relies on the user to ensure that everything is
# compiled for the appropriate ABI. We need to perform appropriate
# munging to get the correct option to rustc.
#
# The canonical list of targets supported can be derived from:
#
# https://github.com/rust-lang/rust/blob/master/src/librustc_back/target/mod.rs
# Avoid having to write out os+kernel for all the platforms where
# they don't differ.
os_or_kernel = host_or_target.kernel if host_or_target.kernel == 'Linux' and host_or_target.os != 'Android' else host_or_target.os
# If we are targetting Windows but the compiler is gcc, we need to
# use a different rustc target
os_or_kernel = 'WINNT-MINGW' if building_with_gcc and host_or_target.kernel == 'WINNT' else os_or_kernel
rustc_target = {
# DragonFly
('x86_64', 'DragonFly'): 'x86_64-unknown-dragonfly',
# FreeBSD
('aarch64', 'FreeBSD'): 'aarch64-unknown-freebsd',
('x86', 'FreeBSD'): 'i686-unknown-freebsd',
('x86_64', 'FreeBSD'): 'x86_64-unknown-freebsd',
# NetBSD
('sparc64', 'NetBSD'): 'sparc64-unknown-netbsd',
('x86', 'NetBSD'): 'i686-unknown-netbsd',
('x86_64', 'NetBSD'): 'x86_64-unknown-netbsd',
# OpenBSD
('x86', 'OpenBSD'): 'i686-unknown-openbsd',
('x86_64', 'OpenBSD'): 'x86_64-unknown-openbsd',
# Linux
('aarch64', 'Linux'): 'aarch64-unknown-linux-gnu',
('arm', 'Linux'): 'armv7-unknown-linux-gnueabihf',
('sparc64', 'Linux'): 'sparc64-unknown-linux-gnu',
('x86', 'Linux'): 'i686-unknown-linux-gnu',
('x86_64', 'Linux'): 'x86_64-unknown-linux-gnu',
# OS X
('x86', 'OSX'): 'i686-apple-darwin',
('x86_64', 'OSX'): 'x86_64-apple-darwin',
# iOS
('aarch64', 'iOS'): 'aarch64-apple-ios',
('arm', 'iOS'): 'armv7s-apple-ios',
('x86', 'iOS'): 'i386-apple-ios',
('x86_64', 'iOS'): 'x86_64-apple-ios',
# Android
('aarch64', 'Android'): 'aarch64-linux-android',
('arm', 'Android'): 'armv7-linux-androideabi',
('x86', 'Android'): 'i686-linux-android',
('x86_64', 'Android'): 'x86_64-linux-android',
# Windows
('x86', 'WINNT'): 'i686-pc-windows-msvc',
('x86_64', 'WINNT'): 'x86_64-pc-windows-msvc',
('x86', 'WINNT-MINGW'): 'i686-pc-windows-gnu',
('x86_64', 'WINNT-MINGW'): 'x86_64-pc-windows-gnu',
# Solaris
('x86_64', 'SunOS'): 'x86_64-sun-solaris',
('sparc64', 'SunOS'): 'sparcv9-sun-solaris',
}.get((host_or_target.cpu, os_or_kernel), None)
if rustc_target is None:
die("Don't know how to translate {} for rustc".format(host_or_target.alias))
# Check to see whether our rustc has a reasonably functional stdlib
# for our chosen target.
target_arg = '--target=' + rustc_target
in_fd, in_path = mkstemp(prefix='conftest', suffix='.rs')
out_fd, out_path = mkstemp(prefix='conftest', suffix='.rlib')
os.close(out_fd)
try:
source = 'pub extern fn hello() { println!("Hello world"); }'
log.debug('Creating `%s` with content:', in_path)
with LineIO(lambda l: log.debug('| %s', l)) as out:
out.write(source)
os.write(in_fd, source)
os.close(in_fd)
cmd = [
rustc,
'--crate-type', 'staticlib',
target_arg,
'-o', out_path,
in_path,
]
def failed():
die(dedent('''\
Cannot compile for {} with {}
The target may be unsupported, or you may not have
a rust std library for that target installed. Try:
rustup target add {}
'''.format(host_or_target.alias, rustc, rustc_target)))
check_cmd_output(*cmd, onerror=failed)
if not os.path.exists(out_path) or os.path.getsize(out_path) == 0:
failed()
finally:
os.remove(in_path)
os.remove(out_path)
# This target is usable.
return rustc_target
return rust_target
rust_target_triple = rust_triple_alias(target)
rust_host_triple = rust_triple_alias(host)
set_config('RUST_TARGET', rust_target_triple)
set_config('RUST_HOST_TARGET', rust_host_triple)
@depends(rust_target_triple)
def rust_target_env_name(triple):
return triple.upper().replace('-','_')
# We need this to form various Cargo environment variables, as there is no
# uppercase function in make, and we don't want to shell out just for
# converting a string to uppercase.
set_config('RUST_TARGET_ENV_NAME', rust_target_env_name)
# This is used for putting source info into symbol files.
set_config('RUSTC_COMMIT', depends(rustc_info)(lambda i: i.commit))
# Until we remove all the other Rust checks in old-configure.
add_old_configure_assignment('RUSTC', rustc)
add_old_configure_assignment('RUST_TARGET', rust_target_triple)