toolkit/moz.configure
author Mike Hommey <mh+mozilla@glandium.org>
Fri, 11 Jan 2019 22:21:24 +0000
changeset 453569 e69490bbd056
parent 453422 02cd44e39566
child 453571 8bac283f6c7e
permissions -rw-r--r--
Bug 1519325 - Move D3D compiler DLL detection to python configure. r=froydnj MOZ_D3D_CPU_SUFFIX and MOZ_HAS_WINSDK_WITH_D3D are not used in the build, and nothing includes d3d10.h except some angle code in a preprocessed branch that is only taken for a macro we never define, so we don't move the code corresponding to those. We also simplify the detection code, which is convoluted now that it doesn't search for multiple different DLLs. Differential Revision: https://phabricator.services.mozilla.com/D16295

# -*- 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/.


# Profiling
# ==============================================================
# Some of the options here imply an option from js/moz.configure,
# so, need to be declared before the include.

option('--enable-jprof', env='MOZ_JPROF',
       help='Enable jprof profiling tool (needs mozilla/tools/jprof)')

@depends('--enable-jprof')
def jprof(value):
    if value:
        return True

set_config('MOZ_JPROF', jprof)
set_define('MOZ_JPROF', jprof)
imply_option('--enable-profiling', jprof)

@depends(target)
def gecko_profiler(target):
    if target.os == 'Android':
        return target.cpu in ('aarch64', 'arm', 'x86', 'x86_64')
    elif target.kernel == 'Linux':
        return target.cpu in ('aarch64', 'arm', 'x86', 'x86_64', 'mips64')
    return target.os in ('OSX', 'WINNT')

@depends(gecko_profiler)
def gecko_profiler_define(value):
    if value:
        return True

set_config('MOZ_GECKO_PROFILER', gecko_profiler_define)
set_define('MOZ_GECKO_PROFILER', gecko_profiler_define)


# Whether code to parse ELF binaries should be compiled for the Gecko profiler
# (for symbol table dumping).
@depends(gecko_profiler, target)
def gecko_profiler_parse_elf(value, target):
    # Currently we only want to build this code on Android, in order to dump
    # symbols from Android system libraries on the device. For other platforms
    # there exist alternatives that don't require bloating up our binary size.
    if value and target.os == 'Android':
        return True

set_config('MOZ_GECKO_PROFILER_PARSE_ELF', gecko_profiler_parse_elf)
set_define('MOZ_GECKO_PROFILER_PARSE_ELF', gecko_profiler_parse_elf)

# enable this by default if the profiler is enabled
# Note: also requires jemalloc
set_config('MOZ_PROFILER_MEMORY', gecko_profiler_define)
set_define('MOZ_PROFILER_MEMORY', gecko_profiler_define)

option('--enable-dmd', env='MOZ_DMD',
       help='Enable Dark Matter Detector (heap profiler). '
            'Also enables jemalloc, replace-malloc and profiling')

@depends('--enable-dmd')
def dmd(value):
    if value:
        return True

set_config('MOZ_DMD', dmd)
set_define('MOZ_DMD', dmd)
add_old_configure_assignment('MOZ_DMD', dmd)
imply_option('--enable-profiling', dmd)
imply_option('--enable-jemalloc', dmd)
imply_option('--enable-replace-malloc', dmd)

# ALSA cubeb backend
# ==============================================================
option('--enable-alsa', env='MOZ_ALSA',
       help='Enable ALSA audio backend.')

alsa = pkg_check_modules('MOZ_ALSA', 'alsa', when='--enable-alsa')

set_config('MOZ_ALSA', depends_if(alsa)(lambda _: True))
set_define('MOZ_ALSA', depends_if(alsa)(lambda _: True))

# JACK cubeb backend
# ==============================================================
option('--enable-jack', env='MOZ_JACK',
       help='Enable JACK audio backend.')

jack = pkg_check_modules('MOZ_JACK', 'jack', when='--enable-jack')

set_config('MOZ_JACK', depends_if(jack)(lambda _: True))
set_define('MOZ_JACK', depends_if(jack)(lambda _: True))

# PulseAudio cubeb backend
# ==============================================================
@depends(target)
def pulseaudio_default(target):
    return target.os not in ('WINNT', 'OSX', 'iOS', 'Android', 'OpenBSD')

option('--enable-pulseaudio', env='MOZ_PULSEAUDIO', default=pulseaudio_default,
       help='{Enable|Disable} PulseAudio audio backend.')

pulseaudio = pkg_check_modules('MOZ_PULSEAUDIO', 'libpulse', when='--enable-pulseaudio')

set_config('MOZ_PULSEAUDIO', depends_if(pulseaudio)(lambda _: True))
set_define('MOZ_PULSEAUDIO', depends_if(pulseaudio)(lambda _: True))

# Javascript engine
# ==============================================================
include('../js/moz.configure')


# NodeJS
# ==============================================================
include('../build/moz.configure/node.configure')

# L10N
# ==============================================================
option('--with-l10n-base', nargs=1, env='L10NBASEDIR',
       help='Path to l10n repositories')

@depends('--with-l10n-base', 'MOZ_AUTOMATION', target, check_build_environment)
@imports(_from='os.path', _import='isdir')
@imports(_from='os.path', _import='expanduser')
@imports(_from='os', _import='environ')
def l10n_base(value, automation, target, build_env):
    if value:
        path = value[0]
        if not isdir(path):
            die("Invalid value --with-l10n-base, %s doesn't exist", path)
    elif automation:
        if target.os == 'Android':
            path = os.path.join(build_env.topobjdir, '..', '..', 'l10n-central')
        else:
            path = os.path.join(build_env.topobjdir, '..', '..', 'l10n')
    else:
        path = os.path.join(
            environ.get(
                'MOZBUILD_STATE_PATH',
                expanduser(os.path.join('~', '.mozbuild'))),
            'l10n-central')
    return os.path.realpath(os.path.abspath(path))

set_config('L10NBASEDIR', l10n_base)


# Default toolkit
# ==============================================================
# Normally, we'd want to use the `default` field on the option, but that
# requires --target to be resolved at --help time, which requires to run
# config.guess, which we want to avoid. Even better, we could actually set
# `choices` depending on the target, but that doesn't pan out for the same
# reason.
option('--enable-default-toolkit', nargs=1,
       choices=('cairo-windows', 'cairo-gtk3', 'cairo-gtk3-wayland',
                'cairo-cocoa', 'cairo-uikit', 'cairo-android'),
       help='Select default toolkit')

@depends('--enable-default-toolkit', target, '--help')
def full_toolkit(value, target, _):
    # Define possible choices for each platform. The default is the first one
    # listed when there are several.
    if target.os == 'WINNT':
        platform_choices = ('cairo-windows',)
    elif target.os == 'OSX':
        platform_choices = ('cairo-cocoa',)
    elif target.os == 'iOS':
        platform_choices = ('cairo-uikit',)
    elif target.os == 'Android':
        platform_choices = ('cairo-android',)
    else:
        platform_choices = ('cairo-gtk3', 'cairo-gtk3-wayland')

    if value:
        if value[0] not in platform_choices:
            die('`%s` is not a valid value for --enable-default-toolkit on %s\n'
                'Valid values: %s', value[0], target.os,
                ', '.join(platform_choices))
        return value[0]

    return platform_choices[0]

