зеркало из https://github.com/mozilla/gecko-dev.git
1181 строка
37 KiB
Python
1181 строка
37 KiB
Python
# -*- 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,
|
|
)
|
|
|
|
|
|
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")
|
|
|
|
|
|
# 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="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_msvc=False, 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.
|
|
os = os.replace("/", "_")
|
|
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 (allow_msvc and os == "windows-msvc"):
|
|
# windows-msvc is only opt-in for the caller of this function until
|
|
# full support in bug 1617793.
|
|
canonical_os = canonical_kernel = "WINNT"
|
|
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)
|
|
elif canonical_cpu == "aarch64" and canonical_os == "WINNT":
|
|
toolchain = "aarch64-windows-msvc"
|
|
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),
|
|
raw_cpu=cpu,
|
|
raw_os=os,
|
|
toolchain=toolchain,
|
|
vendor=vendor,
|
|
)
|
|
|
|
|
|
# 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",
|
|
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")
|
|
return check_cmd_output(shell, config_sub, triplet).strip()
|
|
|
|
|
|
@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-mingw32")
|
|
elif arch == "x86":
|
|
return split_triplet("i686-pc-mingw32")
|
|
|
|
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)
|
|
add_old_configure_assignment("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)
|
|
|
|
|
|
@depends(host)
|
|
def host_os_kernel_major_version(host):
|
|
versions = host.raw_os.split(".")
|
|
version = "".join(x for x in versions[0] if x.isdigit())
|
|
return version
|
|
|
|
|
|
set_config("HOST_MAJOR_VERSION", host_os_kernel_major_version)
|
|
|
|
# Autoconf needs these set
|
|
|
|
|
|
@depends(host)
|
|
def host_for_sub_configure(host):
|
|
return "--host=%s" % host.alias
|
|
|
|
|
|
@depends(target)
|
|
def target_for_sub_configure(target):
|
|
target_alias = target.alias
|
|
return "--target=%s" % target_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.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
|
|
|
|
|
|
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
|
|
|
|
|
|
set_define("XP_MACOSX", target_is_osx)
|
|
|
|
|
|
@depends(target)
|
|
def target_is_linux(target):
|
|
if target.kernel == "Linux":
|
|
return True
|
|
|
|
|
|
set_define("XP_LINUX", target_is_linux)
|
|
|
|
|
|
@depends(target)
|
|
def target_is_linux_or_wasi(target):
|
|
if target.kernel in ("Linux", "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)
|
|
add_old_configure_assignment("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
|
|
|
|
|
|
# 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, "--help")
|
|
@imports(_from="__builtin__", _import="open")
|
|
@imports("os")
|
|
@imports("re")
|
|
def milestone(build_env, build_project, version_path, _):
|
|
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])
|
|
|
|
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 = is_early_beta_or_earlier = 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 ""
|
|
|
|
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)
|
|
add_old_configure_assignment("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)
|
|
add_old_configure_assignment(
|
|
"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 wants to look at these.
|
|
add_old_configure_assignment("MOZILLA_VERSION", milestone.version)
|
|
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")))
|
|
|
|
|
|
# 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"),
|
|
)
|