mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-20 08:51:04 +00:00

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
258 lines
9.7 KiB
Python
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)))
|