Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/build/moz.configure/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 18 kB image not shown  

Quelle  util.configure   Sprache: unbekannt

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


@imports("sys")
def die(*args):
    "Print an error and terminate configure."
    log.error(*args)
    sys.exit(1)


@imports(_from="mozbuild.configure", _import="ConfigureError")
def configure_error(message):
    """Raise a programming error and terminate configure.
    Primarily for use in moz.configure templates to sanity check
    their inputs from moz.configure usage."""
    raise ConfigureError(message)


# A wrapper to obtain a process' output and return code.
# Returns a tuple (retcode, stdout, stderr).
@imports("os")
@imports("subprocess")
@imports(_from="mozbuild.shellutil", _import="quote")
@imports(_from="mozbuild.util", _import="system_encoding")
def get_cmd_output(*args, **kwargs):
    log.debug("Executing: `%s`", quote(*args))
    proc = subprocess.Popen(
        args,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        # On Python 2 on Windows, close_fds prevents the process from inheriting
        # stdout/stderr. Elsewhere, it simply prevents it from inheriting extra
        # file descriptors, which is what we want.
        close_fds=os.name != "nt",
        encoding=system_encoding,
        errors="replace",
        **kwargs,
    )
    stdout, stderr = proc.communicate()
    return proc.wait(), stdout, stderr


# A wrapper to obtain a process' output that returns the output generated
# by running the given command if it exits normally, and streams that
# output to log.debug and calls die or the given error callback if it
# does not.
@imports(_from="mozbuild.configure.util", _import="LineIO")
@imports(_from="mozbuild.shellutil", _import="quote")
def check_cmd_output(*args, **kwargs):
    onerror = kwargs.pop("onerror", None)

    with log.queue_debug():
        retcode, stdout, stderr = get_cmd_output(*args, **kwargs)
        if retcode == 0:
            with LineIO(lambda l: log.debug("| %s", l)) as o:
                o.write(stderr)
            return stdout

        log.debug("The command returned non-zero exit status %d.", retcode)
        for out, desc in ((stdout, "output"), (stderr, "error output")):
            if out:
                log.debug("Its %s was:", desc)
                with LineIO(lambda l: log.debug("| %s", l)) as o:
                    o.write(out)
        if onerror:
            return onerror()
        die("Command `%s` failed with exit status %d." % (quote(*args), retcode))


@imports("os")
def is_absolute_or_relative(path):
    if os.altsep and os.altsep in path:
        return True
    return os.sep in path


@imports(_import="mozpack.path", _as="mozpath")
def normsep(path):
    return mozpath.normsep(path)


@imports("ctypes")
@imports(_from="ctypes", _import="wintypes")
@imports(_from="mozbuild.configure.constants", _import="WindowsBinaryType")
def windows_binary_type(path):
    """Obtain the type of a binary on Windows.

    Returns WindowsBinaryType constant.
    """
    GetBinaryTypeW = ctypes.windll.kernel32.GetBinaryTypeW
    GetBinaryTypeW.argtypes = [wintypes.LPWSTR, ctypes.POINTER(wintypes.DWORD)]
    GetBinaryTypeW.restype = wintypes.BOOL

    bin_type = wintypes.DWORD()
    res = GetBinaryTypeW(path, ctypes.byref(bin_type))
    if not res:
        die("could not obtain binary type of %s" % path)

    if bin_type.value == 0:
        return WindowsBinaryType("win32")
    elif bin_type.value == 6:
        return WindowsBinaryType("win64")
    # If we see another binary type, something is likely horribly wrong.
    else:
        die("unsupported binary type on %s: %s" % (path, bin_type))


@imports("ctypes")
@imports(_from="ctypes", _import="wintypes")
def get_GetShortPathNameW():
    GetShortPathNameW = ctypes.windll.kernel32.GetShortPathNameW
    GetShortPathNameW.argtypes = [wintypes.LPCWSTR, wintypes.LPWSTR, wintypes.DWORD]
    GetShortPathNameW.restype = wintypes.DWORD
    return GetShortPathNameW