@depends(full_toolkit)
def toolkit(toolkit):
    if toolkit == 'cairo-gtk3-wayland':
        widget_toolkit = 'gtk3'
    else:
        widget_toolkit = toolkit.replace('cairo-', '')
    return widget_toolkit

set_config('MOZ_WIDGET_TOOLKIT', toolkit)
add_old_configure_assignment('MOZ_WIDGET_TOOLKIT', toolkit)

@depends(toolkit)
def toolkit_define(toolkit):
    if toolkit == 'gtk3':
        toolkit = 'gtk'
    if toolkit != 'windows':
        return 'MOZ_WIDGET_%s' % toolkit.upper()

set_define(toolkit_define, True)

@depends(toolkit)
def toolkit_gtk(toolkit):
    return toolkit == 'gtk3'

set_config('MOZ_X11', True, when=toolkit_gtk)
set_define('MOZ_X11', True, when=toolkit_gtk)
add_old_configure_assignment('MOZ_X11', True, when=toolkit_gtk)

# Wayland support
# ==============================================================
wayland_headers = pkg_check_modules(
    'MOZ_WAYLAND', 'gtk+-wayland-3.0 >= 3.10 xkbcommon >= 0.4.1',
    allow_missing=depends(full_toolkit)(lambda t: t == 'cairo-gtk3'),
    when=depends(full_toolkit)(lambda t: t in ('cairo-gtk3', 'cairo-gtk3-wayland')))


@depends(wayland_headers, toolkit_gtk, artifact_builds)
def wayland_headers(wayland, toolkit_gtk, artifacts):
    if toolkit_gtk and artifacts:
        return True
    return wayland


set_config('MOZ_WAYLAND', depends_if(wayland_headers)(lambda _: True))
set_define('MOZ_WAYLAND', depends_if(wayland_headers)(lambda _: True))

# GL Provider
# ==============================================================
option('--with-gl-provider', nargs=1, help='Set GL provider backend type')

@depends('--with-gl-provider')
def gl_provider(value):
    if value:
        return value[0]

@depends(gl_provider)
def gl_provider_define(provider):
    if provider:
        return 'GLContextProvider%s' % provider

set_define('MOZ_GL_PROVIDER', gl_provider_define)

@depends(gl_provider, wayland_headers, toolkit_gtk)
def gl_default_provider(value, wayland, toolkit_gtk):
    if value:
        return value
    elif wayland:
        return 'EGL'
    elif toolkit_gtk:
        return 'GLX'

set_config('MOZ_GL_PROVIDER', gl_provider)
set_config('MOZ_GL_DEFAULT_PROVIDER', gl_default_provider)

@depends(gl_default_provider)
def gl_provider_define(provider):
    if provider:
        return 'GL_PROVIDER_%s' % provider

set_define(gl_provider_define, True)


# PDF printing
# ==============================================================
@depends(toolkit)
def pdf_printing(toolkit):
    if toolkit in ('windows', 'gtk3', 'android'):
        return True

@depends(pdf_printing)
def pdf_surface_feature(pdf_printing):
    if pdf_printing:
        return '#define CAIRO_HAS_PDF_SURFACE 1'
    else:
        # CONFIGURE_SUBST_FILES need explicit empty values.
        return ''

set_config('MOZ_PDF_PRINTING', pdf_printing)
set_config('PDF_SURFACE_FEATURE', pdf_surface_feature)


# Event loop instrumentation
# ==============================================================
option(env='MOZ_INSTRUMENT_EVENT_LOOP',
       help='Force-enable event loop instrumentation')

@depends('MOZ_INSTRUMENT_EVENT_LOOP', toolkit)
def instrument_event_loop(value, toolkit):
    if value or (toolkit in ('windows', 'gtk3', 'cocoa', 'android') and
                 value.origin == 'default'):
        return True

set_config('MOZ_INSTRUMENT_EVENT_LOOP', instrument_event_loop)
set_define('MOZ_INSTRUMENT_EVENT_LOOP', instrument_event_loop)


# Fontconfig Freetype
# ==============================================================
option(env='USE_FC_FREETYPE',
       help='Force-enable the use of fontconfig freetype')

@depends('USE_FC_FREETYPE', toolkit)
def fc_freetype(value, toolkit):
    if value or (toolkit == 'gtk3' and
                 value.origin == 'default'):
        return True

add_old_configure_assignment('USE_FC_FREETYPE', fc_freetype)

# Pango
# ==============================================================
pkg_check_modules('MOZ_PANGO',
                  'pango >= 1.22.0 pangoft2 >= 1.22.0 pangocairo >= 1.22.0',
                  when=toolkit_gtk)

# Fontconfig
# ==============================================================
fontconfig_info = pkg_check_modules('_FONTCONFIG', 'fontconfig >= 2.7.0',
                                    when=fc_freetype)

@depends(fc_freetype)
def check_for_freetype2(fc_freetype):
    if fc_freetype:
        return True

# Check for freetype2. Flags are combined with fontconfig flags.
freetype2_info = pkg_check_modules('_FT2', 'freetype2 >= 6.1.0',
                                   when=check_for_freetype2)

@depends(fontconfig_info, freetype2_info)
def freetype2_combined_info(fontconfig_info, freetype2_info):
    if not freetype2_info:
        return
    if not fontconfig_info:
        return freetype2_info
    return namespace(
        cflags=freetype2_info.cflags + fontconfig_info.cflags,
        libs=freetype2_info.libs + fontconfig_info.libs,
    )

add_old_configure_assignment('_HAVE_FREETYPE2',
                             depends_if(freetype2_info)(lambda _: True))

# Apple platform decoder support
# ==============================================================
@depends(toolkit)
def applemedia(toolkit):
    if toolkit in ('cocoa', 'uikit'):
        return True

set_config('MOZ_APPLEMEDIA', applemedia)
set_define('MOZ_APPLEMEDIA', applemedia)
add_old_configure_assignment('MOZ_APPLEMEDIA', applemedia)

# Windows Media Foundation support
# ==============================================================
option('--disable-wmf',
       help='Disable support for Windows Media Foundation')

@depends('--disable-wmf', target)
def wmf(value, target):
    enabled = bool(value)
    if value.origin == 'default':
        # Enable Windows Media Foundation support by default.
        # Note our minimum SDK version is Windows 7 SDK, so we are (currently)
        # guaranteed to have a recent-enough SDK to build WMF.
        enabled = target.os == 'WINNT'
    if enabled and target.os != 'WINNT':
        die('Cannot enable Windows Media Foundation support on %s', target.os)
    if enabled:
        return True

