author Kris Maglione <>
Thu, 14 Feb 2019 17:54:00 -0800
changeset 517406 7436c0f5b8b1583d20d5ea2d1d9d3b2c665bdf33
parent 517088 51c3380d5b9456e9307f35ff09678634a7d0ee7b
child 517286 13fa3e2aead6788c97e688fde0cfb8c5ee32cc72
permissions -rw-r--r--
Fix botched backout (bug 1524687). r=bustage

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

# Set the MOZ_CONFIGURE_OPTIONS variable with all the options that
# were passed somehow (environment, command line, mozconfig)
@imports(_from='mozbuild.shellutil', _import='quote')
def all_configure_options():
    result = []
    previous = None
    for option in __sandbox__._options.itervalues():
        # __sandbox__._options contains items for both and
        # option.env. But it's also an OrderedDict, meaning both are
        # consecutive.
        # Also ignore OLD_CONFIGURE and MOZCONFIG because they're not
        # interesting.
        if option == previous or option.env in ('OLD_CONFIGURE', 'MOZCONFIG'):
        previous = option
        value = __sandbox__._value_for(option)
        # We only want options that were explicitly given on the command
        # line, the environment, or mozconfig, and that differ from the
        # defaults.
        if (value is not None and value.origin not in ('default', 'implied') and
                value != option.default):
        # We however always include options that are sent to old configure
        # because we don't know their actual defaults. (Keep the conditions
        # separate for ease of understanding and ease of removal)
        elif ( == 'Help missing for old configure options' and
                option in __sandbox__._raw_options):

    return quote(*result)

set_config('MOZ_CONFIGURE_OPTIONS', all_configure_options)

# 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)')

def jprof(value):
    if value:
        return True

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

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')

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')

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

# NodeJS
# ==============================================================

# 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')
            path = os.path.join(build_env.topobjdir, '..', '..', 'l10n')
        path = os.path.join(
                expanduser(os.path.join('~', '.mozbuild'))),
    return os.path.realpath(os.path.abspath(path))

set_config('L10NBASEDIR', l10n_base)

# Default toolkit
# ==============================================================
def toolkit_choices(target):
    if target.os == 'WINNT':
        return ('cairo-windows',)
    elif target.os == 'OSX':
        return ('cairo-cocoa',)
    elif target.os == 'iOS':
        return ('cairo-uikit',)
    elif target.os == 'Android':
        return ('cairo-android',)
        return ('cairo-gtk3', 'cairo-gtk3-wayland')

def toolkit_default(choices):
    return choices[0]

option('--enable-default-toolkit', nargs=1,
       choices=toolkit_choices, default=toolkit_default,
       help='Select default toolkit')

def full_toolkit(value):
    return value[0]

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

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

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

set_define(toolkit_define, True)

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')

def gl_provider(value):
    if value:
        return value[0]

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)

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

set_define(gl_provider_define, True)

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

def pdf_surface_feature(pdf_printing):
    if pdf_printing:
        return '#define CAIRO_HAS_PDF_SURFACE 1'
        # 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
# ==============================================================
       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
# ==============================================================
       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
# ==============================================================
                  'pango >= 1.22.0 pangoft2 >= 1.22.0 pangocairo >= 1.22.0',

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

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',

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

                             depends_if(freetype2_info)(lambda _: True))

# Apple platform decoder support
# ==============================================================
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
# ==============================================================
       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
# ==============================================================
       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')

# AV1 Video Codec Support
# ==============================================================
        help='Disable av1 video support')

def av1(value):
    if value:
        return True

@depends(target, nasm_version, when=av1 & compile_environment)
def dav1d_asm(target, nasm_version):
    if target.os == 'GNU' and target.kernel == 'Linux' and target.cpu in ('x86', 'x86_64'):
        if nasm_version < '2.13':
            die('nasm 2.13 or greater is required for AV1 support. '
                'Either install nasm or add --disable-av1 to your configure options.')
        return True