@template
@imports("ctypes")
@imports("platform")
@imports(_from="mozbuild.shellutil", _import="quote")
def normalize_path():
    # Until the build system can properly handle programs that need quoting,
    # transform those paths into their short version on Windows (e.g.
    # c:\PROGRA~1...).
    if platform.system() == "Windows":
        GetShortPathNameW = get_GetShortPathNameW()

        def normalize_path(path):
            path = normsep(path)
            if quote(path) == path:
                return path
            size = 0
            while True:
                out = ctypes.create_unicode_buffer(size)
                needed = GetShortPathNameW(path, out, size)
                if size >= needed:
                    if " " in out.value:
                        die(
                            "GetShortPathName returned a long path name: `%s`. "
                            "Use `fsutil file setshortname' "
                            "to create a short name "
                            "for any components of this path "
                            "that have spaces.",
                            out.value,
                        )
                    return normsep(out.value)
                size = needed

    else:

        def normalize_path(path):
            return normsep(path)

    return normalize_path


normalize_path = normalize_path()


@template
@imports(_from="tempfile", _import="mkstemp")
@imports("os")
@imports(_from="contextlib", _import="contextmanager")
@imports(_from="__builtin__", _import="FileNotFoundError")
def make_create_temporary_file():
    @contextmanager
    def create_temporary_file(suffix):
        fd, path = mkstemp(prefix="conftest", suffix=suffix)
        os.close(fd)
        yield path
        try:
            os.remove(path)
        except FileNotFoundError:
            pass

    return create_temporary_file


create_temporary_file = make_create_temporary_file()


# Locates the given program using which, or returns the given path if it
# exists.
# The `paths` parameter may be passed to search the given paths instead of
# $PATH.
@imports("sys")
@imports(_from="os", _import="pathsep")
@imports(_from="os", _import="environ")
@imports(_from="mozfile", _import="which")
def find_program(file, paths=None, allow_spaces=False):
    def which_normalize(file, path, exts):
        path = which(file, path=path, exts=exts)
        if not path:
            return None
        if not allow_spaces:
            return normalize_path(path)
        return normsep(path)

    # The following snippet comes from `which` itself, with a slight
    # modification to use lowercase extensions, because it's confusing rustup
    # (on top of making results not really appealing to the eye).

    # Windows has the concept of a list of extensions (PATHEXT env var).
    if sys.platform.startswith("win"):
        exts = [e.lower() for e in environ.get("PATHEXT", "").split(pathsep)]
        # If '.exe' is not in exts then obviously this is Win9x and
        # or a bogus PATHEXT, then use a reasonable default.
        if ".exe" not in exts:
            exts = [".com", ".exe", ".bat"]
    else:
        exts = None

    if is_absolute_or_relative(file):
        return which_normalize(
            os.path.basename(file), path=os.path.dirname(file), exts=exts
        )

    if paths:
        if not isinstance(paths, (list, tuple)):
            die(
                "Paths provided to find_program must be a list of strings, " "not %r",
                paths,
            )
        paths = pathsep.join(paths)

    return which_normalize(file, path=paths, exts=exts)


@imports("os")
@imports(_from="mozbuild.configure.util", _import="LineIO")
@imports(_from="__builtin__", _import="open")
@imports(_import="subprocess")
def try_invoke_compiler(
    configure_cache, compiler, language, source, flags=None, onerror=None, wrapper=[]
):
    compiler_path = compiler[0]
    compiler = wrapper + compiler
    use_cache = configure_cache is not None

    if use_cache and compiler_path not in configure_cache.version_checked_compilers:
        try:
            version_info = subprocess.check_output(
                [compiler_path, "--version"],
                encoding="UTF-8",
            ).strip()
        except subprocess.CalledProcessError:
            # There's no sane way to use the cache without the version details, so
            # we need to avoid both reads from and writes to the cache.
            use_cache = False
            pass

        if use_cache:
            if version_info != configure_cache.setdefault(compiler_path, {}).get(
                "version"
            ):
                configure_cache[compiler_path].clear()

            configure_cache[compiler_path]["version"] = version_info
            configure_cache.version_checked_compilers.add(compiler_path)

    flags = flags or []

    if use_cache:
        key = " ".join(compiler) + language + source + (" ".join(flags) or "")

        if key in configure_cache[compiler_path]:
            return configure_cache[compiler_path][key]

    if not isinstance(flags, (list, tuple)):
        die("Flags provided to try_compile must be a list of strings, " "not %r", flags)

    suffix = {
        "C": ".c",
        "C++": ".cpp",
    }[language]

    with create_temporary_file(suffix=suffix) as path:
        bsource = source.encode("ascii", "replace")

        log.debug("Creating `%s` with content:", path)
        with LineIO(lambda l: log.debug("| %s", l)) as out:
            out.write(bsource)

        with open(path, "w") as fd:
            fd.write(source)

        cmd = compiler + [path] + list(flags)
        kwargs = {"onerror": onerror}
        val = check_cmd_output(*cmd, **kwargs)
        if use_cache:
            configure_cache[compiler_path][key] = val
        return val