set_config('MOZ_WMF', wmf)
set_define('MOZ_WMF', wmf)

# FFmpeg H264/AAC Decoding Support
# ==============================================================
option('--disable-ffmpeg',
       help='Disable FFmpeg for fragmented H264/AAC decoding')

@depends('--disable-ffmpeg', target)
def ffmpeg(value, target):
    enabled = bool(value)
    if value.origin == 'default':
        enabled = target.os not in ('Android', 'WINNT')
    if enabled:
        return True

set_config('MOZ_FFMPEG', ffmpeg)
set_define('MOZ_FFMPEG', ffmpeg)
imply_option('--enable-fmp4', ffmpeg, '--enable-ffmpeg')

# Libaom AV1 Video Codec Support
# ==============================================================
option('--enable-av1',
        help='Enable libaom for av1 video support')

@depends('--enable-av1', target)
def av1(value, target):
    enabled = bool(value)
    if value.origin == 'default':
        if target.os == 'WINNT' and target.cpu == 'x86':
            enabled = False
        else:
            enabled = True
    if enabled:
        return True

set_config('MOZ_AV1', av1)
set_define('MOZ_AV1', av1)

# Built-in fragmented MP4 support.
# ==============================================================
option('--disable-fmp4', env='MOZ_FMP4',
       help='Disable support for in built Fragmented MP4 parsing')

@depends('--disable-fmp4', target, wmf, applemedia)
def fmp4(value, target, wmf, applemedia):
    enabled = bool(value)
    if value.origin == 'default':
        # target.os == 'Android' includes all B2G versions
        enabled = wmf or applemedia or target.os == 'Android'
    if enabled:
        return True

set_config('MOZ_FMP4', fmp4)
set_define('MOZ_FMP4', fmp4)
add_old_configure_assignment('MOZ_FMP4', fmp4)

@depends(target)
def sample_type_is_s16(target):
    # Use integers over floats for audio on Android regardless of the CPU
    # architecture, because audio backends for Android don't support floats.
    # We also use integers on ARM because it's more efficient.
    if target.os == 'Android' or target.cpu == 'arm':
        return True

@depends(sample_type_is_s16)
def sample_type_is_float(t):
    if not t:
        return True

set_config('MOZ_SAMPLE_TYPE_S16', sample_type_is_s16)
set_define('MOZ_SAMPLE_TYPE_S16', sample_type_is_s16)
set_config('MOZ_SAMPLE_TYPE_FLOAT32', sample_type_is_float)
set_define('MOZ_SAMPLE_TYPE_FLOAT32', sample_type_is_float)

set_define('MOZ_VORBIS', sample_type_is_float)
set_config('MOZ_VORBIS', sample_type_is_float)
set_define('MOZ_TREMOR', sample_type_is_s16)
set_config('MOZ_TREMOR', sample_type_is_s16)

# OpenMAX IL Decoding Support
# ==============================================================
option('--enable-openmax',
       help='Enable OpenMAX IL for video/audio decoding')

@depends('--enable-openmax')
def openmax(value):
    enabled = bool(value)
    if enabled:
        return True

set_config('MOZ_OMX', openmax)
set_define('MOZ_OMX', openmax)

# EME Support
# ==============================================================
# Widevine is enabled by default in desktop browser builds.
@depends(build_project)
def eme_default(build_project):
    if build_project == 'browser':
        return 'widevine'

option('--enable-eme',
       nargs='*',
       choices=('widevine',),
       default=eme_default,
       help='{Enable|Disable} support for Encrypted Media Extensions')

@depends('--enable-eme', target)
def enable_eme(value, target):
    # Widevine EME by default enabled on desktop Windows, MacOS and Linux,
    # x86 and x64 builds.
    if (target.kernel in ('Darwin', 'WINNT', 'Linux') and
        target.os not in ('Android', 'iOS') and
        target.cpu in ('x86', 'x86_64')):
        return value
    elif value and value.origin != 'default':
        die('%s is not supported on %s' % (value.format('--enable-eme'), target.alias))
    # Return the same type of OptionValue (Positive or Negative), with an empty tuple.
    return value.__class__(())

@depends(enable_eme, fmp4)
def eme(value, fmp4):
    enabled = bool(value)
    if value.origin == 'default':
        enabled = enabled or fmp4
    if enabled and not fmp4:
        die('Encrypted Media Extension support requires '
            'Fragmented MP4 support')
    if enabled:
        return True

@depends(enable_eme)
def eme_modules(value):
    return value

set_config('MOZ_EME_MODULES', eme_modules)

option(name='--enable-chrome-format',
       help='Select FORMAT of chrome files during packaging.',
       nargs=1,
       choices=('omni', 'jar', 'flat'),
       default='omni')

@depends('--enable-chrome-format')
def packager_format(value):
    return value[0]

set_config('MOZ_PACKAGER_FORMAT', packager_format)

@depends(host, build_project)
def jar_maker_format(host, build_project):
    # Multilocales for mobile/android use the same mergedirs for all locales,
    # so we can't use symlinks for those builds.
    if host.os == 'WINNT' or build_project == 'mobile/android':
        return 'flat'
    return 'symlink'

set_config('MOZ_JAR_MAKER_FILE_FORMAT', jar_maker_format)

@depends(toolkit)
def omnijar_name(toolkit):
    # Fennec's static resources live in the assets/ folder of the
    # APK.  Adding a path to the name here works because we only
    # have one omnijar file in the final package (which is not the
    # case on desktop), and necessitates some contortions during
    # packaging so that the resources in the omnijar are considered
    # as rooted at / and not as rooted at assets/ (which again is
    # not the case on desktop: there are omnijars rooted at webrtc/,
    # etc). packager.mk handles changing the rooting of the single
    # omnijar.
    return 'assets/omni.ja' if toolkit == 'android' else 'omni.ja'

set_config('OMNIJAR_NAME', omnijar_name)

project_flag('MOZ_PLACES',
             help='Build Places if required',
             set_as_define=True)

project_flag('MOZ_SERVICES_HEALTHREPORT',
             help='Build Firefox Health Reporter Service',
             set_for_old_configure=True,
             set_as_define=True)

project_flag('MOZ_SERVICES_SYNC',
             help='Build Sync Services if required')

project_flag('MOZ_ANDROID_HISTORY',
             help='Enable Android History instead of Places',
             set_as_define=True)

project_flag('MOZ_DEDICATED_PROFILES',
             help='Enable dedicated profiles per install',
             set_as_define=True)

project_flag('MOZ_BLOCK_PROFILE_DOWNGRADE',
             help='Block users from starting profiles last used by a newer build',
             set_as_define=True)

option(env='MOZ_ALLOW_LEGACY_EXTENSIONS',
       default=milestone.is_nightly,
       help='Allow legacy browser extensions')

@depends('MOZ_ALLOW_LEGACY_EXTENSIONS')
def legacy_extensions(value):
    if bool(value):
        return True