set_config('MOZ_DAV1D_ASM', dav1d_asm)
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)

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

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
# ==============================================================
       help='Enable OpenMAX IL for video/audio decoding')

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.
def eme_default(build_project):
    if build_project == 'browser':
        return 'widevine'

       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

def eme_modules(value):
    return value

set_config('MOZ_EME_MODULES', eme_modules)

       help='Select FORMAT of chrome files during packaging.',
       choices=('omni', 'jar', 'flat'),

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)

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). handles changing the rooting of the single
    # omnijar.
    return 'assets/omni.ja' if toolkit == 'android' else 'omni.ja'

set_config('OMNIJAR_NAME', omnijar_name)

             help='Build Places if required',

             help='Build Firefox Health Reporter Service',

             help='Build Sync Services if required')

             help='Enable Android History instead of Places',

             help='Enable dedicated profiles per install',

             help='Block users from starting profiles last used by a newer build',

       help='Allow legacy browser 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)

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')

def gpsd(value):
    return bool(value)

system_gpsd = pkg_check_modules('MOZ_GPSD', 'libgps >= 3.11',

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

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')

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_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
# ==============================================================
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')

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
# ==============================================================
def no_speechd_on_non_gtk(toolkit):
    if toolkit != 'gtk3':
        return False

imply_option('--enable-synth-speechd', no_speechd_on_non_gtk,

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

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

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

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')

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')

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


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

def skia(value):
    if not value:
        die('--disable-skia is not supported anymore')
        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)

def sfntly_includes(skia_pdf_sfntly):
    includes = []
    if skia_pdf_sfntly:
        includes += [
    return includes

set_config('SFNTLY_INCLUDES', sfntly_includes)

def skia_includes(skia):
    includes = []
    if skia:
        includes += [
    return includes

set_config('SKIA_INCLUDES', skia_includes)

       help='Use system libwebp (located with pkgconfig)')

system_webp = pkg_check_modules('MOZ_WEBP', 'libwebp >= 1.0.2 libwebpdemux >= 1.0.2',

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,),
    if freetype2_combined_info:
        return freetype2_combined_info

set_config('FT2_LIBS', ft2_info.libs)

# 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

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

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

       help='Enable Marionette remote protocol')

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,
       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
# ========================================================
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',
        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
        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')

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')

           depends_if('--enable-hardware-aec-ns', when=webrtc)(lambda _: True))
           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

       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
# ==============================================================
       help='Enable Address Sanitizer Reporter Extension')

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')

    def default_elfhack(release):
        return bool(release)

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

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

def idl_roots(build_env):
    return namespace(ipdl_root=os.path.join(build_env.topobjdir, 'ipc', 'ipdl'),
                                              'dom', 'bindings'),
                                             'xpcom', 'components'))

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

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

       help='Prevent suspected or confirmed proxy bypasses')

def proxy_bypass_protection(_):
    return True

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

# ==============================================================

@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':

    if compile_environment:
        return True

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

@depends(c_compiler, target, toolchain_search_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, toolchain_search_path):
    if c_compiler and c_compiler.type == 'clang-cl':
        env = {
            'x86': 'win32',
            'x86_64': 'x64',
            'aarch64': 'arm64',
        flags = ['-env', env]
        # Ideally, we'd use ['-cpp_cmd', c_compiler.compiler], but clang-cl
        # currently doesn't work as a preprocessor for midl, so we need to
        # find cl.
        cl = find_program('cl', paths=toolchain_search_path)
        if not cl:
            die('Could not find Microsoft Visual C/C++ compiler for MIDL')
        flags += ['-cpp_cmd', cl]
        return flags

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

set_config('MIDL_FLAGS', midl_flags)

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

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

       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:

    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 for details.')
            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
# ==============================================================

       nargs='+', choices=('app', 'system'),
       help='Addon scopes where signature is not required')

def unsigned_addon_scopes(scopes):
    return namespace(
        app='app' in scopes or None,
        system='system' in scopes or None,

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)

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

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

                      when=target_is_windows)(lambda _: True))
                      when=target_is_windows)(lambda _: True))

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

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

