build/moz.configure/rust.configure
author Jan Beich <jbeich@FreeBSD.org>
Fri, 08 Jul 2016 06:36:11 +0000
changeset 347577 a3dcf80115477a4cb54f3fd52597206f098187ab
parent 347381 df90dd14878675782247b176fd7f01bea0584206
child 348076 800fc65da8d3f7fc4f4f0a9a559e8747891a56a4
child 349358 643b03aae1dd2fec67f295fd56bcb5043288e3ae
permissions -rw-r--r--
Bug 1285503 - Fix DragonFly target spelling after bug 1266368. r=glandium, a=ritu MozReview-Commit-ID: 48qNqNa8CdP

# -*- 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']

rustc = check_prog('RUSTC', rust_compiler_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('--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.5')
        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'): 'i686-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'): 'arm-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:
            if cross_compiling:
                die("Don't know how to translate {} for rustc".format(target.alias))
            # Fall back to implicit (native) target when not cross-compiling
            return None

        # 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 target_arg

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)