set_config('MOZ_ALLOW_LEGACY_EXTENSIONS', legacy_extensions)
set_define('MOZ_ALLOW_LEGACY_EXTENSIONS', legacy_extensions)

@depends('MOZ_PLACES', 'MOZ_ANDROID_HISTORY')
def check_places_and_android_history(places, android_history):
    if places and android_history:
        die('Cannot use MOZ_ANDROID_HISTORY alongside MOZ_PLACES.')

# gpsd support
# ==============================================================
option('--enable-gpsd', env='MOZ_GPSD',
       help='Enable gpsd support')

@depends('--enable-gpsd')
def gpsd(value):
    return bool(value)

system_gpsd = pkg_check_modules('MOZ_GPSD', 'libgps >= 3.11',
                                when=gpsd)

set_config('MOZ_GPSD', depends_if(system_gpsd)(lambda _: True))

# Miscellaneous programs
# ==============================================================

check_prog('TAR', ('gnutar', 'gtar', 'tar'))
check_prog('UNZIP', ('unzip',))
check_prog('ZIP', ('zip',))
check_prog('GN', ('gn',), allow_missing=True)

# Key files
# ==============================================================
include('../build/moz.configure/keyfiles.configure')

simple_keyfile('Mozilla API')

simple_keyfile('Google API')

id_and_secret_keyfile('Bing API')

simple_keyfile('Adjust SDK')

id_and_secret_keyfile('Leanplum SDK')

simple_keyfile('Pocket API')


# WebRender integration
# ==============================================================

option('--enable-webrender', nargs='?', choices=('build',),
       help='Include WebRender in the build and/or enable it at runtime')

@depends('--enable-webrender')
def webrender(value):
    build_webrender = None
    enable_webrender = None

    if value.origin == 'default':
        # if nothing is specified, default to building
        build_webrender = True
    elif len(value) and value[0] == 'build':
        # if explicitly set to 'build', then we build but don't enable
        build_webrender = True
    elif bool(value):
        # if set to true, then build and enable
        build_webrender = True
        enable_webrender = True

    # in all other cases, don't build it or enable it (defaults are fine)
    return namespace(
        build = build_webrender,
        enable = enable_webrender,
    )

set_config('MOZ_BUILD_WEBRENDER', webrender.build)
set_define('MOZ_BUILD_WEBRENDER', webrender.build)
set_config('MOZ_ENABLE_WEBRENDER', webrender.enable)

# SIMD acceleration for Rust code (currently just encoding_rs)
# ==============================================================

option('--enable-rust-simd', env='MOZ_RUST_SIMD',
       help='Enable explicit SIMD in Rust code.')

@depends('--enable-rust-simd', target)
def rust_simd(value, target):
    # As of 2018-06-05, the simd crate only works on aarch64,
    # armv7, x86 and x86_64.
    if target.cpu in ('aarch64', 'arm', 'x86', 'x86_64') and value:
        return True

set_config('MOZ_RUST_SIMD', rust_simd)
set_define('MOZ_RUST_SIMD', rust_simd)

# Printing
# ==============================================================
@depends(target)
def ios_disable_printing(target):
    if target.os == 'iOS':
        return False

imply_option('--enable-printing', ios_disable_printing, reason='--target')

option('--disable-printing', help='Disable printing support')

@depends('--disable-printing')
def printing(value):
    if value:
        return True

set_config('NS_PRINTING', printing)
set_define('NS_PRINTING', printing)
set_define('NS_PRINT_PREVIEW', printing)

# Speech-dispatcher support
# ==============================================================
@depends(toolkit)
def no_speechd_on_non_gtk(toolkit):
    if toolkit != 'gtk3':
        return False

imply_option('--enable-synth-speechd', no_speechd_on_non_gtk,
             reason='--enable-default-toolkit')

option('--disable-synth-speechd', help='Disable speech-dispatcher support')

set_config('MOZ_SYNTH_SPEECHD',
           depends_if('--disable-synth-speechd')(lambda _: True))

# Speech API
# ==============================================================
option('--disable-webspeech', help='Disable support for HTML Speech API')

@depends('--disable-webspeech')
def webspeech(value):
    if value:
        return True

set_config('MOZ_WEBSPEECH', webspeech)
set_define('MOZ_WEBSPEECH', webspeech)
add_old_configure_assignment('MOZ_WEBSPEECH', webspeech)

# Speech API test backend
# ==============================================================
option('--enable-webspeechtestbackend', default=webspeech,
       help='{Enable|Disable} support for HTML Speech API Test Backend')

@depends_if('--enable-webspeechtestbackend')
def webspeech_test_backend(value):
    return True

set_config('MOZ_WEBSPEECH_TEST_BACKEND', webspeech_test_backend)
set_define('MOZ_WEBSPEECH_TEST_BACKEND', webspeech_test_backend)

# Enable IPDL's "expensive" unit tests
# ==============================================================
option('--enable-ipdl-tests', help='Enable expensive IPDL tests')

set_config('MOZ_IPDL_TESTS',
           depends_if('--enable-ipdl-tests')(lambda _: True))

include('nss.configure')

# Graphics
# ==============================================================
option('--disable-skia', help='Disable use of Skia')

@depends('--disable-skia')
def skia(value):
    if not value:
        die('--disable-skia is not supported anymore')
    else:
        return True

set_config('MOZ_ENABLE_SKIA', skia)
set_define('MOZ_ENABLE_SKIA', skia)
set_define('USE_SKIA', skia)

@depends(skia, target)
def skia_android(skia, target):
    if skia and target.os == 'Android':
        return True

set_define('SK_BUILD_FOR_ANDROID_NDK', skia_android)

option('--disable-skia-gpu', help='Disable use of Skia-GPU')

@depends('--disable-skia-gpu', skia)
def skia_gpu(value, skia):
    if value.origin == 'default':
        if not skia:
            return None
    elif value and not skia:
        die('Cannot enable Skia-GPU without enabling Skia')
    if skia and value:
        return True

set_config('MOZ_ENABLE_SKIA_GPU', skia_gpu)
set_define('USE_SKIA_GPU', skia_gpu)

option('--enable-skia-pdf', help='Enable Skia PDF')

@depends('--enable-skia-pdf', skia, target, milestone)
def skia_pdf(value, skia, target, milestone):
    if value.origin == 'default':
        if not skia:
            return None
        if milestone.is_nightly and target.os != 'WINNT':
            return True
    elif value and not skia:
        die('Cannot enable Skia PDF without enabling Skia')
    if skia and value:
        return True

set_config('MOZ_ENABLE_SKIA_PDF', skia_pdf)
set_define('MOZ_ENABLE_SKIA_PDF', skia_pdf)

option('--enable-skia-pdf-sfntly', help='Enable SFNTLY font subsetting in Skia PDF')

@depends('--enable-skia-pdf-sfntly', skia_pdf)
def skia_pdf_sfntly(value, skia_pdf):
    if value.origin == 'default':
        return skia_pdf
    if value and not skia_pdf:
        die('Cannot enable SFNTLY subsetting without enabling Skia PDF')
    if skia_pdf and value:
        return True