def allow_bundled_fonts(project):
    return project == 'browser'

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

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

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

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

           depends_if('--enable-verify-mar')(lambda _: True))
           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
# ==============================================================

def reflow_perf(debug):
    if debug:
        return True

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

def layout_debugger(debug):
    if debug:
        return True

       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'),
    wine = check_prog('WINE', ['wine'], when=depends(target, host)
                      (lambda t, h: t.kernel == 'WINNT' and h.kernel == 'Linux'))

# ===

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

    with only_when('--with-system-libvpx'):
        vpx = pkg_check_modules('MOZ_LIBVPX', 'vpx >= 1.7.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:

        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:
        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)

# ====

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

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

    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.'))

                #if JPEG_LIB_VERSION < 62
                #error Insufficient JPEG library version
            check_msg='for sufficient jpeg library version',
            onerror=lambda: die('Insufficient JPEG library version for '
                                '--with-system-jpeg (62 required)'),

                #ifndef JCS_EXTENSIONS
                #error libjpeg-turbo JCS_EXTENSIONS required
            check_msg='for sufficient libjpeg-turbo JCS_EXTENSIONS',
            onerror=lambda: die('libjpeg-turbo JCS_EXTENSIONS required for '

        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:

        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')
                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):
    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']
                flags = ['-D__x86_64__', '-DPIC', '-DELF']
        if flags:
            if target.kernel == 'Linux' and target.os == 'GNU':
                need_yasm = Version('1.0.1')
                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)

# FFmpeg's ffvpx configuration
# ==============================================================
with only_when(compile_environment):
    def yasm_has_avx2(yasm_version):
        return yasm_version >= '1.2'

    set_config('YASM_HAS_AVX2', yasm_has_avx2)

    @depends(yasm_has_avx2, libav_fft, vpx_as_flags, target)
    def ffvpx(yasm_has_avx2, libav_fft, vpx_as_flags, target):
        enable = flac_only = use_yasm = False
        flags = []
        if target.cpu in ('x86', 'x86_64'):
            enable = True
            if libav_fft and libav_fft.flags:
                use_yasm = True
                if target.kernel == 'WINNT':
                    if target.cpu == 'x86':
                        # 32-bit windows need to prefix symbols with an underscore.
                        flags.extend(('-DPREFIX', '-Pconfig_win32.asm'))
                elif target.kernel == 'Darwin':
                    # 32/64-bit macosx assemblers need to prefix symbols with an
                    # underscore.
                    flags.extend(('-DPREFIX', '-Pconfig_darwin64.asm'))
                    # Default to unix.
                flac_only = True
        elif target.cpu in ('arm', 'aarch64') and \
                target.kernel not in ('WINNT', 'Darwin'):
            enable = flac_only = True

        if use_yasm:
            # default disabled components
            if not yasm_has_avx2:

        return namespace(

    set_config('MOZ_FFVPX', True, when=ffvpx.enable)
    set_define('MOZ_FFVPX', True, when=ffvpx.enable)
    set_config('MOZ_FFVPX_FLACONLY', True, when=ffvpx.flac_only)
    set_define('MOZ_FFVPX_FLACONLY', True, when=ffvpx.flac_only)
    set_config('FFVPX_ASFLAGS', ffvpx.flags)
    set_config('FFVPX_USE_YASM', True, when=ffvpx.use_yasm)

@depends(yasm_version, in_tree_vpx.need_yasm, in_tree_jpeg.use_yasm,
         libav_fft.need_yasm, ffvpx.use_yasm)
@imports(_from='__builtin__', _import='sorted')
def valid_yasm_version(yasm_version, for_vpx, for_jpeg, for_libav,
    # Note: the default for for_ffvpx above only matters for unit tests.
    requires = {
        'vpx': for_vpx,
        'jpeg': for_jpeg,
        'libav': for_libav,
        'ffvpx': for_ffvpx,
    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]))
            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)
    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)
            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_PATH', d3d_compiler_dll.path)