diff options
Diffstat (limited to 'build/moz.configure/rust.configure')
-rw-r--r-- | build/moz.configure/rust.configure | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/build/moz.configure/rust.configure b/build/moz.configure/rust.configure new file mode 100644 index 000000000..261768f64 --- /dev/null +++ b/build/moz.configure/rust.configure @@ -0,0 +1,166 @@ +# -*- 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/. + +option('--enable-rust', help='Include Rust language sources') + +@depends('--enable-rust') +def rust_compiler_names(value): + if value: + return ['rustc'] + +@depends('--enable-rust') +def cargo_binary_names(value): + if value: + return ['cargo'] + +rustc = check_prog('RUSTC', rust_compiler_names, allow_missing=True) +cargo = check_prog('CARGO', cargo_binary_names, 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 support for --frozen') +@imports('subprocess') +@imports('os') +def cargo_supports_frozen(cargo): + try: + lines = subprocess.check_output( + [cargo, 'help', 'build'] + ).splitlines() + supported = any(' --frozen' in l for l in lines) + if 'MOZ_AUTOMATION' in os.environ and not supported: + die('cargo in automation must support --frozen') + return supported + except subprocess.CalledProcessError as e: + die('Failed to call cargo: %s', e.message) + +set_config('MOZ_CARGO_SUPPORTS_FROZEN', cargo_supports_frozen) + +@depends('--enable-rust', rustc, rustc_info) +@imports(_from='textwrap', _import='dedent') +def rust_compiler(value, rustc, rustc_info): + if value: + if not rustc: + 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. + ''')) + version = rustc_info.version + min_version = Version('1.10') + if version < 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'. + '''.format(version, min_version))) + return True + +set_config('MOZ_RUST', rust_compiler) + +@depends(rust_compiler, rustc, target, cross_compiling) +@imports('os') +@imports('subprocess') +@imports(_from='mozbuild.configure.util', _import='LineIO') +@imports(_from='mozbuild.shellutil', _import='quote') +@imports(_from='tempfile', _import='mkstemp') +def rust_target(rust_compiler, rustc, target, cross_compiling): + if rust_compiler: + # 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/tree/master/mk/cfg + + # Avoid having to write out os+kernel for all the platforms where + # they don't differ. + os_or_kernel = target.kernel if target.kernel == 'Linux' and target.os != 'Android' else target.os + rustc_target = { + # DragonFly + ('x86_64', 'DragonFly'): 'x86_64-unknown-dragonfly', + # FreeBSD + ('x86', 'FreeBSD'): 'i686-unknown-freebsd', + ('x86_64', 'FreeBSD'): 'x86_64-unknown-freebsd', + # NetBSD + ('x86_64', 'NetBSD'): 'x86_64-unknown-netbsd', + # OpenBSD + ('x86_64', 'OpenBSD'): 'x86_64-unknown-openbsd', + # Linux + ('x86', 'Linux'): 'i586-unknown-linux-gnu', + # Linux + ('x86_64', 'Linux'): 'x86_64-unknown-linux-gnu', + # OS X and iOS + ('x86', 'OSX'): 'i686-apple-darwin', + ('x86', 'iOS'): 'i386-apple-ios', + ('x86_64', 'OSX'): 'x86_64-apple-darwin', + # Android + ('x86', 'Android'): 'i686-linux-android', + ('arm', 'Android'): 'armv7-linux-androideabi', + # Windows + # XXX better detection of CXX needed here, to figure out whether + # we need i686-pc-windows-gnu instead, since mingw32 builds work. + ('x86', 'WINNT'): 'i686-pc-windows-msvc', + ('x86_64', 'WINNT'): 'x86_64-pc-windows-msvc', + }.get((target.cpu, os_or_kernel), None) + + if rustc_target is None: + die("Don't know how to translate {} for rustc".format(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('Cannot compile for {} with {}'.format(target.alias, rustc)) + 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 + +set_config('RUST_TARGET', rust_target) + +# Until we remove all the other Rust checks in old-configure. +add_old_configure_assignment('MOZ_RUST', rust_compiler) +add_old_configure_assignment('RUSTC', rustc) +add_old_configure_assignment('RUST_TARGET', rust_target) |