set_config('MOZ_ENABLE_SKIA_PDF_SFNTLY', skia_pdf_sfntly)
set_define('MOZ_ENABLE_SKIA_PDF_SFNTLY', skia_pdf_sfntly)

@depends(skia_pdf_sfntly)
def sfntly_includes(skia_pdf_sfntly):
    includes = []
    if skia_pdf_sfntly:
        includes += [
            '/gfx/sfntly/cpp/src',
        ]
    return includes

set_config('SFNTLY_INCLUDES', sfntly_includes)

@depends(skia)
def skia_includes(skia):
    includes = []
    if skia:
        includes += [
            '/gfx/skia',
            '/gfx/skia/skia/include/config',
            '/gfx/skia/skia/include/core',
            '/gfx/skia/skia/include/docs',
            '/gfx/skia/skia/include/gpu',
            '/gfx/skia/skia/include/utils',
        ]
    return includes

set_config('SKIA_INCLUDES', skia_includes)

option('--with-system-webp',
       help='Use system libwebp (located with pkgconfig)')

system_webp = pkg_check_modules('MOZ_WEBP', 'libwebp >= 1.0.1 libwebpdemux >= 1.0.1',
                                when='--with-system-webp')

set_config('MOZ_SYSTEM_WEBP', depends(when=system_webp)(lambda: True))

# Build Freetype in the tree
# ==============================================================
@depends(target, skia_pdf)
def tree_freetype(target, skia_pdf):
    if target.os == 'Android' or (skia_pdf and target.os == 'WINNT'):
        return True

set_define('MOZ_TREE_FREETYPE', tree_freetype)
set_config('MOZ_TREE_FREETYPE', tree_freetype)
add_old_configure_assignment('MOZ_TREE_FREETYPE', tree_freetype)

set_define('HAVE_FT_BITMAP_SIZE_Y_PPEM', tree_freetype)
set_define('HAVE_FT_GLYPHSLOT_EMBOLDEN', tree_freetype)
set_define('HAVE_FT_LOAD_SFNT_TABLE', tree_freetype)

@depends(freetype2_combined_info, tree_freetype, check_build_environment)
def ft2_info(freetype2_combined_info, tree_freetype, build_env):
    if tree_freetype:
        return namespace(cflags=('-I%s/modules/freetype2/include' % build_env.topsrcdir,),
                         libs=())
    if freetype2_combined_info:
        return freetype2_combined_info

set_config('FT2_LIBS', ft2_info.libs)
add_old_configure_assignment('FT2_LIBS',
                             ft2_info.libs)
add_old_configure_assignment('FT2_CFLAGS',
                             ft2_info.cflags)

# Marionette remote protocol
# ==============================================================
#
# Marionette is the Gecko remote protocol used for various remote control,
# automation, and testing purposes throughout Gecko, Firefox, and Fennec.
# Marionette lives in ../testing/marionette.
#
# Marionette is not really a toolkit feature, as much as a Gecko engine
# feature.  But it is enabled based on the toolkit (and target), so here
# it lives.
#
# It also backs ../testing/geckodriver, which is Mozilla's WebDriver
# implementation.
#
# For more information, see
# https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette.

@depends(target)
def marionette(target):
    """Enable Marionette by default, except on Android."""
    if target.os != 'Android':
        return True

imply_option('--enable-marionette', marionette, reason='Not Android')

option('--enable-marionette',
       help='Enable Marionette remote protocol')

@depends('--enable-marionette')
def marionette(value):
    if value:
        return True

set_config('ENABLE_MARIONETTE', marionette)

# geckodriver WebDriver implementation
# ==============================================================
#
# Turn off geckodriver for build configs we don't handle yet,
# but allow --enable-geckodriver to override when compile environment is available.
# --disable-tests implies disabling geckodriver.

@depends('--enable-tests', target, cross_compiling, hazard_analysis, asan)
def geckodriver_default(enable_tests, target, cross_compile, hazard, asan):
    if not enable_tests:
        return False
    # geckodriver depends on winapi 0.2.8, which doesn't work with AArch64.
    if target.os == 'WINNT' and target.cpu == 'aarch64':
        return False
    if hazard or target.os == 'Android' or (asan and cross_compile):
        return False
    return True

option('--enable-geckodriver', default=geckodriver_default,
       when='--enable-compile-environment',
       help='{Build|Do not build} geckodriver')

@depends('--enable-geckodriver', when='--enable-compile-environment')
def geckodriver(enabled):
    if enabled:
        return True

set_config('ENABLE_GECKODRIVER', geckodriver)

# WebRTC
# ========================================================
@depends(target)
def webrtc_default(target):
    # Turn off webrtc for OS's we don't handle yet, but allow
    # --enable-webrtc to override.
    os_match = False
    for os_fragment in ('linux', 'mingw', 'android', 'linuxandroid',
                        'dragonfly', 'freebsd', 'netbsd', 'openbsd',
                        'darwin'):
        if target.raw_os.startswith(os_fragment):
            os_match = True

    cpu_match = False
    if (target.cpu in ('x86_64', 'arm', 'aarch64', 'x86', 'ia64', 'mips32', 'mips64') or
        target.cpu.startswith('ppc')):
        cpu_match = True

    if os_match and cpu_match:
        return True
    return False

option('--disable-webrtc', default=webrtc_default,
       help='{Enable|Disable} support for WebRTC')

@depends('--disable-webrtc')
def webrtc(enabled):
    if enabled:
        return True

set_config('MOZ_WEBRTC', webrtc)
set_define('MOZ_WEBRTC', webrtc)
add_old_configure_assignment('MOZ_WEBRTC', webrtc)
set_config('MOZ_SCTP', webrtc)
set_define('MOZ_SCTP', webrtc)
set_config('MOZ_SRTP', webrtc)
set_define('MOZ_SRTP', webrtc)
set_config('MOZ_WEBRTC_SIGNALING', webrtc)
set_define('MOZ_WEBRTC_SIGNALING', webrtc)
set_config('MOZ_PEERCONNECTION', webrtc)
set_define('MOZ_PEERCONNECTION', webrtc)
# MOZ_WEBRTC_ASSERT_ALWAYS turns on a number of safety asserts in
# opt/production builds (via MOZ_CRASH())
set_config('MOZ_WEBRTC_ASSERT_ALWAYS', webrtc)
set_define('MOZ_WEBRTC_ASSERT_ALWAYS', webrtc)

option('--enable-hardware-aec-ns', when=webrtc,
       help='Enable support for hardware AEC and noise suppression')

set_config('MOZ_WEBRTC_HARDWARE_AEC_NS',
           depends_if('--enable-hardware-aec-ns', when=webrtc)(lambda _: True))
set_define('MOZ_WEBRTC_HARDWARE_AEC_NS',
           depends_if('--enable-hardware-aec-ns', when=webrtc)(lambda _: True))