def unique_list(l):
    result = []
    for i in l:
        if l not in result:
            result.append(i)
    return result


# Get values out of the Windows registry. This function can only be called on
# Windows.
# The `pattern` argument is a string starting with HKEY_ and giving the full
# "path" of the registry key to get the value for, with backslash separators.
# The string can contains wildcards ('*').
# The result of this functions is an enumerator yielding tuples for each
# match. Each of these tuples contains the key name matching wildcards
# followed by the value.
#
# The `get_32_and_64_bit` argument is a boolean, if True then it will return the
# values from the 32-bit and 64-bit registry views. This defaults to False,
# which will return the view depending on the bitness of python.
#
# Examples:
#   get_registry_values(r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\'
#                       r'Windows Kits\Installed Roots\KitsRoot*')
#   yields e.g.:
#     ('KitsRoot81', r'C:\Program Files (x86)\Windows Kits\8.1\')
#     ('KitsRoot10', r'C:\Program Files (x86)\Windows Kits\10\')
#
#   get_registry_values(r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\'
#                       r'Windows Kits\Installed Roots\KitsRoot8.1')
#   yields e.g.:
#     (r'C:\Program Files (x86)\Windows Kits\8.1\',)
#
#   get_registry_values(r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\'
#                       r'Windows Kits\Installed Roots\KitsRoot8.1',
#                       get_32_and_64_bit=True)
#   yields e.g.:
#     (r'C:\Program Files (x86)\Windows Kits\8.1\',)
#     (r'C:\Program Files\Windows Kits\8.1\',)
#
#   get_registry_values(r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\'
#                       r'Windows Kits\*\KitsRoot*')
#   yields e.g.:
#     ('Installed Roots', 'KitsRoot81',
#      r'C:\Program Files (x86)\Windows Kits\8.1\')
#     ('Installed Roots', 'KitsRoot10',
#      r'C:\Program Files (x86)\Windows Kits\10\')
#
#   get_registry_values(r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\'
#                       r'VisualStudio\VC\*\x86\*\Compiler')
#   yields e.g.:
#     ('19.0', 'arm', r'C:\...\amd64_arm\cl.exe')
#     ('19.0', 'x64', r'C:\...\amd64\cl.exe')
#     ('19.0', 'x86', r'C:\...\amd64_x86\cl.exe')
@imports(_import="winreg")
@imports(_from="__builtin__", _import="WindowsError")
@imports(_from="fnmatch", _import="fnmatch")
def get_registry_values(pattern, get_32_and_64_bit=False):
    def enum_helper(func, key):
        i = 0
        while True:
            try:
                yield func(key, i)
            except WindowsError:
                break
            i += 1

    def get_keys(key, pattern, access_mask):
        try:
            s = winreg.OpenKey(key, "\\".join(pattern[:-1]), 0, access_mask)
        except WindowsError:
            return
        for k in enum_helper(winreg.EnumKey, s):
            if fnmatch(k, pattern[-1]):
                try:
                    yield k, winreg.OpenKey(s, k, 0, access_mask)
                except WindowsError:
                    pass

    def get_values(key, pattern, access_mask):
        try:
            s = winreg.OpenKey(key, "\\".join(pattern[:-1]), 0, access_mask)
        except WindowsError:
            return
        for k, v, t in enum_helper(winreg.EnumValue, s):
            if fnmatch(k, pattern[-1]):
                yield k, v

    def split_pattern(pattern):
        subpattern = []
        for p in pattern:
            subpattern.append(p)
            if "*" in p:
                yield subpattern
                subpattern = []
        if subpattern:
            yield subpattern

    def get_all_values(keys, pattern, access_mask):
        for i, p in enumerate(pattern):
            next_keys = []
            for base_key in keys:
                matches = base_key[:-1]
                base_key = base_key[-1]
                if i == len(pattern) - 1:
                    want_name = "*" in p[-1]
                    for name, value in get_values(base_key, p, access_mask):
                        yield matches + ((name, value) if want_name else (value,))
                else:
                    for name, k in get_keys(base_key, p, access_mask):
                        next_keys.append(matches + (name, k))
            keys = next_keys

    pattern = pattern.split("\\")
    assert pattern[0].startswith("HKEY_")
    keys = [(getattr(winreg, pattern[0]),)]
    pattern = list(split_pattern(pattern[1:]))
    if get_32_and_64_bit:
        for match in get_all_values(
            keys, pattern, winreg.KEY_READ | winreg.KEY_WOW64_32KEY
        ):
            yield match
        for match in get_all_values(
            keys, pattern, winreg.KEY_READ | winreg.KEY_WOW64_64KEY
        ):
            yield match
    else:
        for match in get_all_values(keys, pattern, winreg.KEY_READ):
            yield match


