summaryrefslogtreecommitdiffstats
path: root/build/moz.configure/init.configure
diff options
context:
space:
mode:
Diffstat (limited to 'build/moz.configure/init.configure')
-rw-r--r--build/moz.configure/init.configure1307
1 files changed, 1307 insertions, 0 deletions
diff --git a/build/moz.configure/init.configure b/build/moz.configure/init.configure
new file mode 100644
index 0000000000..53bbc4203f
--- /dev/null
+++ b/build/moz.configure/init.configure
@@ -0,0 +1,1307 @@
+# -*- 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("util.configure")
+include("checks.configure")
+
+# Make `toolkit` available when toolkit/moz.configure is not included.
+toolkit = dependable(None)
+# Likewise with `bindgen_config_paths` when
+# build/moz.configure/bindgen.configure is not included.
+bindgen_config_paths = dependable(None)
+
+
+@depends("--help")
+def build_environment(_):
+ topobjdir = os.path.realpath(".")
+ topsrcdir = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".."))
+ dist = os.path.join(topobjdir, "dist")
+
+ return namespace(
+ topsrcdir=topsrcdir,
+ topobjdir=topobjdir,
+ dist=dist,
+ )
+
+
+@depends(build_environment)
+@imports(_import="json")
+@imports(_from="pathlib", _import="Path")
+def configure_cache(build_environment):
+ """
+ This cache is used to cache the results of compiler invocations
+ between different runs of configure and save them to the disk, which
+ results in a significant speed up of subsequent configure runs (15%-50%).
+
+ It is not currently thread safe because it is just a simple dictionary
+ wrapped in a dummy class (ConfigureCache). It could be improved to be
+ thread safe in the future, if we ever make configure parallelized, but
+ for now there is no advantage to doing so.
+ """
+
+ class ConfigureCache(dict):
+ pass
+
+ cache_file = Path(build_environment.topobjdir) / "configure.cache"
+ if cache_file.exists():
+ with cache_file.open() as f:
+ cache_data = json.load(f)
+ else:
+ cache_data = {}
+
+ cache = ConfigureCache(cache_data)
+ cache.version_checked_compilers = set()
+
+ return cache
+
+
+set_config("TOPSRCDIR", build_environment.topsrcdir)
+set_config("TOPOBJDIR", build_environment.topobjdir)
+set_config("DIST", build_environment.dist)
+
+add_old_configure_assignment("_topsrcdir", build_environment.topsrcdir)
+add_old_configure_assignment("_objdir", build_environment.topobjdir)
+add_old_configure_assignment("DIST", build_environment.dist)
+
+option(env="MOZ_AUTOMATION", help="Enable options for automated builds")
+set_config("MOZ_AUTOMATION", depends_if("MOZ_AUTOMATION")(lambda x: True))
+
+
+option(env="OLD_CONFIGURE", nargs=1, help="Path to the old configure script")
+
+option(env="MOZCONFIG", nargs=1, help="Mozconfig location")
+
+
+# Read user mozconfig
+# ==============================================================
+# Note: the dependency on --help is only there to always read the mozconfig,
+# even when --help is passed. Without this dependency, the function wouldn't
+# be called when --help is passed, and the mozconfig wouldn't be read.
+
+
+@depends("MOZCONFIG", "OLD_CONFIGURE", build_environment, "--help")
+@imports(_from="mozbuild.mozconfig", _import="MozconfigLoader")
+@imports(_from="mozboot.mozconfig", _import="find_mozconfig")
+@imports("os")
+def mozconfig(mozconfig, old_configure, build_env, help):
+ # Don't read the mozconfig for the js configure (yay backwards
+ # compatibility)
+ # While the long term goal is that js and top-level use the same configure
+ # and the same overall setup, including the possibility to use mozconfigs,
+ # figuring out what we want to do wrt mozconfig vs. command line and
+ # environment variable is not a clear-cut case, and it's more important to
+ # fix the immediate problem mozconfig causes to js developers by
+ # "temporarily" returning to the previous behavior of not loading the
+ # mozconfig for the js configure.
+ # Separately to the immediate problem for js developers, there is also the
+ # need to not load a mozconfig when running js configure as a subconfigure.
+ # Unfortunately, there is no direct way to tell whether the running
+ # configure is the js configure. The indirect way is to look at the
+ # OLD_CONFIGURE path, which points to js/src/old-configure.
+ # I expect we'll have figured things out for mozconfigs well before
+ # old-configure dies.
+ if (
+ old_configure
+ and os.path.dirname(os.path.abspath(old_configure[0])).endswith("/js/src")
+ or (mozconfig and mozconfig[0] == os.devnull)
+ ):
+ return {"path": None}
+
+ topsrcdir = build_env.topsrcdir
+ loader = MozconfigLoader(topsrcdir)
+ mozconfig = mozconfig[0] if mozconfig else None
+ mozconfig = find_mozconfig(topsrcdir, env={"MOZCONFIG": mozconfig})
+ mozconfig = loader.read_mozconfig(mozconfig)
+
+ return mozconfig
+
+
+set_config("MOZCONFIG", depends(mozconfig)(lambda m: m["path"]))
+
+
+# Mozilla-Build
+# ==============================================================
+option(env="MOZILLABUILD", nargs=1, help="Path to Mozilla Build (Windows-only)")
+
+option(env="CONFIG_SHELL", nargs=1, help="Path to a POSIX shell")
+
+# It feels dirty replicating this from python/mozbuild/mozbuild/mozconfig.py,
+# but the end goal being that the configure script would go away...
+
+
+@depends("CONFIG_SHELL", "MOZILLABUILD")
+@checking("for a shell")
+@imports("sys")
+@imports(_from="pathlib", _import="Path")
+def shell(value, mozillabuild):
+ if value:
+ return find_program(value[0])
+ shell = "sh"
+ if mozillabuild:
+ if (Path(mozillabuild[0]) / "msys2").exists():
+ shell = mozillabuild[0] + "/msys2/usr/bin/sh"
+ else:
+ shell = mozillabuild[0] + "/msys/bin/sh"
+ if sys.platform == "win32":
+ shell = shell + ".exe"
+ return find_program(shell)
+
+
+# This defines a reasonable shell for when running with --help.
+# If one was passed in the environment, though, fall back to that.
+@depends("--help", "CONFIG_SHELL")
+def help_shell(help, shell):
+ if help and not shell:
+ return "sh"
+
+
+shell = help_shell | shell
+
+
+# Python 3
+# ========
+@dependable
+@checking("for Python 3", callback=lambda x: "%s (%s)" % (x.path, x.str_version))
+@imports("sys")
+@imports(_from="mach.site", _import="PythonVirtualenv")
+@imports(_from="os.path", _import="realpath")
+def virtualenv_python3():
+ return namespace(
+ # sys.executable is currently not updated for in-process activations. However,
+ # sys.prefix is, so we can calculate the python executable's path from there.
+ path=normsep(PythonVirtualenv(realpath(sys.prefix)).python_path),
+ str_version=".".join(str(i) for i in sys.version_info[0:3]),
+ )
+
+
+set_config("PYTHON3", virtualenv_python3.path)
+set_config("PYTHON3_VERSION", virtualenv_python3.str_version)
+add_old_configure_assignment("PYTHON3", virtualenv_python3.path)
+
+
+# Inject mozconfig options
+# ==============================================================
+# All options defined above this point can't be injected in mozconfig_options
+# below, so collect them.
+
+
+@template
+def early_options():
+ @depends("--help")
+ @imports("__sandbox__")
+ def early_options(_):
+ return set(option.env for option in __sandbox__._options.values() if option.env)
+
+ return early_options
+
+
+early_options = early_options()
+
+
+@depends(mozconfig, early_options, "MOZ_AUTOMATION", "--help")
+# This gives access to the sandbox. Don't copy this blindly.
+@imports("__sandbox__")
+@imports("os")
+def mozconfig_options(mozconfig, early_options, automation, help):
+ if mozconfig["path"]:
+ if "MOZ_AUTOMATION_MOZCONFIG" in mozconfig["env"]["added"]:
+ if not automation:
+ log.error(
+ "%s directly or indirectly includes an in-tree " "mozconfig.",
+ mozconfig["path"],
+ )
+ log.error(
+ "In-tree mozconfigs make strong assumptions about "
+ "and are only meant to be used by Mozilla "
+ "automation."
+ )
+ die("Please don't use them.")
+ helper = __sandbox__._helper
+ log.info("Adding configure options from %s" % mozconfig["path"])
+ for arg in mozconfig["configure_args"]:
+ log.info(" %s" % arg)
+ # We could be using imply_option() here, but it has other
+ # contraints that don't really apply to the command-line
+ # emulation that mozconfig provides.
+ helper.add(arg, origin="mozconfig", args=helper._args)
+
+ def add(key, value):
+ if key.isupper():
+ arg = "%s=%s" % (key, value)
+ log.info(" %s" % arg)
+ if key not in early_options:
+ helper.add(arg, origin="mozconfig", args=helper._args)
+
+ for key, value in mozconfig["env"]["added"].items():
+ add(key, value)
+ os.environ[key] = value
+ for key, (_, value) in mozconfig["env"]["modified"].items():
+ add(key, value)
+ os.environ[key] = value
+ for key, value in mozconfig["vars"]["added"].items():
+ add(key, value)
+ for key, (_, value) in mozconfig["vars"]["modified"].items():
+ add(key, value)
+
+
+@depends(build_environment, "--help")
+@imports(_from="os.path", _import="exists")
+def js_package(build_env, help):
+ return not exists(os.path.join(build_env.topsrcdir, "browser"))
+
+
+# Source checkout and version control integration.
+# ================================================
+
+
+@depends(build_environment, "MOZ_AUTOMATION", js_package, "--help")
+@checking("for vcs source checkout")
+@imports("os")
+def vcs_checkout_type(build_env, automation, js_package, help):
+ if os.path.exists(os.path.join(build_env.topsrcdir, ".hg")):
+ return "hg"
+ elif os.path.exists(os.path.join(build_env.topsrcdir, ".git")):
+ return "git"
+ elif automation and not js_package and not help:
+ raise FatalCheckError(
+ "unable to resolve VCS type; must run "
+ "from a source checkout when MOZ_AUTOMATION "
+ "is set"
+ )
+
+
+# Resolve VCS binary for detected repository type.
+
+
+# TODO remove hg.exe once bug 1382940 addresses ambiguous executables case.
+hg = check_prog(
+ "HG",
+ (
+ "hg.exe",
+ "hg",
+ ),
+ allow_missing=True,
+ when=depends(vcs_checkout_type)(lambda x: x == "hg"),
+)
+git = check_prog(
+ "GIT",
+ ("git",),
+ allow_missing=True,
+ when=depends(vcs_checkout_type)(lambda x: x == "git"),
+)
+
+
+@depends_if(hg)
+@checking("for Mercurial version")
+@imports("os")
+@imports("re")
+def hg_version(hg):
+ # HGPLAIN in Mercurial 1.5+ forces stable output, regardless of set
+ # locale or encoding.
+ env = dict(os.environ)
+ env["HGPLAIN"] = "1"
+
+ out = check_cmd_output(hg, "--version", env=env)
+
+ match = re.search(r"Mercurial Distributed SCM \(version ([^\)]+)", out)
+
+ if not match:
+ raise FatalCheckError("unable to determine Mercurial version: %s" % out)
+
+ # The version string may be "unknown" for Mercurial run out of its own
+ # source checkout or for bad builds. But LooseVersion handles it.
+
+ return Version(match.group(1))
+
+
+# Resolve Mercurial config items so other checks have easy access.
+# Do NOT set this in the config because it may contain sensitive data
+# like API keys.
+
+
+@depends_all(build_environment, hg, hg_version)
+@imports("os")
+def hg_config(build_env, hg, version):
+ env = dict(os.environ)
+ env["HGPLAIN"] = "1"
+
+ # Warnings may get sent to stderr. But check_cmd_output() ignores
+ # stderr if exit code is 0. And the command should always succeed if
+ # `hg version` worked.
+ out = check_cmd_output(hg, "config", env=env, cwd=build_env.topsrcdir)
+
+ config = {}
+
+ for line in out.strip().splitlines():
+ key, value = [s.strip() for s in line.split("=", 1)]
+ config[key] = value
+
+ return config
+
+
+@depends_if(git)
+@checking("for Git version")
+@imports("re")
+def git_version(git):
+ out = check_cmd_output(git, "--version").rstrip()
+
+ match = re.search("git version (.*)$", out)
+
+ if not match:
+ raise FatalCheckError("unable to determine Git version: %s" % out)
+
+ return Version(match.group(1))
+
+
+# Only set VCS_CHECKOUT_TYPE if we resolved the VCS binary.
+# Require resolved VCS info when running in automation so automation's
+# environment is more well-defined.
+
+
+@depends(vcs_checkout_type, hg_version, git_version, "MOZ_AUTOMATION")
+def exposed_vcs_checkout_type(vcs_checkout_type, hg, git, automation):
+ if vcs_checkout_type == "hg":
+ if hg:
+ return "hg"
+
+ if automation:
+ raise FatalCheckError("could not resolve Mercurial binary info")
+
+ elif vcs_checkout_type == "git":
+ if git:
+ return "git"
+
+ if automation:
+ raise FatalCheckError("could not resolve Git binary info")
+ elif vcs_checkout_type:
+ raise FatalCheckError("unhandled VCS type: %s" % vcs_checkout_type)
+
+
+set_config("VCS_CHECKOUT_TYPE", exposed_vcs_checkout_type)
+
+# Obtain a Repository interface for the current VCS repository.
+
+
+@depends(build_environment, exposed_vcs_checkout_type, hg, git)
+@imports(_from="mozversioncontrol", _import="get_repository_object")
+def vcs_repository(build_env, vcs_checkout_type, hg, git):
+ if vcs_checkout_type == "hg":
+ return get_repository_object(build_env.topsrcdir, hg=hg)
+ elif vcs_checkout_type == "git":
+ return get_repository_object(build_env.topsrcdir, git=git)
+ elif vcs_checkout_type:
+ raise FatalCheckError("unhandled VCS type: %s" % vcs_checkout_type)
+
+
+@depends_if(vcs_repository)
+@checking("for sparse checkout")
+def vcs_sparse_checkout(repo):
+ return repo.sparse_checkout_present()
+
+
+set_config("VCS_SPARSE_CHECKOUT", vcs_sparse_checkout)
+
+# The application/project to build
+# ==============================================================
+option(
+ "--enable-application",
+ nargs=1,
+ env="MOZ_BUILD_APP",
+ help="Application to build. Same as --enable-project.",
+)
+
+
+@depends("--enable-application")
+def application(app):
+ if app:
+ return app
+
+
+imply_option("--enable-project", application)
+
+
+@depends(build_environment, js_package)
+def default_project(build_env, js_package):
+ if js_package or build_env.topobjdir.endswith("/js/src"):
+ return "js"
+ return "browser"
+
+
+option("--enable-project", nargs=1, default=default_project, help="Project to build")
+
+
+# Artifact builds
+# ==============================================================
+
+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)
+
+# Host and target systems
+# ==============================================================
+option("--host", nargs=1, help="Define the system type performing the build")
+
+option(
+ "--target",
+ nargs=1,
+ help="Define the system type where the resulting executables will be " "used",
+)
+
+
+@imports(_from="mozbuild.configure.constants", _import="Abi")
+@imports(_from="mozbuild.configure.constants", _import="CPU")
+@imports(_from="mozbuild.configure.constants", _import="CPU_bitness")
+@imports(_from="mozbuild.configure.constants", _import="Endianness")
+@imports(_from="mozbuild.configure.constants", _import="Kernel")
+@imports(_from="mozbuild.configure.constants", _import="OS")
+@imports(_from="__builtin__", _import="ValueError")
+def split_triplet(triplet, allow_wasi=False):
+ # The standard triplet is defined as
+ # CPU_TYPE-VENDOR-OPERATING_SYSTEM
+ # There is also a quartet form:
+ # CPU_TYPE-VENDOR-KERNEL-OPERATING_SYSTEM
+ # But we can consider the "KERNEL-OPERATING_SYSTEM" as one.
+ # Additionally, some may omit "unknown" when the vendor
+ # is not specified and emit
+ # CPU_TYPE-OPERATING_SYSTEM
+ vendor = "unknown"
+ parts = triplet.split("-", 2)
+ if len(parts) == 3:
+ cpu, vendor, os = parts
+ elif len(parts) == 2:
+ cpu, os = parts
+ else:
+ raise ValueError("Unexpected triplet string: %s" % triplet)
+
+ # Autoconf uses config.sub to validate and canonicalize those triplets,
+ # but the granularity of its results has never been satisfying to our
+ # use, so we've had our own, different, canonicalization. We've also
+ # historically not been very consistent with how we use the canonicalized
+ # values. Hopefully, this will help us make things better.
+ # The tests are inherited from our decades-old autoconf-based configure,
+ # which can probably be improved/cleaned up because they are based on a
+ # mix of uname and config.guess output, while we now only use the latter,
+ # which presumably has a cleaner and leaner output. Let's refine later.
+ raw_os = os = os.replace("/", "_")
+ abi = None
+ sub_configure_alias = triplet
+ if "android" in os:
+ canonical_os = "Android"
+ canonical_kernel = "Linux"
+ elif os.startswith("linux"):
+ canonical_os = "GNU"
+ canonical_kernel = "Linux"
+ elif os.startswith("kfreebsd") and os.endswith("-gnu"):
+ canonical_os = "GNU"
+ canonical_kernel = "kFreeBSD"
+ elif os.startswith("gnu"):
+ canonical_os = canonical_kernel = "GNU"
+ elif os.startswith("mingw") or os in ("windows-msvc", "windows-gnu"):
+ canonical_os = canonical_kernel = "WINNT"
+ if not os.startswith("mingw"):
+ if os == "windows-msvc":
+ abi = "msvc"
+ elif os == "windows-gnu":
+ abi = "mingw"
+ # Many things down the line are looking for the string "mingw32"
+ # until they are all fixed, we pretend that's the raw os we had
+ # in the first place, even when we didn't.
+ sub_configure_alias = sub_configure_alias[: -len(os)] + "mingw32"
+ raw_os = "mingw32"
+ elif os.startswith("darwin"):
+ canonical_kernel = "Darwin"
+ canonical_os = "OSX"
+ elif os.startswith("dragonfly"):
+ canonical_os = canonical_kernel = "DragonFly"
+ elif os.startswith("freebsd"):
+ canonical_os = canonical_kernel = "FreeBSD"
+ elif os.startswith("netbsd"):
+ canonical_os = canonical_kernel = "NetBSD"
+ elif os.startswith("openbsd"):
+ canonical_os = canonical_kernel = "OpenBSD"
+ elif os.startswith("solaris"):
+ canonical_os = canonical_kernel = "SunOS"
+ elif os.startswith("wasi") and allow_wasi:
+ canonical_os = canonical_kernel = "WASI"
+ else:
+ raise ValueError("Unknown OS: %s" % os)
+
+ # The CPU granularity is probably not enough. Moving more things from
+ # old-configure will tell us if we need more
+ if cpu.endswith("86") or (cpu.startswith("i") and "86" in cpu):
+ canonical_cpu = "x86"
+ endianness = "little"
+ elif cpu in ("x86_64", "ia64"):
+ canonical_cpu = cpu
+ endianness = "little"
+ elif cpu in ("s390", "s390x"):
+ canonical_cpu = cpu
+ endianness = "big"
+ elif cpu in ("powerpc64", "ppc64", "powerpc64le", "ppc64le"):
+ canonical_cpu = "ppc64"
+ endianness = "little" if "le" in cpu else "big"
+ elif cpu in ("powerpc", "ppc", "rs6000") or cpu.startswith("powerpc"):
+ canonical_cpu = "ppc"
+ endianness = "big"
+ elif cpu in ("Alpha", "alpha", "ALPHA"):
+ canonical_cpu = "Alpha"
+ endianness = "little"
+ elif cpu.startswith("hppa") or cpu == "parisc":
+ canonical_cpu = "hppa"
+ endianness = "big"
+ elif cpu.startswith("sparc64") or cpu.startswith("sparcv9"):
+ canonical_cpu = "sparc64"
+ endianness = "big"
+ elif cpu.startswith("sparc") or cpu == "sun4u":
+ canonical_cpu = "sparc"
+ endianness = "big"
+ elif cpu.startswith("arm"):
+ canonical_cpu = "arm"
+ endianness = "big" if cpu.startswith(("armeb", "armbe")) else "little"
+ elif cpu in ("m68k"):
+ canonical_cpu = "m68k"
+ endianness = "big"
+ elif cpu in ("mips", "mipsel"):
+ canonical_cpu = "mips32"
+ endianness = "little" if "el" in cpu else "big"
+ elif cpu in ("mips64", "mips64el"):
+ canonical_cpu = "mips64"
+ endianness = "little" if "el" in cpu else "big"
+ elif cpu.startswith("aarch64"):
+ canonical_cpu = "aarch64"
+ endianness = "little"
+ elif cpu in ("riscv64", "riscv64gc"):
+ canonical_cpu = "riscv64"
+ endianness = "little"
+ elif cpu.startswith("loongarch64"):
+ canonical_cpu = "loongarch64"
+ endianness = "little"
+ elif cpu == "sh4":
+ canonical_cpu = "sh4"
+ endianness = "little"
+ elif cpu == "wasm32" and allow_wasi:
+ canonical_cpu = "wasm32"
+ endianness = "little"
+ else:
+ raise ValueError("Unknown CPU type: %s" % cpu)
+
+ # Toolchains, most notably for cross compilation may use cpu-os
+ # prefixes. We need to be more specific about the LLVM target on Mac
+ # so cross-language LTO will work correctly.
+
+ if os.startswith("darwin"):
+ toolchain = "%s-apple-%s" % (cpu, os)
+ else:
+ toolchain = "%s-%s" % (cpu, os)
+
+ return namespace(
+ alias=triplet,
+ cpu=CPU(canonical_cpu),
+ bitness=CPU_bitness[canonical_cpu],
+ kernel=Kernel(canonical_kernel),
+ os=OS(canonical_os),
+ endianness=Endianness(endianness),
+ # For now, only report the Windows ABI.
+ abi=abi and Abi(abi),
+ raw_cpu=cpu,
+ raw_os=raw_os,
+ toolchain=toolchain,
+ vendor=vendor,
+ sub_configure_alias=sub_configure_alias,
+ )
+
+
+# This defines a fake target/host namespace for when running with --help
+# If either --host or --target is passed on the command line, then fall
+# back to the real deal.
+@depends("--help", "--host", "--target")
+def help_host_target(help, host, target):
+ if help and not host and not target:
+ return namespace(
+ alias="unknown-unknown-unknown",
+ cpu="unknown",
+ bitness="unknown",
+ kernel="unknown",
+ os="unknown",
+ endianness="unknown",
+ abi="unknown",
+ raw_cpu="unknown",
+ raw_os="unknown",
+ toolchain="unknown-unknown",
+ )
+
+
+def config_sub(shell, triplet):
+ config_sub = os.path.join(os.path.dirname(__file__), "..", "autoconf", "config.sub")
+ # Config.sub doesn't like the *-windows-msvc/*-windows-gnu triplets, so
+ # munge those before and after calling config.sub.
+ suffix = None
+ munging = {
+ "-windows-msvc": "-mingw32",
+ "-windows-gnu": "-mingw32",
+ }
+ for check_suffix, replacement in munging.items():
+ if triplet.endswith(check_suffix):
+ suffix = check_suffix
+ triplet = triplet[: -len(suffix)] + replacement
+ break
+ result = check_cmd_output(shell, config_sub, triplet).strip()
+ if suffix:
+ assert result.endswith(replacement)
+ result = result[: -len(replacement)] + suffix
+ return result
+
+
+@depends("--host", shell)
+@checking("for host system type", lambda h: h.alias)
+@imports("os")
+@imports("sys")
+@imports(_from="__builtin__", _import="ValueError")
+def real_host(value, shell):
+ if not value and sys.platform == "win32":
+ arch = os.environ.get("PROCESSOR_ARCHITEW6432") or os.environ.get(
+ "PROCESSOR_ARCHITECTURE"
+ )
+ if arch == "AMD64":
+ return split_triplet("x86_64-pc-windows-msvc")
+ elif arch == "x86":
+ return split_triplet("i686-pc-windows-msvc")
+
+ if not value:
+ config_guess = os.path.join(
+ os.path.dirname(__file__), "..", "autoconf", "config.guess"
+ )
+
+ # Ensure that config.guess is determining the host triplet, not the target
+ # triplet
+ env = os.environ.copy()
+ env.pop("CC_FOR_BUILD", None)
+ env.pop("HOST_CC", None)
+ env.pop("CC", None)
+
+ host = check_cmd_output(shell, config_guess, env=env).strip()
+ try:
+ return split_triplet(host)
+ except ValueError:
+ pass
+ else:
+ host = value[0]
+
+ host = config_sub(shell, host)
+
+ try:
+ return split_triplet(host)
+ except ValueError as e:
+ die(e)
+
+
+host = help_host_target | real_host
+
+
+@depends("--target", real_host, shell, "--enable-project", "--enable-application")
+@checking("for target system type", lambda t: t.alias)
+@imports(_from="__builtin__", _import="ValueError")
+def real_target(value, host, shell, project, application):
+ # Because --enable-project is implied by --enable-application, and
+ # implied options are not currently handled during --help, which is
+ # used get the build target in mozbuild.base, we manually check
+ # whether --enable-application was given, and fall back to
+ # --enable-project if not. Both can't be given contradictory values
+ # under normal circumstances, so it's fine.
+ if application:
+ project = application[0]
+ elif project:
+ project = project[0]
+ if not value:
+ if project == "mobile/android":
+ if host.raw_os == "mingw32":
+ log.warning(
+ "Building Firefox for Android on Windows is not fully "
+ "supported. See https://bugzilla.mozilla.org/show_bug.cgi?"
+ "id=1169873 for details."
+ )
+ return split_triplet("arm-unknown-linux-androideabi")
+ return host
+ # If --target was only given a cpu arch, expand it with the
+ # non-cpu part of the host. For mobile/android, expand it with
+ # unknown-linux-android.
+ target = value[0]
+ if "-" not in target:
+ if project == "mobile/android":
+ rest = "unknown-linux-android"
+ if target.startswith("arm"):
+ rest += "eabi"
+ else:
+ cpu, rest = host.alias.split("-", 1)
+ target = "-".join((target, rest))
+ try:
+ return split_triplet(target)
+ except ValueError:
+ pass
+
+ try:
+ return split_triplet(config_sub(shell, target), allow_wasi=(project == "js"))
+ except ValueError as e:
+ die(e)
+
+
+target = help_host_target | real_target
+
+
+@depends(host, target)
+@checking("whether cross compiling")
+def cross_compiling(host, target):
+ return host != target
+
+
+set_config("CROSS_COMPILE", cross_compiling)
+set_define("CROSS_COMPILE", cross_compiling)
+
+
+@depends(target)
+def have_64_bit(target):
+ if target.bitness == 64:
+ return True
+
+
+set_config("HAVE_64BIT_BUILD", have_64_bit)
+set_define("HAVE_64BIT_BUILD", have_64_bit)
+add_old_configure_assignment("HAVE_64BIT_BUILD", have_64_bit)
+
+# Some third-party code bases depend on this being set for big-endians.
+set_define(
+ "WORDS_BIGENDIAN", True, when=depends(target.endianness)(lambda e: e == "big")
+)
+
+
+# Autoconf needs these set
+
+
+@depends(host)
+def host_for_sub_configure(host):
+ return "--host=%s" % host.sub_configure_alias
+
+
+@depends(target)
+def target_for_sub_configure(target):
+ return "--target=%s" % target.sub_configure_alias
+
+
+# These variables are for compatibility with the current moz.builds and
+# old-configure. Eventually, we'll want to canonicalize better.
+@depends(target)
+def target_variables(target):
+ if target.kernel == "kFreeBSD":
+ os_target = "GNU/kFreeBSD"
+ os_arch = "GNU_kFreeBSD"
+ elif target.kernel == "Darwin" or (target.kernel == "Linux" and target.os == "GNU"):
+ os_target = target.kernel
+ os_arch = target.kernel
+ else:
+ os_target = target.os
+ os_arch = target.kernel
+
+ return namespace(
+ OS_TARGET=os_target,
+ OS_ARCH=os_arch,
+ INTEL_ARCHITECTURE=target.cpu in ("x86", "x86_64") or None,
+ )
+
+
+set_config("OS_TARGET", target_variables.OS_TARGET)
+add_old_configure_assignment("OS_TARGET", target_variables.OS_TARGET)
+set_config("OS_ARCH", target_variables.OS_ARCH)
+add_old_configure_assignment("OS_ARCH", target_variables.OS_ARCH)
+set_config("CPU_ARCH", target.cpu)
+add_old_configure_assignment("CPU_ARCH", target.cpu)
+set_config("INTEL_ARCHITECTURE", target_variables.INTEL_ARCHITECTURE)
+set_config("TARGET_CPU", target.raw_cpu)
+set_config("TARGET_OS", target.os)
+set_config("TARGET_RAW_OS", target.raw_os)
+set_config("TARGET_ENDIANNESS", target.endianness)
+
+
+@depends(host)
+def host_variables(host):
+ if host.kernel == "kFreeBSD":
+ os_arch = "GNU_kFreeBSD"
+ else:
+ os_arch = host.kernel
+ return namespace(
+ HOST_OS_ARCH=os_arch,
+ )
+
+
+set_config("HOST_CPU_ARCH", host.cpu)
+set_config("HOST_OS_ARCH", host_variables.HOST_OS_ARCH)
+add_old_configure_assignment("HOST_OS_ARCH", host_variables.HOST_OS_ARCH)
+set_config("HOST_ALIAS", host.alias)
+
+
+@depends(target)
+def target_is_windows(target):
+ if target.kernel == "WINNT":
+ return True
+
+
+@depends(host)
+def host_is_windows(host):
+ if host.kernel == "WINNT":
+ return True
+
+
+set_define("_WINDOWS", target_is_windows)
+set_define("WIN32", target_is_windows)
+set_define("XP_WIN", target_is_windows)
+
+
+@depends(target)
+def target_is_unix(target):
+ if target.kernel != "WINNT":
+ return True
+
+
+set_define("XP_UNIX", target_is_unix)
+
+
+@depends(target)
+def target_is_darwin(target):
+ if target.kernel == "Darwin":
+ return True
+
+
+set_define("XP_DARWIN", target_is_darwin)
+
+
+@depends(target)
+def target_is_osx(target):
+ if target.kernel == "Darwin" and target.os == "OSX":
+ return True
+
+
+@depends(host)
+def host_is_osx(host):
+ if host.os == "OSX":
+ return True
+
+
+set_define("XP_MACOSX", target_is_osx)
+
+
+@depends(target)
+def target_has_linux_kernel(target):
+ if target.kernel == "Linux":
+ return True
+
+
+set_define("XP_LINUX", target_has_linux_kernel)
+
+
+@depends(target)
+def target_is_linux_or_wasi(target):
+ if (target.kernel == "Linux" and target.os == "GNU") or target.kernel == "WASI":
+ return True
+
+
+@depends(target)
+def target_is_android(target):
+ if target.os == "Android":
+ return True
+
+
+set_define("ANDROID", target_is_android)
+
+
+@depends(target)
+def target_is_openbsd(target):
+ if target.kernel == "OpenBSD":
+ return True
+
+
+set_define("XP_OPENBSD", target_is_openbsd)
+
+
+@depends(target)
+def target_is_netbsd(target):
+ if target.kernel == "NetBSD":
+ return True
+
+
+set_define("XP_NETBSD", target_is_netbsd)
+
+
+@depends(target)
+def target_is_freebsd(target):
+ if target.kernel == "FreeBSD":
+ return True
+
+
+set_define("XP_FREEBSD", target_is_freebsd)
+
+
+@depends(target)
+def target_is_solaris(target):
+ if target.kernel == "SunOS":
+ return True
+
+
+set_define("XP_SOLARIS", target_is_solaris)
+
+
+@depends(target)
+def target_is_sparc(target):
+ if target.cpu == "sparc64":
+ return True
+
+
+set_define("SPARC64", target_is_sparc)
+
+
+@depends(target, when=target_is_android)
+def android_cpu_arch(target):
+ d = {
+ "aarch64": "arm64-v8a",
+ "arm": "armeabi-v7a",
+ "x86": "x86",
+ "x86_64": "x86_64",
+ }
+ if target.cpu not in d:
+ die(f"Cannot determine android_cpu_arch: unknown target.cpu: {target.cpu}")
+ return d[target.cpu]
+
+
+set_config("ANDROID_CPU_ARCH", android_cpu_arch)
+
+
+@depends("--enable-project", build_environment, "--help")
+@imports(_from="os.path", _import="exists")
+def include_project_configure(project, build_env, help):
+ if not project:
+ die("--enable-project is required.")
+
+ base_dir = build_env.topsrcdir
+ path = os.path.join(base_dir, project[0], "moz.configure")
+ if not exists(path):
+ die("Cannot find project %s", project[0])
+ return path
+
+
+@depends("--enable-project")
+def build_project(project):
+ return project[0]
+
+
+set_config("MOZ_BUILD_APP", build_project)
+set_define("MOZ_BUILD_APP", build_project)
+add_old_configure_assignment("MOZ_BUILD_APP", build_project)
+
+
+option(env="MOZILLA_OFFICIAL", help="Build an official release")
+
+
+@depends("MOZILLA_OFFICIAL")
+def mozilla_official(official):
+ if official:
+ return True
+
+
+set_config("MOZILLA_OFFICIAL", mozilla_official)
+set_define("MOZILLA_OFFICIAL", mozilla_official)
+add_old_configure_assignment("MOZILLA_OFFICIAL", mozilla_official)
+
+
+# Allow specifying custom paths to the version files used by the milestone() function below.
+option(
+ "--with-version-file-path",
+ nargs=1,
+ help="Specify a custom path to app version files instead of auto-detecting",
+ default=None,
+)
+
+
+@depends("--with-version-file-path")
+def version_path(path):
+ return path
+
+
+# Allow to easily build nightly with a release / beta configuration so that we
+# can have the same options we'd have on a release version.
+# This is useful for performance profiling, as there are things that we don't
+# enable in release (like the background hang monitor) that can affect
+# performance.
+option(
+ "--as-milestone",
+ help="Build with another milestone configuration (e.g., as release)",
+ choices=("early-beta", "late-beta", "release"),
+ default=None,
+)
+
+
+# set RELEASE_OR_BETA and NIGHTLY_BUILD variables depending on the cycle we're in
+# The logic works like this:
+# - if we have "a1" in GRE_MILESTONE, we're building Nightly (define NIGHTLY_BUILD)
+# - otherwise, if we have "a" in GRE_MILESTONE, we're building Nightly or Aurora
+# - otherwise, we're building Release/Beta (define RELEASE_OR_BETA)
+@depends(
+ build_environment,
+ build_project,
+ version_path,
+ "--as-milestone",
+ "--help",
+)
+@imports(_from="__builtin__", _import="open")
+@imports("os")
+@imports("re")
+def milestone(build_env, build_project, version_path, as_milestone, _):
+ versions = []
+ paths = ["config/milestone.txt"]
+ if build_project == "js":
+ paths = paths * 3
+ else:
+ paths += [
+ "browser/config/version.txt",
+ "browser/config/version_display.txt",
+ ]
+ if version_path:
+ version_path = version_path[0]
+ else:
+ version_path = os.path.join(build_project, "config")
+ for f in ("version.txt", "version_display.txt"):
+ f = os.path.join(version_path, f)
+ if not os.path.exists(os.path.join(build_env.topsrcdir, f)):
+ break
+ paths.append(f)
+
+ for p in paths:
+ with open(os.path.join(build_env.topsrcdir, p), "r") as fh:
+ content = fh.read().splitlines()
+ if not content:
+ die("Could not find a version number in {}".format(p))
+ versions.append(content[-1])
+
+ is_early_beta_or_earlier = None
+ if as_milestone:
+ if "a1" not in versions[0]:
+ # We could make this work with some effort
+ die("--as-milestone only works on nightly builds")
+ as_milestone = as_milestone[0]
+ as_milestone_flag = "" if as_milestone == "release" else "b1"
+ versions = [v.replace("a1", as_milestone_flag) for v in versions]
+ if as_milestone == "early-beta":
+ is_early_beta_or_earlier = True
+
+ milestone, firefox_version, firefox_version_display = versions[:3]
+
+ # version.txt content from the project directory if there is one, otherwise
+ # the firefox version.
+ app_version = versions[3] if len(versions) > 3 else firefox_version
+ # version_display.txt content from the project directory if there is one,
+ # otherwise version.txt content from the project directory, otherwise the
+ # firefox version for display.
+ app_version_display = versions[-1] if len(versions) > 3 else firefox_version_display
+
+ is_nightly = is_release_or_beta = None
+
+ if "a1" in milestone:
+ is_nightly = True
+ elif "a" not in milestone:
+ is_release_or_beta = True
+
+ major_version = milestone.split(".")[0]
+ m = re.search(r"([ab]\d+)", milestone)
+ ab_patch = m.group(1) if m else ""
+
+ if not as_milestone:
+ defines = os.path.join(build_env.topsrcdir, "build", "defines.sh")
+ with open(defines, "r") as fh:
+ for line in fh.read().splitlines():
+ line = line.strip()
+ if not line or line.startswith("#"):
+ continue
+ name, _, value = line.partition("=")
+ name = name.strip()
+ value = value.strip()
+ if name != "EARLY_BETA_OR_EARLIER":
+ die(
+ "Only the EARLY_BETA_OR_EARLIER variable can be set in build/defines.sh"
+ )
+ if value and any(x in app_version_display for x in "ab"):
+ is_early_beta_or_earlier = True
+
+ # Only expose the major version milestone in the UA string and hide the
+ # patch leve (bugs 572659 and 870868).
+ #
+ # Only expose major milestone and alpha version in the symbolversion
+ # string; as the name suggests, we use it for symbol versioning on Linux.
+ return namespace(
+ version=milestone,
+ uaversion="%s.0" % major_version,
+ symbolversion="%s%s" % (major_version, ab_patch),
+ is_nightly=is_nightly,
+ is_release_or_beta=is_release_or_beta,
+ is_early_beta_or_earlier=is_early_beta_or_earlier,
+ is_esr=app_version_display.endswith("esr") or None,
+ app_version=app_version,
+ app_version_display=app_version_display,
+ )
+
+
+set_config("GRE_MILESTONE", milestone.version)
+set_config("NIGHTLY_BUILD", milestone.is_nightly)
+set_define("NIGHTLY_BUILD", milestone.is_nightly)
+set_config("RELEASE_OR_BETA", milestone.is_release_or_beta)
+set_define("RELEASE_OR_BETA", milestone.is_release_or_beta)
+set_config("MOZ_ESR", milestone.is_esr)
+set_define("MOZ_ESR", milestone.is_esr)
+set_config("EARLY_BETA_OR_EARLIER", milestone.is_early_beta_or_earlier)
+set_define("EARLY_BETA_OR_EARLIER", milestone.is_early_beta_or_earlier)
+set_define("MOZILLA_VERSION", depends(milestone)(lambda m: '"%s"' % m.version))
+set_config("MOZILLA_VERSION", milestone.version)
+set_define("MOZILLA_VERSION_U", milestone.version)
+set_define("MOZILLA_UAVERSION", depends(milestone)(lambda m: '"%s"' % m.uaversion))
+set_config("MOZILLA_SYMBOLVERSION", milestone.symbolversion)
+# JS configure still want to look at this one.
+add_old_configure_assignment("MOZILLA_SYMBOLVERSION", milestone.symbolversion)
+
+set_config("MOZ_APP_VERSION", milestone.app_version)
+set_config("MOZ_APP_VERSION_DISPLAY", milestone.app_version_display)
+add_old_configure_assignment("MOZ_APP_VERSION", milestone.app_version)
+
+
+# The app update channel is 'default' when not supplied. The value is used in
+# the application's confvars.sh (and is made available to a project specific
+# moz.configure).
+option(
+ "--enable-update-channel",
+ nargs=1,
+ help="Select application update channel",
+ default="default",
+)
+
+
+@depends("--enable-update-channel")
+def update_channel(channel):
+ if not channel or channel[0] == "":
+ return "default"
+ return channel[0].lower()
+
+
+set_config("MOZ_UPDATE_CHANNEL", update_channel)
+set_define("MOZ_UPDATE_CHANNEL", update_channel)
+add_old_configure_assignment("MOZ_UPDATE_CHANNEL", update_channel)
+
+
+option(
+ env="MOZBUILD_STATE_PATH",
+ nargs=1,
+ help="Path to a persistent state directory for the build system "
+ "and related tools",
+)
+
+
+@depends("MOZBUILD_STATE_PATH", "--help")
+@imports("os")
+def mozbuild_state_path(path, _):
+ if path:
+ return normalize_path(path[0])
+ return normalize_path(os.path.expanduser(os.path.join("~", ".mozbuild")))
+
+
+@depends("MOZILLABUILD", shell, host_is_windows)
+@imports(_from="pathlib", _import="Path")
+def mozillabuild_bin_paths(mozillabuild, shell, host_is_windows):
+ paths = []
+ if not mozillabuild or not host_is_windows:
+ return paths
+ paths.append(os.path.dirname(shell))
+ paths.append(str(Path(mozillabuild[0]) / "bin"))
+ return paths
+
+
+@depends(mozillabuild_bin_paths)
+@imports("os")
+def prefer_mozillabuild_path(mozillabuild_bin_paths):
+ return mozillabuild_bin_paths + os.environ["PATH"].split(os.pathsep)
+
+
+# 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 and set_for_old_configure arguments
+# will additionally cause the variable to be set using set_define and
+# add_old_configure_assignment. util.configure would be an appropriate place for
+# this, but it uses add_old_configure_assignment, which is defined in this file.
+@template
+def project_flag(env=None, set_for_old_configure=False, set_as_define=False, **kwargs):
+
+ if not env:
+ configure_error("A project_flag must be passed a variable name to set.")
+
+ opt = option(env=env, possible_origins=("implied",), **kwargs)
+
+ @depends(opt.option)
+ def option_implementation(value):
+ if value:
+ if len(value):
+ return value
+ return bool(value)
+
+ set_config(env, option_implementation)
+ if set_as_define:
+ set_define(env, option_implementation)
+ if set_for_old_configure:
+ add_old_configure_assignment(env, option_implementation)
+
+
+# milestone.is_nightly corresponds to cases NIGHTLY_BUILD is set.
+
+
+@depends(milestone)
+def enabled_in_nightly(milestone):
+ return milestone.is_nightly
+
+
+# Branding
+# ==============================================================
+option(
+ "--with-app-basename",
+ env="MOZ_APP_BASENAME",
+ nargs=1,
+ help="Typically stays consistent for multiple branded versions of a "
+ 'given application (e.g. Aurora and Firefox both use "Firefox"), but '
+ "may vary for full rebrandings (e.g. Iceweasel). Used for "
+ 'application.ini\'s "Name" field, which controls profile location in '
+ 'the absence of a "Profile" field (see below), and various system '
+ "integration hooks (Unix remoting, Windows MessageWindow name, etc.",
+)
+
+
+@depends("--with-app-basename", target_is_android)
+def moz_app_basename(value, target_is_android):
+ if value:
+ return value[0]
+ if target_is_android:
+ return "Fennec"
+ return "Firefox"
+
+
+set_config(
+ "MOZ_APP_BASENAME",
+ moz_app_basename,
+ when=depends(build_project)(lambda p: p != "js"),
+)