# RAW media
# ==============================================================

@depends(target, webrtc)
def raw_media_default(target, webrtc):
    if target.os == 'Android':
        return True
    if webrtc:
        return True

option('--enable-raw',
       default=raw_media_default,
       help='{Enable|Disable} support for RAW media')

set_config('MOZ_RAW', depends_if('--enable-raw')(lambda _: True))
set_define('MOZ_RAW', depends_if('--enable-raw')(lambda _: True))

# ASan Reporter Addon
# ==============================================================
option('--enable-address-sanitizer-reporter',
       help='Enable Address Sanitizer Reporter Extension')

@depends('--enable-address-sanitizer-reporter')
def enable_asan_reporter(value):
    if value:
        return True

set_config('MOZ_ASAN_REPORTER', enable_asan_reporter)
set_define('MOZ_ASAN_REPORTER', enable_asan_reporter)
add_old_configure_assignment('MOZ_ASAN_REPORTER', enable_asan_reporter)

# Elfhack
# ==============================================================
with only_when('--enable-compile-environment'):
    @depends(host, target)
    def has_elfhack(host, target):
        return target.kernel == 'Linux' and host.kernel == 'Linux' and \
               target.cpu in ('arm', 'x86', 'x86_64')

    @depends('--enable-release')
    def default_elfhack(release):
        return bool(release)

    with only_when(has_elfhack):
        option('--disable-elf-hack', default=default_elfhack,
               help='{Enable|Disable} elf hacks')

        set_config('USE_ELF_HACK',
                   depends_if('--enable-elf-hack')(lambda _: True))


@depends(check_build_environment)
def idl_roots(build_env):
    return namespace(ipdl_root=os.path.join(build_env.topobjdir, 'ipc', 'ipdl'),
                     webidl_root=os.path.join(build_env.topobjdir,
                                              'dom', 'bindings'))

set_config('WEBIDL_ROOT', idl_roots.webidl_root)
set_config('IPDL_ROOT', idl_roots.ipdl_root)

# Proxy bypass protection
# ==============================================================

option('--enable-proxy-bypass-protection',
       help='Prevent suspected or confirmed proxy bypasses')

@depends_if('--enable-proxy-bypass-protection')
def proxy_bypass_protection(_):
    return True

set_config('MOZ_PROXY_BYPASS_PROTECTION', proxy_bypass_protection)
set_define('MOZ_PROXY_BYPASS_PROTECTION', proxy_bypass_protection)

# MIDL
# ==============================================================

@depends(c_compiler, toolchain_prefix)
def midl_names(c_compiler, toolchain_prefix):
    if c_compiler and c_compiler.type in ['gcc', 'clang']:
        # mingw
        widl = ('widl', )
        if toolchain_prefix:
            prefixed = tuple('%s%s' % (p, 'widl') for p in toolchain_prefix)
            widl = prefixed + widl
        return widl

    return ('midl',)

@depends(target, '--enable-compile-environment')
def check_for_midl(target, compile_environment):
    if target.os != 'WINNT':
        return

    if compile_environment:
        return True


midl = check_prog('MIDL', midl_names, when=check_for_midl, allow_missing=True,
                  paths=sdk_bin_path)


@depends(c_compiler, target, vc_compiler_path,
         when=depends(midl, target)(lambda m, t: m and t.kernel == 'WINNT'))
@imports(_from='mozbuild.shellutil', _import='quote')
def midl_flags(c_compiler, target, vc_compiler_path):
    if c_compiler and c_compiler.type in ('msvc', 'clang-cl'):
        env = {
            'x86': 'win32',
            'x86_64': 'x64',
            'aarch64': 'arm64',
        }[target.cpu]
        flags = ['-env', env]
        if c_compiler.type == 'msvc':
            flags += ['-cpp_cmd', c_compiler.compiler]
            if c_compiler.flags:
                flags += ['-cpp_opt', quote(' '.join(list(c_compiler.flags) + ['-E']))]
        else:
            # Ideally, we'd use the same flags setup as for msvc, but clang-cl
            # currently doesn't work as a preprocessor for midl, so we need to
            # find cl. https://bugs.llvm.org/show_bug.cgi?id=40140
            flags += ['-cpp_cmd', find_program('cl', paths=vc_compiler_path)]
        return flags

    # mingw
    return {
        'x86': ['--win32', '-m32'],
        'x86_64': ['--win64', '-m64'],
    }[target.cpu]


set_config('MIDL_FLAGS', midl_flags)

# Accessibility
# ==============================================================

@depends(target)
def a11y_default(target):
    # Accessibility doesn't work on aarch64-windows yet.
    if target.kernel == 'WINNT' and target.cpu == 'aarch64':
        return False
    return True

option('--enable-accessibility',
       default=a11y_default, help='{Enable|Disable} accessibility support')

@depends('--enable-accessibility', check_for_midl, midl, c_compiler)
def accessibility(value, check_for_midl, midl, c_compiler):
    enabled = bool(value)

    if not enabled:
        return

    if check_for_midl and not midl:
        if c_compiler and c_compiler.type in ('gcc', 'clang'):
            die('You have accessibility enabled, but widl could not be found. '
                'Add --disable-accessibility to your mozconfig or install widl. '
                'See https://developer.mozilla.org/en-US/docs/Cross_Compile_Mozilla_for_Mingw32 for details.')
        else:
            die('MIDL could not be found. '
                'Building accessibility without MIDL is not supported.')

    return enabled


set_config('ACCESSIBILITY', accessibility)
set_define('ACCESSIBILITY', accessibility)
add_old_configure_assignment('ACCESSIBILITY', accessibility)

# Addon signing
# ==============================================================

option('--with-unsigned-addon-scopes',
       nargs='+', choices=('app', 'system'),
       help='Addon scopes where signature is not required')

@depends('--with-unsigned-addon-scopes')
def unsigned_addon_scopes(scopes):
    return namespace(
        app='app' in scopes or None,
        system='system' in scopes or None,
    )

set_config('MOZ_UNSIGNED_APP_SCOPE', unsigned_addon_scopes.app)
set_config('MOZ_UNSIGNED_SYSTEM_SCOPE', unsigned_addon_scopes.system)

# Launcher process (Windows only)
# ==============================================================

@depends(target, milestone)
def launcher_process_default(target, milestone):
    return target.os == 'WINNT' and milestone.is_nightly

option('--enable-launcher-process', default=launcher_process_default,
       help='{Enable|Disable} launcher process by default')

@depends('--enable-launcher-process', target)
def launcher(value, target):
    enabled = bool(value)
    if enabled and target.os != 'WINNT':
        die('Cannot enable launcher process on %s', target.os)
    if enabled:
        return True

set_config('MOZ_LAUNCHER_PROCESS', launcher)
set_define('MOZ_LAUNCHER_PROCESS', launcher)