@imports(_from="mozbuild.configure.util", _import="Version", _as="_Version")
def Version(v):
    "A version number that can be compared usefully."
    return _Version(v)


# Denotes a deprecated option. Combines option() and @depends:
# @deprecated_option('--option')
# def option(value):
#     ...
# @deprecated_option() takes the same arguments as option(), except `help`.
# The function may handle the option like a typical @depends function would,
# but it is recommended it emits a deprecation error message suggesting an
# alternative option to use if there is one.
@template
def deprecated_option(*args, **kwargs):
    assert "help" not in kwargs
    kwargs["help"] = "Deprecated"
    opt = option(*args, **kwargs)
    kwargs = {k: v for k, v in kwargs.items() if k == "when"}

    def decorator(func):
        @depends(opt.option, **kwargs)
        def deprecated(value):
            if value.origin != "default":
                return func(value)

        return deprecated

    return decorator


# Turn an object into an object that can be used as an argument to @depends.
# The given object can be a literal value, a function that takes no argument,
# or, for convenience, a @depends function.
@template
@imports(_from="mozbuild.configure", _import="SandboxDependsFunction")
def dependable(obj):
    if isinstance(obj, SandboxDependsFunction):
        return obj
    return depends(when=True)(obj)


always = dependable(True)
never = dependable(False)


# Create a decorator that will only execute the body of a function
# if the passed function returns True when passed all positional
# arguments.
@template
def depends_tmpl(eval_args_fn, *args, **kwargs):
    if kwargs:
        assert len(kwargs) == 1
        when = kwargs["when"]
    else:
        when = None

    def decorator(func):
        @depends(*args, when=when)
        def wrapper(*args):
            if eval_args_fn(args):
                return func(*args)

        return wrapper

    return decorator


# Like @depends, but the decorated function is only called if one of the
# arguments it would be called with has a positive value (bool(value) is True)
@template
def depends_if(*args, **kwargs):
    return depends_tmpl(any, *args, **kwargs)


# Like @depends, but the decorated function is only called if all of the
# arguments it would be called with have a positive value.
@template
def depends_all(*args, **kwargs):
    return depends_tmpl(all, *args, **kwargs)


# A template providing a shorthand for setting a variable. The created
# option will only be settable with imply_option.
# It is expected that a project-specific moz.configure will call imply_option
# to set a value other than the default.
# If required, the set_as_define argument will additionally cause the variable
# to be set using set_define.
@template
def project_flag(env=None, set_as_define=False, **kwargs):
    if not env:
        configure_error("A project_flag must be passed a variable name to set.")

    if kwargs.get("nargs", 0) not in (0, 1):
        configure_error("A project_flag must be passed nargs={0,1}.")

    opt = option(env=env, possible_origins=("implied",), **kwargs)

    @depends(opt.option)
    def option_implementation(value):
        if value:
            if len(value) == 1:
                return value[0]
            elif len(value):
                return value
            return bool(value)

    set_config(env, option_implementation)
    if set_as_define:
        set_define(env, option_implementation)


@template
@imports(_from="mozbuild.configure.constants", _import="RaiseErrorOnUse")
def obsolete_config(name, *, replacement):
    set_config(name, RaiseErrorOnUse(f"{name} is obsolete. Use {replacement} instead."))


# Hacks related to old-configure
# ==============================


@dependable
def old_configure_assignments():
    return []


@template
def add_old_configure_assignment(var, value, when=None):
    var = dependable(var)
    value = dependable(value)

    @depends(old_configure_assignments, var, value, when=when)
    @imports(_from="mozbuild.shellutil", _import="quote")
    def add_assignment(assignments, var, value):
        if var is None or value is None:
            return
        if value is True:
            assignments.append((var, "1"))
        elif value is False:
            assignments.append((var, ""))
        else:
            if isinstance(value, (list, tuple)):
                value = quote(*value)
            assignments.append((var, str(value)))

[ Dauer der Verarbeitung: 0.28 Sekunden  (vorverarbeitet)  ]