Skip to content
Snippets Groups Projects
moz.configure 23.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • # -*- 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/.
    
    include('build/moz.configure/init.configure')
    
    
    # Note:
    # - Gecko-specific options and rules should go in toolkit/moz.configure.
    # - Firefox-specific options and rules should go in browser/moz.configure.
    # - Fennec-specific options and rules should go in
    #   mobile/android/moz.configure.
    # - Spidermonkey-specific options and rules should go in js/moz.configure.
    # - etc.
    
    
    option('--enable-artifact-builds', env='MOZ_ARTIFACT_BUILDS',
           help='Download and use prebuilt binary artifacts.')
    
    @depends('--enable-artifact-builds')
    def artifact_builds(value):
        if value:
    
            return True
    
    set_config('MOZ_ARTIFACT_BUILDS', artifact_builds)
    
    imply_option('--enable-artifact-build-symbols',
                 depends(artifact_builds)(lambda v: False if v is None else None),
                 reason='--disable-artifact-builds')
    
    
    option('--enable-artifact-build-symbols', nargs='?', choices=('full',),
    
           help='Download symbols when artifact builds are enabled.')
    
    
    @depends('--enable-artifact-build-symbols', 'MOZ_AUTOMATION', target)
    def enable_artifact_build_symbols(value, automation, target):
        if len(value):
            return value[0]
        if bool(value):
            if target.os == 'Android' and not automation:
                return 'full'
            return True
        return None
    
    
    @depends('--enable-artifact-builds')
    def imply_disable_compile_environment(value):
        if value:
            return False
    
    
    option(env='MOZ_COPY_PDBS',
        help='For builds that do not support symbols in the normal fashion,'
             ' generate and copy them into the resulting build archive.')
    
    set_config('MOZ_COPY_PDBS', depends_if('MOZ_COPY_PDBS')(lambda _: True))
    
    
    imply_option('--enable-compile-environment', imply_disable_compile_environment)
    
    
    option('--disable-compile-environment',
           help='Disable compiler/library checks')
    
    @depends('--disable-compile-environment')
    
    def compile_environment(compile_env):
        if compile_env:
    
            return True
    
    set_config('COMPILE_ENVIRONMENT', compile_environment)
    
    add_old_configure_assignment('COMPILE_ENVIRONMENT', compile_environment)
    
    js_option('--disable-tests',
              help='Do not build test libraries & programs')
    
    @depends('--disable-tests')
    def enable_tests(value):
        if value:
            return True
    
    set_config('ENABLE_TESTS', enable_tests)
    set_define('ENABLE_TESTS', enable_tests)
    
    @depends(enable_tests)
    def gtest_has_rtti(value):
        if value:
            return '0'
    
    set_define('GTEST_HAS_RTTI', gtest_has_rtti)
    
    @depends(target, enable_tests)
    def linux_gtest_defines(target, enable_tests):
        if enable_tests and target.os == 'Android':
            return namespace(os_linux_android=True,
                             use_own_tr1_tuple=True,
                             has_clone='0')
    
    set_define('GTEST_OS_LINUX_ANDROID',
    
    set_define('GTEST_USE_OWN_TR1_TUPLE',
    
    js_option('--enable-debug',
              nargs='?',
              help='Enable building with developer debug info '
                   '(using the given compiler flags).')
    
    
    @depends('--enable-debug')
    def moz_debug(debug):
        if debug:
            return bool(debug)
    
    set_config('MOZ_DEBUG', moz_debug)
    set_define('MOZ_DEBUG', moz_debug)
    
    # Override any value MOZ_DEBUG may have from the environment when passing it
    # down to old-configure.
    add_old_configure_assignment('MOZ_DEBUG',
                                 depends('--enable-debug')(lambda x: bool(x)))
    
    js_option('--enable-rust-debug',
    
              default=depends(when='--enable-debug')(lambda: True),
    
              help='{Build|Do not build} Rust code with debug assertions turned '
                   'on.')
    
    @depends(when='--enable-rust-debug')
    def debug_rust():
        return True
    
    
    set_config('MOZ_DEBUG_RUST', debug_rust)
    set_define('MOZ_DEBUG_RUST', debug_rust)
    
    
    js_option(env='MOZ_PGO', help='Build with profile guided optimizations')
    
    set_config('MOZ_PGO', depends('MOZ_PGO')(lambda x: bool(x)))
    
    
    include('build/moz.configure/toolchain.configure',
            when='--enable-compile-environment')
    
    
    include('build/moz.configure/pkg.configure')
    # Make this assignment here rather than in pkg.configure to avoid
    # requiring this file in unit tests.
    add_old_configure_assignment('PKG_CONFIG', pkg_config)
    
    
    include('build/moz.configure/memory.configure',
            when='--enable-compile-environment')
    include('build/moz.configure/headers.configure',
            when='--enable-compile-environment')
    include('build/moz.configure/warnings.configure',
            when='--enable-compile-environment')
    
    include('build/moz.configure/flags.configure',
            when='--enable-compile-environment')
    
    # rust.configure is included by js/moz.configure.
    
    js_option('--enable-valgrind',
              help='Enable Valgrind integration hooks')
    
    valgrind_h = check_header('valgrind/valgrind.h', when='--enable-valgrind')
    
    @depends('--enable-valgrind', valgrind_h)
    def check_valgrind(valgrind, valgrind_h):
        if valgrind:
            if not valgrind_h:
                die('--enable-valgrind specified but Valgrind is not installed')
            return True
    
    set_define('MOZ_VALGRIND', check_valgrind)
    set_config('MOZ_VALGRIND', check_valgrind)
    
    
    @depends(target, host)
    def is_openbsd(target, host):
        return target.kernel == 'OpenBSD' or host.kernel == 'OpenBSD'
    
    option(env='SO_VERSION', nargs=1, default='1.0', when=is_openbsd,
           help='Shared library version for OpenBSD systems')
    
    @depends('SO_VERSION', when=is_openbsd)
    def so_version(value):
        return value
    
    
    @template
    def library_name_info_template(host_or_target):
    
        assert host_or_target in {host, target}
    
        compiler = {
            host: host_c_compiler,
            target: c_compiler,
        }[host_or_target]
    
        @depends(host_or_target, compiler, so_version)
        def library_name_info_impl(host_or_target, compiler, so_version):
            if host_or_target.kernel == 'WINNT':
                # There aren't artifacts for mingw builds, so it's OK that the
                # results are inaccurate in that case.
    
                if compiler and compiler.type != 'clang-cl':
    
                    return namespace(
                        dll=namespace(prefix='', suffix='.dll'),
                        lib=namespace(prefix='lib', suffix='a'),
                        import_lib=namespace(prefix='lib', suffix='a'),
                        rust_lib=namespace(prefix='', suffix='lib'),
                        obj=namespace(prefix='', suffix='o'),
                    )
    
    
                return namespace(
                    dll=namespace(prefix='', suffix='.dll'),
    
                    lib=namespace(prefix='', suffix='lib'),
                    import_lib=namespace(prefix='', suffix='lib'),
    
                    rust_lib=namespace(prefix='', suffix='lib'),
    
            elif host_or_target.kernel == 'Darwin':
                return namespace(
                    dll=namespace(prefix='lib', suffix='.dylib'),
                    lib=namespace(prefix='lib', suffix='a'),
                    import_lib=namespace(prefix=None, suffix=''),
                    rust_lib=namespace(prefix='lib', suffix='a'),
                    obj=namespace(prefix='', suffix='o'),
                )
            elif so_version:
                so = '.so.%s' % so_version
            else:
                so = '.so'
    
                lib=namespace(prefix='lib', suffix='a'),
                import_lib=namespace(prefix=None, suffix=''),
                rust_lib=namespace(prefix='lib', suffix='a'),
                obj=namespace(prefix='', suffix='o'),
            )
    
    
        return library_name_info_impl
    
    host_library_name_info = library_name_info_template(host)
    library_name_info = library_name_info_template(target)
    
    set_config('DLL_PREFIX', library_name_info.dll.prefix)
    set_config('DLL_SUFFIX', library_name_info.dll.suffix)
    
    set_config('HOST_DLL_PREFIX', host_library_name_info.dll.prefix)
    set_config('HOST_DLL_SUFFIX', host_library_name_info.dll.suffix)
    
    set_config('LIB_PREFIX', library_name_info.lib.prefix)
    set_config('LIB_SUFFIX', library_name_info.lib.suffix)
    set_config('RUST_LIB_PREFIX', library_name_info.rust_lib.prefix)
    set_config('RUST_LIB_SUFFIX', library_name_info.rust_lib.suffix)
    set_config('OBJ_SUFFIX', library_name_info.obj.suffix)
    
    # Lots of compilation tests depend on this variable being present.
    
    add_old_configure_assignment('OBJ_SUFFIX', library_name_info.obj.suffix)
    set_config('IMPORT_LIB_SUFFIX', library_name_info.import_lib.suffix)
    
    set_define('MOZ_DLL_PREFIX', depends(library_name_info.dll.prefix)(lambda s: '"%s"' % s))
    
    set_define('MOZ_DLL_SUFFIX', depends(library_name_info.dll.suffix)(lambda s: '"%s"' % s))
    
    @imports(_from='mozbuild.backend', _import='backends')
    
    @deprecated_option('--enable-build-backend', nargs='+',
                       choices=build_backends_choices)
    def build_backend(backends):
        if backends:
            return tuple('+%s' % b for b in backends)
    
    @depends('--enable-artifact-builds', '--disable-compile-environment',
             '--enable-build-backend', '--help')
    
    def build_backend_defaults(artifact_builds, compile_environment, requested_backends,
                               _):
        if 'Tup' in requested_backends:
            # As a special case, if Tup was requested, do not combine it with any
            # Make based backend by default.
            all_backends = []
        elif artifact_builds:
    
            all_backends = ['FasterMake+RecursiveMake']
        else:
            all_backends = ['RecursiveMake', 'FasterMake']
    
        # Normally, we'd use target.os == 'WINNT', but a dependency on target
        # would require target to depend on --help, as well as host and shell,
        # and this is not a can of worms we can open at the moment.
        if sys.platform == 'win32' and compile_environment:
    
    
    option('--build-backends', nargs='+', default=build_backend_defaults,
           choices=build_backends_choices, help='Build backends to generate')
    
    @depends('--build-backends')
    def build_backends(backends):
        return backends
    
    set_config('BUILD_BACKENDS', build_backends)
    
    
    @depends(check_build_environment, build_backends)
    @imports('glob')
    def check_objdir_backend_reuse(build_env, backends):
        # "Make based" might be RecursiveMake or a hybrid backend, so "Make" is
        # intentionally vague for use with the substring match below.
        incompatible_backends = (
            ('Tup', 'Make'),
            ('Make', 'Tup')
        )
        for backend_file in glob.iglob(os.path.join(build_env.topobjdir,
                                                    'backend.*Backend')):
            for prev, curr in incompatible_backends:
                if prev in backend_file and any(curr in b for b in backends):
                    die("The active objdir, %s, was previously "
                        "used to build with a %s based backend. "
                        "Change objdirs (by setting MOZ_OBJDIR in "
                        "your mozconfig) or clobber to continue.\n",
                        build_env.topobjdir, prev)
    
    
    
    option('--disable-gtest-in-build',
           help='Force disable building the gtest libxul during the build.',
           when='--enable-compile-environment')
    
    
    # Determine whether to build the gtest xul. This happens in automation
    
    # on Android and Desktop platforms with the exception of Windows PGO, where
    # linking xul-gtest.dll takes too long.
    
    @depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION', '--disable-gtest-in-build',
    
             enable_tests, when='--enable-compile-environment')
    def build_gtest(pgo, build_project, target, automation, enabled, enable_tests):
        if not enable_tests or not enabled:
    
        if (automation and build_project in ('browser', 'mobile/android') and
    
            not (pgo and target.os == 'WINNT')):
            return True
    
    set_config('LINK_GTEST_DURING_COMPILE', build_gtest)
    
    # Localization
    # ==============================================================
    option('--enable-ui-locale', default='en-US',
           help='Select the user interface locale (default: en-US)')
    
    set_config('MOZ_UI_LOCALE', depends('--enable-ui-locale')(lambda x: x))
    
    
    # clang-plugin location
    # ==============================================================
    
    @depends(host_library_name_info, check_build_environment,
             when='--enable-clang-plugin')
    
    def clang_plugin_path(library_name_info, build_env):
        topobjdir = build_env.topobjdir
        if topobjdir.endswith('/js/src'):
            topobjdir = topobjdir[:-7]
        return os.path.abspath(
            os.path.join(topobjdir, 'build', 'clang-plugin',
                         '%sclang-plugin%s' % (library_name_info.dll.prefix,
                                               library_name_info.dll.suffix))
        )
    
    add_old_configure_assignment('CLANG_PLUGIN', clang_plugin_path)
    
    
    
    # Awk detection
    # ==============================================================
    awk = check_prog('AWK', ('gawk', 'mawk', 'nawk', 'awk'))
    
    # Until the AWK variable is not necessary in old-configure
    @depends(awk)
    def awk_for_old_configure(value):
    
        return value
    
    add_old_configure_assignment('AWK', awk_for_old_configure)
    
    # Perl detection
    # ==============================================================
    perl = check_prog('PERL', ('perl5', 'perl'))
    
    # Until the PERL variable is not necessary in old-configure
    @depends(perl)
    def perl_for_old_configure(value):
    
        return value
    
    add_old_configure_assignment('PERL', perl_for_old_configure)
    
    
    @template
    def perl_version_check(min_version):
        @depends(perl)
        @checking('for minimum required perl version >= %s' % min_version)
        def get_perl_version(perl):
    
            return Version(check_cmd_output(
                perl, '-e', 'print $]',
                onerror=lambda: die('Failed to get perl version.')
            ))
    
    
        @depends(get_perl_version)
        def check_perl_version(version):
            if version < min_version:
    
                die('Perl %s or higher is required.', min_version)
    
    
        @depends(perl)
        @checking('for full perl installation')
    
        def has_full_perl_installation(perl):
            ret = subprocess.call(
                [perl, '-e', 'use Config; exit(!-d $Config{archlib})'])
            return ret == 0
    
        @depends(has_full_perl_installation)
        def require_full_perl_installation(has_full_perl_installation):
            if not has_full_perl_installation:
    
                die('Cannot find Config.pm or $Config{archlib}. '
                    'A full perl installation is required.')
    
    # GNU make detection
    # ==============================================================
    option(env='MAKE', nargs=1, help='Path to GNU make')
    
    @depends('MAKE', host)
    def possible_makes(make, host):
        candidates = []
        if host.kernel == 'WINNT':
            candidates.append('mingw32-make')
        if make:
            candidates.append(make[0])
        if host.kernel == 'WINNT':
            candidates.extend(('make', 'gmake'))
        else:
            candidates.extend(('gmake', 'make'))
        return candidates
    
    check_prog('GMAKE', possible_makes)
    
    
    @depends(build_backends, build_project)
    def tup_include(build_backends, build_project):
        # We need to check the rustc version when building with tup, but
        # rustc_info isn't available when configuring js (and build_backends isn't
        # available from project-specific configure), so as a workaround we only
        # include the file when we know we'll need it. This can be removed when
        # we globally require a rustc recent enough to build with tup.
        if build_project not in ('browser', 'mobile/android'):
            return None
    
        for backend in build_backends:
            if 'Tup' in backend:
    
                return 'build/moz.configure/tup.configure'
    
    # watchman detection
    # ==============================================================
    
    
    option(env='WATCHMAN', nargs=1, help='Path to the watchman program')
    
    @checking('for watchman', callback=lambda w: w.path if w else 'not found')
    
    def watchman(host, prog):
        # On Windows, `watchman` is only supported on 64-bit hosts.
        if host.os == 'WINNT' and host.cpu != 'x86_64':
            return
    
    
        if not prog:
            prog = find_program('watchman')
    
        if not prog:
            return
    
    
        # `watchman version` will talk to the Watchman daemon service.
        # This can hang due to permissions problems. e.g.
        # https://github.com/facebook/watchman/issues/376. So use
        # `watchman --version` to prevent a class of failures.
        out = check_cmd_output(prog, '--version', onerror=lambda: None)
    
        return namespace(path=prog, version=Version(out.strip()))
    
    @checking('for watchman version')
    def watchman_version(w):
        return w.version
    
    
    @depends_all(hg_version, hg_config, watchman)
    @checking('for watchman Mercurial integration')
    @imports('os')
    def watchman_hg(hg_version, hg_config, watchman):
        if hg_version < Version('3.8'):
            return 'no (Mercurial 3.8+ required)'
    
        ext_enabled = False
        mode_disabled = False
    
        for k in ('extensions.fsmonitor', 'extensions.hgext.fsmonitor'):
            if k in hg_config and hg_config[k] != '!':
                ext_enabled = True
    
        mode_disabled = hg_config.get('fsmonitor.mode') == 'off'
    
        if not ext_enabled:
            return 'no (fsmonitor extension not enabled)'
        if mode_disabled:
            return 'no (fsmonitor.mode=off disables fsmonitor)'
    
        return True
    
    
    # Miscellaneous programs
    # ==============================================================
    check_prog('XARGS', ('xargs',))
    
    
            return namespace(
                DSYMUTIL=('dsymutil', 'llvm-dsymutil'),
    
                MKFSHFS=('newfs_hfs', 'mkfs.hfsplus'),
                HFS_TOOL=('hfsplus',)
    
        if target.os == 'GNU' and target.kernel == 'Linux':
    
    check_prog('DSYMUTIL', extra_programs.DSYMUTIL,
    
    check_prog('MKFSHFS', extra_programs.MKFSHFS,
    
    check_prog('HFS_TOOL', extra_programs.HFS_TOOL,
    
    check_prog('RPMBUILD', extra_programs.RPMBUILD,
    
        if target.kernel != 'WINNT':
            return
    
        candidates = [
    
            'makensis-3.01',
            'makensis-3.0b3',
            'makensis-3.0b1',
    
            'makensis',
        ]
    
        # Look for nsis installed by msys environment. But only the 32-bit version.
        # We use an absolute path and insert as the first entry so it is preferred
        # over a 64-bit exe that may be in PATH.
        if 'MSYSTEM_PREFIX' in os.environ:
            prefix = os.path.dirname(os.environ['MSYSTEM_PREFIX'])
            candidates.insert(0, os.path.join(prefix, 'mingw32', 'bin', 'makensis.exe'))
    
        return tuple(candidates)
    
    nsis = check_prog('MAKENSISU', makensis_progs, allow_missing=True)
    
    
    # Make sure the version of makensis is up to date.
    @depends_if(nsis)
    @checking('for NSIS version')
    @imports('re')
    def nsis_version(nsis):
        nsis_min_version = '3.0b1'
        out = check_cmd_output(nsis, '-version',
                               onerror=lambda: die('Failed to get nsis version.'))
        m = re.search(r'(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?', out)
    
        if not m:
            raise FatalCheckError('Unknown version of makensis')
        ver = Version(m.group(0))
    
    
        # Versions comparisons don't quite work well with beta versions, so ensure
        # it works for the non-beta version.
        if ver < nsis_min_version and (ver >= '3.0a' or ver < '3'):
    
            raise FatalCheckError('To build the installer you must have NSIS'
                                  ' version %s or greater in your path'
                                  % nsis_min_version)
    
        return ver
    
    
    # And that makensis is 32-bit (but only on Windows).
    @depends_if(nsis, when=depends(host)(lambda h: h.kernel == 'WINNT'))
    
    @checking('for 32-bit NSIS')
    def nsis_binary_type(nsis):
        bin_type = windows_binary_type(nsis)
        if bin_type != 'win32':
            raise FatalCheckError('%s is not a 32-bit Windows application' % nsis)
    
        return 'yes'
    
    
    # And any flags we have to give to makensis
    @depends(host)
    def nsis_flags(host):
        if host.kernel != 'WINNT':
            return '-nocd'
        return ''
    
    set_config('MAKENSISU_FLAGS', nsis_flags)
    
    check_prog('7Z', ('7z', '7za'), allow_missing=True, when=target_is_windows)
    
    
    @depends(host_c_compiler, c_compiler, bindgen_config_paths)
    def llvm_objdump(host_c_compiler, c_compiler, bindgen_config_paths):
    
        for compiler in (host_c_compiler, c_compiler):
            if compiler and compiler.type == 'clang':
                clang = compiler.compiler
                break
            elif compiler and compiler.type == 'clang-cl':
                clang = os.path.join(os.path.dirname(compiler.compiler), 'clang')
                break
    
        if not clang and bindgen_config_paths:
    
            clang = bindgen_config_paths.clang_path
        llvm_objdump = 'llvm-objdump'
        if clang:
            out = check_cmd_output(clang, '--print-prog-name=llvm-objdump',
                                   onerror=lambda: None)
            if out:
                llvm_objdump = out.rstrip()
        return (llvm_objdump,)
    
    
    
    llvm_objdump = check_prog('LLVM_OBJDUMP', llvm_objdump, what='llvm-objdump',
    
                              when='--enable-compile-environment',
                              paths=toolchain_search_path)
    
    
    add_old_configure_assignment('LLVM_OBJDUMP', llvm_objdump)
    
    # Fallthrough to autoconf-based configure
    include('build/moz.configure/old.configure')
    
    # JS Subconfigure.
    include('js/sub.configure', when=compile_environment & toolkit)
    
    
    
    @depends(check_build_environment, build_project)
    
    @imports('glob')
    def config_status_deps(build_env, build_project):
    
        topsrcdir = build_env.topsrcdir
        topobjdir = build_env.topobjdir
    
    
        if not build_env.topobjdir.endswith('js/src'):
            extra_deps = [
                os.path.join(topsrcdir, build_project, 'confvars.sh'),
                os.path.join(topobjdir, '.mozconfig.json'),
            ]
        else:
            # mozconfig changes may impact js configure.
            extra_deps = [os.path.join(topobjdir[:-7], '.mozconfig.json')]
    
        return list(__sandbox__._all_paths) + extra_deps + [
    
            os.path.join(topsrcdir, 'configure'),
            os.path.join(topsrcdir, 'js', 'src', 'configure'),
            os.path.join(topsrcdir, 'configure.in'),
            os.path.join(topsrcdir, 'js', 'src', 'configure.in'),
            os.path.join(topsrcdir, 'nsprpub', 'configure'),
            os.path.join(topsrcdir, 'config', 'milestone.txt'),
            os.path.join(topsrcdir, 'browser', 'config', 'version.txt'),
            os.path.join(topsrcdir, 'browser', 'config', 'version_display.txt'),
            os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'),
            os.path.join(topsrcdir, 'python', 'mozbuild', 'mozbuild', 'virtualenv.py'),
            os.path.join(topsrcdir, 'testing', 'mozbase', 'packages.txt'),
            os.path.join(topsrcdir, 'aclocal.m4'),
            os.path.join(topsrcdir, 'old-configure.in'),
            os.path.join(topsrcdir, 'js', 'src', 'aclocal.m4'),
            os.path.join(topsrcdir, 'js', 'src', 'old-configure.in'),
        ] + glob.glob(os.path.join(topsrcdir, 'build', 'autoconf', '*.m4'))
    
    set_config('CONFIG_STATUS_DEPS', config_status_deps)
    # Please do not add anything after setting config_dep_paths.