# Prio
# ==============================================================
@depends(c_compiler)
def libprio(info):
    if info:
      # MSVC is not supported by libprio.
      if info.type in ('msvc',):
        return None
    return True

set_config('MOZ_LIBPRIO', libprio)

# Maintenance service (Windows only)
# ==============================================================

option('--enable-maintenance-service',
       when=target_is_windows, default=target_is_windows,
       help='{Enable|Disable} building of maintenance service')

set_define('MOZ_MAINTENANCE_SERVICE',
           depends_if('--enable-maintenance-service',
                      when=target_is_windows)(lambda _: True))
set_config('MOZ_MAINTENANCE_SERVICE',
           depends_if('--enable-maintenance-service',
                      when=target_is_windows)(lambda _: True))

# Bundled fonts on desktop platform
# ==============================================================

@depends(target)
def bundled_fonts_default(target):
    return target.os == 'WINNT' or target.kernel == 'Linux'

@depends(build_project)
def allow_bundled_fonts(project):
    return project == 'browser'

option('--enable-bundled-fonts', default=bundled_fonts_default,
       when=allow_bundled_fonts,
       help='{Enable|Disable} support for bundled fonts on desktop platforms')

set_define('MOZ_BUNDLED_FONTS',
           depends_if('--enable-bundled-fonts', when=allow_bundled_fonts)(lambda _: True))

# Verify MAR signatures
# ==============================================================

option('--enable-verify-mar', help='Enable verifying MAR signatures')

set_define('MOZ_VERIFY_MAR_SIGNATURE',
           depends_if('--enable-verify-mar')(lambda _: True))
set_config('MOZ_VERIFY_MAR_SIGNATURE',
           depends_if('--enable-verify-mar')(lambda _: True))

# TaskTracer
# ==============================================================

option('--enable-tasktracer', help='Enable TaskTracer')

set_define('MOZ_TASK_TRACER', depends_if('--enable-tasktracer')(lambda _: True))
set_config('MOZ_TASK_TRACER', depends_if('--enable-tasktracer')(lambda _: True))

# Reflow counting
# ==============================================================

@depends(moz_debug)
def reflow_perf(debug):
    if debug:
        return True

option('--enable-reflow-perf',
       default=reflow_perf,
       help='{Enable|Disable} reflow performance tracing')

# The difference in conditions here comes from the initial implementation
# in old-configure, which was unexplained there as well.
set_define('MOZ_REFLOW_PERF', depends_if('--enable-reflow-perf')(lambda _: True))
set_define('MOZ_REFLOW_PERF_DSP', reflow_perf)

# Layout debugger
# ==============================================================

@depends(moz_debug)
def layout_debugger(debug):
    if debug:
        return True

option('--enable-layout-debugger',
       default=layout_debugger,
       help='{Enable|Disable} layout debugger')

set_config('MOZ_LAYOUT_DEBUGGER', depends_if('--enable-layout-debugger')(lambda _: True))


# Shader Compiler for Windows (and MinGW Cross Compile)
# ==============================================================

with only_when(compile_environment):
    fxc = check_prog('FXC', ('fxc.exe', 'fxc2.exe'), when=depends(target)
                     (lambda t: t.kernel == 'WINNT'),
                     paths=sdk_bin_path)
    wine = check_prog('WINE', ['wine'], when=depends(target, host)
                      (lambda t, h: t.kernel == 'WINNT' and h.kernel == 'Linux'))


# VPX
# ===

with only_when(compile_environment):
    option('--with-system-libvpx',
           help='Use system libvpx (located with pkgconfig)')

    with only_when('--with-system-libvpx'):
        vpx = pkg_check_modules('MOZ_LIBVPX', 'vpx >= 1.5.0')

        check_header('vpx/vpx_decoder.h', flags=vpx.cflags, onerror=lambda: die(
            "Couldn't find vpx/vpx_decoder.h, which is required to build "
            "with system libvpx. Use --without-system-libvpx to build "
            "with in-tree libvpx."))

        check_symbol('vpx_codec_dec_init_ver', flags=vpx.libs, onerror=lambda: die(
            "--with-system-libvpx requested but symbol vpx_codec_dec_init_ver "
            "not found"
        ))

        set_config('MOZ_SYSTEM_LIBVPX', True)


    @depends('--with-system-libvpx', target, gnu_as)
    def in_tree_vpx(system_libvpx, target, gnu_as):
        if system_libvpx:
            return

        use_yasm = (target.cpu in ('x86', 'x86_64')) or None
        need_yasm = False
        arm_asm = (target.cpu == 'arm' and gnu_as) or None

        if use_yasm:
            need_yasm = True
            if target.kernel == 'WINNT':
                need_yasm = Version('1.1')

        return namespace(arm_asm=arm_asm, use_yasm=use_yasm, need_yasm=need_yasm)


    # Building with -mfpu=neon requires either the "softfp" or the
    # "hardfp" ABI. Depending on the compiler's default target, and the
    # CFLAGS, the default ABI might be neither, in which case it is the
    # "softfloat" ABI.
    # The "softfloat" ABI is binary-compatible with the "softfp" ABI, so
    # we can safely mix code built with both ABIs. So, if we detect
    # that compiling uses the "softfloat" ABI, force the use of the
    # "softfp" ABI instead.
    # Confusingly, the __SOFTFP__ preprocessor variable indicates the
    # "softfloat" ABI, not the "softfp" ABI.
    # Note: VPX_ASFLAGS is also used in CFLAGS.
    softfp = cxx_compiler.try_compile(body='''
        #ifndef __SOFTFP__
        #error "compiler target supports -mfpu=neon, so we don't have to add extra flags"
        #endif''', when=in_tree_vpx.arm_asm)


    @depends(in_tree_vpx, softfp, target)
    def vpx_as_flags(vpx, softfp, target):
        flags = []
        if vpx and vpx.arm_asm:
            # These flags are a lie; they're just used to enable the requisite
            # opcodes; actual arch detection is done at runtime.
            flags = ['-march=armv7-a', '-mfpu=neon']
            if softfp:
                flags.append('-mfloat-abi=softfp')
        elif vpx and vpx.use_yasm and target.os != 'WINNT' and target.cpu != 'x86_64':
            flags = ['-DPIC']
        return flags


    set_config('VPX_USE_YASM', in_tree_vpx.use_yasm)
    set_config('VPX_ASFLAGS', vpx_as_flags)
    add_old_configure_assignment('VPX_ASFLAGS', vpx_as_flags)


# JPEG
# ====

