gecko-dev/build/moz.configure/rust.configure
Ralph Giles 9681e0465c Bug 1408567 - Require Rust 1.20.0 or newer. r=nalexander
By the schedule we would have bumped the minimum-supported rust
version to 1.20.0 some weeks ago, just before Firefox 57 went to
beta. However, that was blocked on a couple of compatibility
issues with sccache and dsymutil. See bug 1396884.

Now that 1.20.0 is working in our automation builds, require
it for all builds to unblock servo and webrender upgrades.

Also update our integration test to verify building with
the new minimum.

MozReview-Commit-ID: 8otdix6f45f

--HG--
extra : rebase_source : 7d2550e8ddc772b45602bd488f174fc180e91484
2017-10-13 15:08:21 -07:00

258 lines
9.7 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.20.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
@depends(rustc, when=rust_compiler)
def rust_supported_targets(rustc):
out = check_cmd_output(rustc, '--print', 'target-list').splitlines()
# The os in the triplets used by rust may match the same OSes, in which
# case we need to check the raw_os instead.
per_os = {}
ambiguous = set()
per_raw_os = {}
for t in out:
t = split_triplet(t, allow_unknown=True)
key = (t.cpu, t.endianness, t.os)
if key in per_os:
previous = per_os[key]
per_raw_os[(previous.cpu, previous.endianness,
previous.raw_os)] = previous
del per_os[key]
ambiguous.add(key)
if key in ambiguous:
raw_os = t.raw_os
# split_triplet will return a raw_os of 'androideabi' for
# rust targets in the form cpu-linux-androideabi, but what
# we get from the build system is linux-androideabi, so
# normalize.
if raw_os == 'androideabi':
raw_os = 'linux-androideabi'
per_raw_os[(t.cpu, t.endianness, raw_os)] = t
else:
per_os[key] = t
return namespace(per_os=per_os, per_raw_os=per_raw_os)
@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, rust_supported_targets,
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_supported_targets):
# 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.
# We correlate the autoconf-derived targets with the list of targets
# rustc gives us with --print target-list.
if host_or_target.kernel == 'WINNT':
if building_with_gcc:
host_or_target_os = 'windows-gnu'
else:
host_or_target_os = 'windows-msvc'
host_or_target_raw_os = host_or_target_os
else:
host_or_target_os = host_or_target.os
host_or_target_raw_os = host_or_target.raw_os
rustc_target = rust_supported_targets.per_os.get(
(host_or_target.cpu, host_or_target.endianness, host_or_target_os))
if rustc_target is None:
rustc_target = rust_supported_targets.per_raw_os.get(
(host_or_target.cpu, host_or_target.endianness,
host_or_target_raw_os))
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.alias
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.alias)))
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.alias
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)
# This option is separate from --enable-tests because Rust tests are particularly
# expensive in terms of compile time (especially for code in libxul).
option('--enable-rust-tests',
help='Enable building of Rust tests, and build-time execution of them')
set_config('MOZ_RUST_TESTS', depends('--enable-rust-tests')(lambda v: bool(v)))