with only_when(compile_environment):
    option('--with-system-jpeg', nargs='?',
           help='Use system libjpeg (installed at given prefix)')

    @depends_if('--with-system-jpeg')
    def jpeg_flags(value):
        if len(value):
            return namespace(
                cflags=('-I%s/include' % value[0],),
                ldflags=('-L%s/lib' % value[0], '-ljpeg'),
            )
        return namespace(
            ldflags=('-ljpeg',),
        )

    with only_when('--with-system-jpeg'):
        check_symbol('jpeg_destroy_compress', flags=jpeg_flags.ldflags,
                     onerror=lambda: die('--with-system-jpeg requested but symbol '
                                         'jpeg_destroy_compress not found.'))

        c_compiler.try_compile(
            includes=[
                'stdio.h',
                'sys/types.h',
                'jpeglib.h',
            ],
            body='''
                #if JPEG_LIB_VERSION < 62
                #error Insufficient JPEG library version
                #endif
            ''',
            flags=jpeg_flags.cflags,
            check_msg='for sufficient jpeg library version',
            onerror=lambda: die('Insufficient JPEG library version for '
                                '--with-system-jpeg (62 required)'),
        )

        c_compiler.try_compile(
            includes=[
                'stdio.h',
                'sys/types.h',
                'jpeglib.h',
            ],
            body='''
                #ifndef JCS_EXTENSIONS
                #error libjpeg-turbo JCS_EXTENSIONS required
                #endif
            ''',
            flags=jpeg_flags.cflags,
            check_msg='for sufficient libjpeg-turbo JCS_EXTENSIONS',
            onerror=lambda: die('libjpeg-turbo JCS_EXTENSIONS required for '
                                 '--with-system-jpeg'),
        )

        set_config('MOZ_JPEG_CFLAGS', jpeg_flags.cflags)
        set_config('MOZ_JPEG_LIBS', jpeg_flags.ldflags)

    @depends('--with-system-jpeg', target)
    def in_tree_jpeg(system_jpeg, target):
        if system_jpeg:
            return

        flags = ()
        use_yasm = None
        need_yasm = False
        if target.kernel == 'Darwin':
            if target.cpu == 'x86':
                flags = ('-DPIC', '-DMACHO')
            elif target.cpu == 'x86_64':
                flags = ('-D__x86_64__', '-DPIC', '-DMACHO')
        elif target.kernel == 'WINNT':
            if target.cpu == 'x86':
                flags = ('-DPIC', '-DWIN32')
            elif target.cpu == 'x86_64':
                flags = ('-D__x86_64__', '-DPIC', '-DWIN64', '-DMSVC')
        elif target.cpu == 'arm':
            flags = ('-march=armv7-a', '-mfpu=neon')
        elif target.cpu == 'aarch64':
            flags = ('-march=armv8-a',)
        elif target.cpu == 'mips32':
            flags = ('-mdspr2',)
        elif target.cpu == 'x86':
            flags = ('-DPIC', '-DELF')
        elif target.cpu == 'x86_64':
            flags = ('-D__x86_64__', '-DPIC', '-DELF')

        if target.cpu in ('x86', 'x86_64'):
            use_yasm = True
            if target.kernel == 'Linux' and target.os == 'GNU':
                need_yasm = Version('1.0.1')
            else:
                need_yasm = Version('1.1')

        return namespace(flags=flags, use_yasm=use_yasm, need_yasm=need_yasm)

    set_config('LIBJPEG_TURBO_USE_YASM', in_tree_jpeg.use_yasm)
    set_config('LIBJPEG_TURBO_ASFLAGS', in_tree_jpeg.flags)


# Libav-fft Support
# ==============================================================
with only_when(compile_environment):
    @depends(target)
    def libav_fft(target):
        flags = None
        if target.kernel == 'WINNT' and target.cpu == 'x86':
            flags = ['-DPIC', '-DWIN32']
        elif target.cpu == 'x86_64':
            if target.kernel == 'Darwin':
                flags = ['-D__x86_64__', '-DPIC', '-DMACHO']
            elif target.kernel == 'WINNT':
                flags = ['-D__x86_64__', '-DPIC', '-DWIN64', '-DMSVC']
            else:
                flags = ['-D__x86_64__', '-DPIC', '-DELF']
        if flags:
            if target.kernel == 'Linux' and target.os == 'GNU':
                need_yasm = Version('1.0.1')
            else:
                need_yasm = Version('1.1')
            return namespace(flags=flags, need_yasm=need_yasm)


    set_config('MOZ_LIBAV_FFT', depends(when=libav_fft)(lambda: True))
    set_define('MOZ_LIBAV_FFT', depends(when=libav_fft)(lambda: True))
    set_config('LIBAV_FFT_ASFLAGS', libav_fft.flags)
    add_old_configure_assignment('LIBAV_FFT_ASFLAGS', libav_fft.flags)


@depends(yasm_version, in_tree_vpx.need_yasm, in_tree_jpeg.use_yasm,
         libav_fft.need_yasm)
@imports(_from='__builtin__', _import='sorted')
def valid_yasm_version(yasm_version, for_vpx, for_jpeg, for_libav):
    requires = {
        'vpx': for_vpx,
        'jpeg': for_jpeg,
        'libav': for_libav,
    }
    requires = {k: v for (k, v) in requires.items() if v}
    if requires and not yasm_version:
        items = sorted(requires.keys())
        if len(items) > 1:
            what = ' and '.join((', '.join(items[:-1]), items[-1]))
        else:
            what = items[0]
        die('Yasm is required to build with %s, but you do not appear to have '
            'Yasm installed.' % what)

    versioned = {k: v for (k, v) in requires.items() if v is not True}
    by_version = sorted(versioned.items(), key=lambda x: x[1])
    if by_version:
        what, version = by_version[-1]
        if yasm_version < version:
            die('Yasm version %s or greater is required to build with %s.'
                % (version, what))


# ANGLE OpenGL->D3D translator for WebGL
# ==============================================================

with only_when(compile_environment & target_is_windows):
    def d3d_compiler_dll_result(value):
        if not value.path:
            return 'provided by the OS'
        return value.path

    @depends(target, valid_windows_sdk_dir, fxc)
    @checking('for D3D compiler DLL', d3d_compiler_dll_result)
    @imports('os.path')
    def d3d_compiler_dll(target, windows_sdk_dir, fxc):
        suffix = {
            'x86_64': 'x64',
        }.get(target.cpu, target.cpu)

        name = 'd3dcompiler_47.dll'

        if target.cpu == 'aarch64':
            # AArch64 Windows comes with d3dcompiler_47.dll installed
            return namespace(name=name, path=None)

        if windows_sdk_dir:
            path = os.path.join(windows_sdk_dir.path, 'Redist', 'D3D', suffix, name)
            error_extra = 'in Windows SDK at {}'.format(windows_sdk_dir.path)
        else:
            path = os.path.join(os.path.dirname(fxc), name)
            error_extra = 'alongside FXC at {}'.format(fxc)

        if os.path.exists(path):
            return namespace(name=name, path=path)
        die('Could not find {} {}'.format(name, error_extra))


    set_config('MOZ_ANGLE_RENDERER', True)
    set_config('MOZ_D3DCOMPILER_VISTA_DLL', d3d_compiler_dll.name,
               when=d3d_compiler_dll.path)
    set_config('MOZ_D3DCOMPILER_VISTA_DLL_PATH', d3d_compiler_dll.path)