1 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
2 # vim: set filetype=python:
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 include("util.configure")
8 include("checks.configure")
10 # Make `toolkit` available when toolkit/moz.configure is not included.
11 toolkit = dependable(None)
12 # Likewise with `bindgen_config_paths` when
13 # build/moz.configure/bindgen.configure is not included.
14 bindgen_config_paths = dependable(None)
18 def build_environment(_):
19 topobjdir = os.path.realpath(".")
20 topsrcdir = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".."))
21 dist = os.path.join(topobjdir, "dist")
30 set_config("TOPSRCDIR", build_environment.topsrcdir)
31 set_config("TOPOBJDIR", build_environment.topobjdir)
32 set_config("DIST", build_environment.dist)
34 add_old_configure_assignment("_topsrcdir", build_environment.topsrcdir)
35 add_old_configure_assignment("_objdir", build_environment.topobjdir)
36 add_old_configure_assignment("DIST", build_environment.dist)
38 option(env="MOZ_AUTOMATION", help="Enable options for automated builds")
39 set_config("MOZ_AUTOMATION", depends_if("MOZ_AUTOMATION")(lambda x: True))
42 option(env="OLD_CONFIGURE", nargs=1, help="Path to the old configure script")
44 option(env="MOZCONFIG", nargs=1, help="Mozconfig location")
48 # ==============================================================
49 # Note: the dependency on --help is only there to always read the mozconfig,
50 # even when --help is passed. Without this dependency, the function wouldn't
51 # be called when --help is passed, and the mozconfig wouldn't be read.
54 @depends("MOZCONFIG", "OLD_CONFIGURE", build_environment, "--help")
55 @imports(_from="mozbuild.mozconfig", _import="MozconfigLoader")
56 @imports(_from="mozboot.mozconfig", _import="find_mozconfig")
58 def mozconfig(mozconfig, old_configure, build_env, help):
59 # Don't read the mozconfig for the js configure (yay backwards
61 # While the long term goal is that js and top-level use the same configure
62 # and the same overall setup, including the possibility to use mozconfigs,
63 # figuring out what we want to do wrt mozconfig vs. command line and
64 # environment variable is not a clear-cut case, and it's more important to
65 # fix the immediate problem mozconfig causes to js developers by
66 # "temporarily" returning to the previous behavior of not loading the
67 # mozconfig for the js configure.
68 # Separately to the immediate problem for js developers, there is also the
69 # need to not load a mozconfig when running js configure as a subconfigure.
70 # Unfortunately, there is no direct way to tell whether the running
71 # configure is the js configure. The indirect way is to look at the
72 # OLD_CONFIGURE path, which points to js/src/old-configure.
73 # I expect we'll have figured things out for mozconfigs well before
77 and os.path.dirname(os.path.abspath(old_configure[0])).endswith("/js/src")
78 or (mozconfig and mozconfig[0] == os.devnull)
82 topsrcdir = build_env.topsrcdir
83 loader = MozconfigLoader(topsrcdir)
84 mozconfig = mozconfig[0] if mozconfig else None
85 mozconfig = find_mozconfig(topsrcdir, env={"MOZCONFIG": mozconfig})
86 mozconfig = loader.read_mozconfig(mozconfig)
91 set_config("MOZCONFIG", depends(mozconfig)(lambda m: m["path"]))
95 # ==============================================================
96 option(env="MOZILLABUILD", nargs=1, help="Path to Mozilla Build (Windows-only)")
98 option(env="CONFIG_SHELL", nargs=1, help="Path to a POSIX shell")
100 # It feels dirty replicating this from python/mozbuild/mozbuild/mozconfig.py,
101 # but the end goal being that the configure script would go away...
104 @depends("CONFIG_SHELL", "MOZILLABUILD")
105 @checking("for a shell")
107 @imports(_from="pathlib", _import="Path")
108 def shell(value, mozillabuild):
110 return find_program(value[0])
113 if (Path(mozillabuild[0]) / "msys2").exists():
114 shell = mozillabuild[0] + "/msys2/usr/bin/sh"
116 shell = mozillabuild[0] + "/msys/bin/sh"
117 if sys.platform == "win32":
118 shell = shell + ".exe"
119 return find_program(shell)
122 # This defines a reasonable shell for when running with --help.
123 # If one was passed in the environment, though, fall back to that.
124 @depends("--help", "CONFIG_SHELL")
125 def help_shell(help, shell):
126 if help and not shell:
130 shell = help_shell | shell
136 @checking("for Python 3", callback=lambda x: "%s (%s)" % (x.path, x.str_version))
138 @imports(_from="mach.site", _import="PythonVirtualenv")
139 @imports(_from="os.path", _import="realpath")
140 def virtualenv_python3():
142 # sys.executable is currently not updated for in-process activations. However,
143 # sys.prefix is, so we can calculate the python executable's path from there.
144 path=normsep(PythonVirtualenv(realpath(sys.prefix)).python_path),
145 str_version=".".join(str(i) for i in sys.version_info[0:3]),
149 set_config("PYTHON3", virtualenv_python3.path)
150 set_config("PYTHON3_VERSION", virtualenv_python3.str_version)
151 add_old_configure_assignment("PYTHON3", virtualenv_python3.path)
154 # Inject mozconfig options
155 # ==============================================================
156 # All options defined above this point can't be injected in mozconfig_options
157 # below, so collect them.
163 @imports("__sandbox__")
164 def early_options(_):
165 return set(option.env for option in __sandbox__._options.values() if option.env)
170 early_options = early_options()
173 @depends(mozconfig, early_options, "MOZ_AUTOMATION", "--help")
174 # This gives access to the sandbox. Don't copy this blindly.
175 @imports("__sandbox__")
177 def mozconfig_options(mozconfig, early_options, automation, help):
178 if mozconfig["path"]:
179 if "MOZ_AUTOMATION_MOZCONFIG" in mozconfig["env"]["added"]:
182 "%s directly or indirectly includes an in-tree " "mozconfig.",
186 "In-tree mozconfigs make strong assumptions about "
187 "and are only meant to be used by Mozilla "
190 die("Please don't use them.")
191 helper = __sandbox__._helper
192 log.info("Adding configure options from %s" % mozconfig["path"])
193 for arg in mozconfig["configure_args"]:
194 log.info(" %s" % arg)
195 # We could be using imply_option() here, but it has other
196 # contraints that don't really apply to the command-line
197 # emulation that mozconfig provides.
198 helper.add(arg, origin="mozconfig", args=helper._args)
202 arg = "%s=%s" % (key, value)
203 log.info(" %s" % arg)
204 if key not in early_options:
205 helper.add(arg, origin="mozconfig", args=helper._args)
207 for key, value in mozconfig["env"]["added"].items():
209 os.environ[key] = value
210 for key, (_, value) in mozconfig["env"]["modified"].items():
212 os.environ[key] = value
213 for key, value in mozconfig["vars"]["added"].items():
215 for key, (_, value) in mozconfig["vars"]["modified"].items():
219 @depends(build_environment, "--help")
220 @imports(_from="os.path", _import="exists")
221 def js_package(build_env, help):
222 return not exists(os.path.join(build_env.topsrcdir, "browser"))
225 # Source checkout and version control integration.
226 # ================================================
229 @depends(build_environment, "MOZ_AUTOMATION", js_package, "--help")
230 @checking("for vcs source checkout")
232 def vcs_checkout_type(build_env, automation, js_package, help):
233 if os.path.exists(os.path.join(build_env.topsrcdir, ".hg")):
235 elif os.path.exists(os.path.join(build_env.topsrcdir, ".git")):
237 elif automation and not js_package and not help:
238 raise FatalCheckError(
239 "unable to resolve VCS type; must run "
240 "from a source checkout when MOZ_AUTOMATION "
245 # Resolve VCS binary for detected repository type.
248 # TODO remove hg.exe once bug 1382940 addresses ambiguous executables case.
256 when=depends(vcs_checkout_type)(lambda x: x == "hg"),
262 when=depends(vcs_checkout_type)(lambda x: x == "git"),
267 @checking("for Mercurial version")
271 # HGPLAIN in Mercurial 1.5+ forces stable output, regardless of set
272 # locale or encoding.
273 env = dict(os.environ)
276 out = check_cmd_output(hg, "--version", env=env)
278 match = re.search(r"Mercurial Distributed SCM \(version ([^\)]+)", out)
281 raise FatalCheckError("unable to determine Mercurial version: %s" % out)
283 # The version string may be "unknown" for Mercurial run out of its own
284 # source checkout or for bad builds. But LooseVersion handles it.
286 return Version(match.group(1))
289 # Resolve Mercurial config items so other checks have easy access.
290 # Do NOT set this in the config because it may contain sensitive data
294 @depends_all(build_environment, hg, hg_version)
296 def hg_config(build_env, hg, version):
297 env = dict(os.environ)
300 # Warnings may get sent to stderr. But check_cmd_output() ignores
301 # stderr if exit code is 0. And the command should always succeed if
302 # `hg version` worked.
303 out = check_cmd_output(hg, "config", env=env, cwd=build_env.topsrcdir)
307 for line in out.strip().splitlines():
308 key, value = [s.strip() for s in line.split("=", 1)]
315 @checking("for Git version")
317 def git_version(git):
318 out = check_cmd_output(git, "--version").rstrip()
320 match = re.search("git version (.*)$", out)
323 raise FatalCheckError("unable to determine Git version: %s" % out)
325 return Version(match.group(1))
328 # Only set VCS_CHECKOUT_TYPE if we resolved the VCS binary.
329 # Require resolved VCS info when running in automation so automation's
330 # environment is more well-defined.
333 @depends(vcs_checkout_type, hg_version, git_version, "MOZ_AUTOMATION")
334 def exposed_vcs_checkout_type(vcs_checkout_type, hg, git, automation):
335 if vcs_checkout_type == "hg":
340 raise FatalCheckError("could not resolve Mercurial binary info")
342 elif vcs_checkout_type == "git":
347 raise FatalCheckError("could not resolve Git binary info")
348 elif vcs_checkout_type:
349 raise FatalCheckError("unhandled VCS type: %s" % vcs_checkout_type)
352 set_config("VCS_CHECKOUT_TYPE", exposed_vcs_checkout_type)
354 # Obtain a Repository interface for the current VCS repository.
357 @depends(build_environment, exposed_vcs_checkout_type, hg, git)
358 @imports(_from="mozversioncontrol", _import="get_repository_object")
359 def vcs_repository(build_env, vcs_checkout_type, hg, git):
360 if vcs_checkout_type == "hg":
361 return get_repository_object(build_env.topsrcdir, hg=hg)
362 elif vcs_checkout_type == "git":
363 return get_repository_object(build_env.topsrcdir, git=git)
364 elif vcs_checkout_type:
365 raise FatalCheckError("unhandled VCS type: %s" % vcs_checkout_type)
368 @depends_if(vcs_repository)
369 @checking("for sparse checkout")
370 def vcs_sparse_checkout(repo):
371 return repo.sparse_checkout_present()
374 set_config("VCS_SPARSE_CHECKOUT", vcs_sparse_checkout)
376 # The application/project to build
377 # ==============================================================
379 "--enable-application",
382 help="Application to build. Same as --enable-project.",
386 @depends("--enable-application")
387 def application(app):
392 imply_option("--enable-project", application)
395 @depends(build_environment, js_package)
396 def default_project(build_env, js_package):
397 if js_package or build_env.topobjdir.endswith("/js/src"):
402 option("--enable-project", nargs=1, default=default_project, help="Project to build")
405 # Host and target systems
406 # ==============================================================
407 option("--host", nargs=1, help="Define the system type performing the build")
412 help="Define the system type where the resulting executables will be " "used",
416 @imports(_from="mozbuild.configure.constants", _import="CPU")
417 @imports(_from="mozbuild.configure.constants", _import="CPU_bitness")
418 @imports(_from="mozbuild.configure.constants", _import="Endianness")
419 @imports(_from="mozbuild.configure.constants", _import="Kernel")
420 @imports(_from="mozbuild.configure.constants", _import="OS")
421 @imports(_from="__builtin__", _import="ValueError")
422 def split_triplet(triplet, allow_msvc=False, allow_wasi=False):
423 # The standard triplet is defined as
424 # CPU_TYPE-VENDOR-OPERATING_SYSTEM
425 # There is also a quartet form:
426 # CPU_TYPE-VENDOR-KERNEL-OPERATING_SYSTEM
427 # But we can consider the "KERNEL-OPERATING_SYSTEM" as one.
428 # Additionally, some may omit "unknown" when the vendor
429 # is not specified and emit
430 # CPU_TYPE-OPERATING_SYSTEM
432 parts = triplet.split("-", 2)
434 cpu, vendor, os = parts
435 elif len(parts) == 2:
438 raise ValueError("Unexpected triplet string: %s" % triplet)
440 # Autoconf uses config.sub to validate and canonicalize those triplets,
441 # but the granularity of its results has never been satisfying to our
442 # use, so we've had our own, different, canonicalization. We've also
443 # historically not been very consistent with how we use the canonicalized
444 # values. Hopefully, this will help us make things better.
445 # The tests are inherited from our decades-old autoconf-based configure,
446 # which can probably be improved/cleaned up because they are based on a
447 # mix of uname and config.guess output, while we now only use the latter,
448 # which presumably has a cleaner and leaner output. Let's refine later.
449 os = os.replace("/", "_")
451 canonical_os = "Android"
452 canonical_kernel = "Linux"
453 elif os.startswith("linux"):
455 canonical_kernel = "Linux"
456 elif os.startswith("kfreebsd") and os.endswith("-gnu"):
458 canonical_kernel = "kFreeBSD"
459 elif os.startswith("gnu"):
460 canonical_os = canonical_kernel = "GNU"
461 elif os.startswith("mingw") or (allow_msvc and os == "windows-msvc"):
462 # windows-msvc is only opt-in for the caller of this function until
463 # full support in bug 1617793.
464 canonical_os = canonical_kernel = "WINNT"
465 elif os.startswith("darwin"):
466 canonical_kernel = "Darwin"
468 elif os.startswith("dragonfly"):
469 canonical_os = canonical_kernel = "DragonFly"
470 elif os.startswith("freebsd"):
471 canonical_os = canonical_kernel = "FreeBSD"
472 elif os.startswith("netbsd"):
473 canonical_os = canonical_kernel = "NetBSD"
474 elif os.startswith("openbsd"):
475 canonical_os = canonical_kernel = "OpenBSD"
476 elif os.startswith("solaris"):
477 canonical_os = canonical_kernel = "SunOS"
478 elif os.startswith("wasi") and allow_wasi:
479 canonical_os = canonical_kernel = "WASI"
481 raise ValueError("Unknown OS: %s" % os)
483 # The CPU granularity is probably not enough. Moving more things from
484 # old-configure will tell us if we need more
485 if cpu.endswith("86") or (cpu.startswith("i") and "86" in cpu):
486 canonical_cpu = "x86"
487 endianness = "little"
488 elif cpu in ("x86_64", "ia64"):
490 endianness = "little"
491 elif cpu in ("s390", "s390x"):
494 elif cpu in ("powerpc64", "ppc64", "powerpc64le", "ppc64le"):
495 canonical_cpu = "ppc64"
496 endianness = "little" if "le" in cpu else "big"
497 elif cpu in ("powerpc", "ppc", "rs6000") or cpu.startswith("powerpc"):
498 canonical_cpu = "ppc"
500 elif cpu in ("Alpha", "alpha", "ALPHA"):
501 canonical_cpu = "Alpha"
502 endianness = "little"
503 elif cpu.startswith("hppa") or cpu == "parisc":
504 canonical_cpu = "hppa"
506 elif cpu.startswith("sparc64") or cpu.startswith("sparcv9"):
507 canonical_cpu = "sparc64"
509 elif cpu.startswith("sparc") or cpu == "sun4u":
510 canonical_cpu = "sparc"
512 elif cpu.startswith("arm"):
513 canonical_cpu = "arm"
514 endianness = "big" if cpu.startswith(("armeb", "armbe")) else "little"
515 elif cpu in ("m68k"):
516 canonical_cpu = "m68k"
518 elif cpu in ("mips", "mipsel"):
519 canonical_cpu = "mips32"
520 endianness = "little" if "el" in cpu else "big"
521 elif cpu in ("mips64", "mips64el"):
522 canonical_cpu = "mips64"
523 endianness = "little" if "el" in cpu else "big"
524 elif cpu.startswith("aarch64"):
525 canonical_cpu = "aarch64"
526 endianness = "little"
527 elif cpu in ("riscv64", "riscv64gc"):
528 canonical_cpu = "riscv64"
529 endianness = "little"
530 elif cpu.startswith("loongarch64"):
531 canonical_cpu = "loongarch64"
532 endianness = "little"
534 canonical_cpu = "sh4"
535 endianness = "little"
536 elif cpu == "wasm32" and allow_wasi:
537 canonical_cpu = "wasm32"
538 endianness = "little"
540 raise ValueError("Unknown CPU type: %s" % cpu)
542 # Toolchains, most notably for cross compilation may use cpu-os
543 # prefixes. We need to be more specific about the LLVM target on Mac
544 # so cross-language LTO will work correctly.
546 if os.startswith("darwin"):
547 toolchain = "%s-apple-%s" % (cpu, os)
548 elif canonical_cpu == "aarch64" and canonical_os == "WINNT":
549 toolchain = "aarch64-windows-msvc"
551 toolchain = "%s-%s" % (cpu, os)
555 cpu=CPU(canonical_cpu),
556 bitness=CPU_bitness[canonical_cpu],
557 kernel=Kernel(canonical_kernel),
559 endianness=Endianness(endianness),
567 # This defines a fake target/host namespace for when running with --help
568 # If either --host or --target is passed on the command line, then fall
569 # back to the real deal.
570 @depends("--help", "--host", "--target")
571 def help_host_target(help, host, target):
572 if help and not host and not target:
574 alias="unknown-unknown-unknown",
579 endianness="unknown",
582 toolchain="unknown-unknown",
586 def config_sub(shell, triplet):
587 config_sub = os.path.join(os.path.dirname(__file__), "..", "autoconf", "config.sub")
588 return check_cmd_output(shell, config_sub, triplet).strip()
591 @depends("--host", shell)
592 @checking("for host system type", lambda h: h.alias)
595 @imports(_from="__builtin__", _import="ValueError")
596 def real_host(value, shell):
597 if not value and sys.platform == "win32":
598 arch = os.environ.get("PROCESSOR_ARCHITEW6432") or os.environ.get(
599 "PROCESSOR_ARCHITECTURE"
602 return split_triplet("x86_64-pc-mingw32")
604 return split_triplet("i686-pc-mingw32")
607 config_guess = os.path.join(
608 os.path.dirname(__file__), "..", "autoconf", "config.guess"
611 # Ensure that config.guess is determining the host triplet, not the target
613 env = os.environ.copy()
614 env.pop("CC_FOR_BUILD", None)
615 env.pop("HOST_CC", None)
618 host = check_cmd_output(shell, config_guess, env=env).strip()
620 return split_triplet(host)
626 host = config_sub(shell, host)
629 return split_triplet(host)
630 except ValueError as e:
634 host = help_host_target | real_host
637 @depends("--target", real_host, shell, "--enable-project", "--enable-application")
638 @checking("for target system type", lambda t: t.alias)
639 @imports(_from="__builtin__", _import="ValueError")
640 def real_target(value, host, shell, project, application):
641 # Because --enable-project is implied by --enable-application, and
642 # implied options are not currently handled during --help, which is
643 # used get the build target in mozbuild.base, we manually check
644 # whether --enable-application was given, and fall back to
645 # --enable-project if not. Both can't be given contradictory values
646 # under normal circumstances, so it's fine.
648 project = application[0]
652 if project == "mobile/android":
653 if host.raw_os == "mingw32":
655 "Building Firefox for Android on Windows is not fully "
656 "supported. See https://bugzilla.mozilla.org/show_bug.cgi?"
657 "id=1169873 for details."
659 return split_triplet("arm-unknown-linux-androideabi")
661 # If --target was only given a cpu arch, expand it with the
662 # non-cpu part of the host. For mobile/android, expand it with
663 # unknown-linux-android.
665 if "-" not in target:
666 if project == "mobile/android":
667 rest = "unknown-linux-android"
668 if target.startswith("arm"):
671 cpu, rest = host.alias.split("-", 1)
672 target = "-".join((target, rest))
674 return split_triplet(target)
679 return split_triplet(config_sub(shell, target), allow_wasi=(project == "js"))
680 except ValueError as e:
684 target = help_host_target | real_target
687 @depends(host, target)
688 @checking("whether cross compiling")
689 def cross_compiling(host, target):
690 return host != target
693 set_config("CROSS_COMPILE", cross_compiling)
694 set_define("CROSS_COMPILE", cross_compiling)
695 add_old_configure_assignment("CROSS_COMPILE", cross_compiling)
699 def have_64_bit(target):
700 if target.bitness == 64:
704 set_config("HAVE_64BIT_BUILD", have_64_bit)
705 set_define("HAVE_64BIT_BUILD", have_64_bit)
706 add_old_configure_assignment("HAVE_64BIT_BUILD", have_64_bit)
710 def host_os_kernel_major_version(host):
711 versions = host.raw_os.split(".")
712 version = "".join(x for x in versions[0] if x.isdigit())
716 set_config("HOST_MAJOR_VERSION", host_os_kernel_major_version)
718 # Autoconf needs these set
722 def host_for_sub_configure(host):
723 return "--host=%s" % host.alias
727 def target_for_sub_configure(target):
728 target_alias = target.alias
729 return "--target=%s" % target_alias
732 # These variables are for compatibility with the current moz.builds and
733 # old-configure. Eventually, we'll want to canonicalize better.
735 def target_variables(target):
736 if target.kernel == "kFreeBSD":
737 os_target = "GNU/kFreeBSD"
738 os_arch = "GNU_kFreeBSD"
739 elif target.kernel == "Darwin" or (target.kernel == "Linux" and target.os == "GNU"):
740 os_target = target.kernel
741 os_arch = target.kernel
743 os_target = target.os
744 os_arch = target.kernel
749 INTEL_ARCHITECTURE=target.cpu in ("x86", "x86_64") or None,
753 set_config("OS_TARGET", target_variables.OS_TARGET)
754 add_old_configure_assignment("OS_TARGET", target_variables.OS_TARGET)
755 set_config("OS_ARCH", target_variables.OS_ARCH)
756 add_old_configure_assignment("OS_ARCH", target_variables.OS_ARCH)
757 set_config("CPU_ARCH", target.cpu)
758 add_old_configure_assignment("CPU_ARCH", target.cpu)
759 set_config("INTEL_ARCHITECTURE", target_variables.INTEL_ARCHITECTURE)
760 set_config("TARGET_CPU", target.raw_cpu)
761 set_config("TARGET_OS", target.raw_os)
762 set_config("TARGET_ENDIANNESS", target.endianness)
766 def host_variables(host):
767 if host.kernel == "kFreeBSD":
768 os_arch = "GNU_kFreeBSD"
770 os_arch = host.kernel
772 HOST_OS_ARCH=os_arch,
776 set_config("HOST_CPU_ARCH", host.cpu)
777 set_config("HOST_OS_ARCH", host_variables.HOST_OS_ARCH)
778 add_old_configure_assignment("HOST_OS_ARCH", host_variables.HOST_OS_ARCH)
779 set_config("HOST_ALIAS", host.alias)
783 def target_is_windows(target):
784 if target.kernel == "WINNT":
788 set_define("_WINDOWS", target_is_windows)
789 set_define("WIN32", target_is_windows)
790 set_define("XP_WIN", target_is_windows)
794 def target_is_unix(target):
795 if target.kernel != "WINNT":
799 set_define("XP_UNIX", target_is_unix)
803 def target_is_darwin(target):
804 if target.kernel == "Darwin":
808 set_define("XP_DARWIN", target_is_darwin)
812 def target_is_osx(target):
813 if target.kernel == "Darwin" and target.os == "OSX":
817 set_define("XP_MACOSX", target_is_osx)
821 def target_is_linux(target):
822 if target.kernel == "Linux":
826 set_define("XP_LINUX", target_is_linux)
830 def target_is_linux_or_wasi(target):
831 if target.kernel in ("Linux", "WASI"):
836 def target_is_android(target):
837 if target.os == "Android":
841 set_define("ANDROID", target_is_android)
845 def target_is_openbsd(target):
846 if target.kernel == "OpenBSD":
850 set_define("XP_OPENBSD", target_is_openbsd)
854 def target_is_netbsd(target):
855 if target.kernel == "NetBSD":
859 set_define("XP_NETBSD", target_is_netbsd)
863 def target_is_freebsd(target):
864 if target.kernel == "FreeBSD":
868 set_define("XP_FREEBSD", target_is_freebsd)
872 def target_is_solaris(target):
873 if target.kernel == "SunOS":
877 set_define("XP_SOLARIS", target_is_solaris)
881 def target_is_sparc(target):
882 if target.cpu == "sparc64":
886 set_define("SPARC64", target_is_sparc)
889 @depends(target, when=target_is_android)
890 def android_cpu_arch(target):
892 "aarch64": "arm64-v8a",
893 "arm": "armeabi-v7a",
897 if target.cpu not in d:
898 die(f"Cannot determine android_cpu_arch: unknown target.cpu: {target.cpu}")
902 set_config("ANDROID_CPU_ARCH", android_cpu_arch)
903 add_old_configure_assignment("ANDROID_CPU_ARCH", android_cpu_arch)
906 @depends("--enable-project", build_environment, "--help")
907 @imports(_from="os.path", _import="exists")
908 def include_project_configure(project, build_env, help):
910 die("--enable-project is required.")
912 base_dir = build_env.topsrcdir
913 path = os.path.join(base_dir, project[0], "moz.configure")
915 die("Cannot find project %s", project[0])
919 @depends("--enable-project")
920 def build_project(project):
924 set_config("MOZ_BUILD_APP", build_project)
925 set_define("MOZ_BUILD_APP", build_project)
926 add_old_configure_assignment("MOZ_BUILD_APP", build_project)
929 option(env="MOZILLA_OFFICIAL", help="Build an official release")
932 @depends("MOZILLA_OFFICIAL")
933 def mozilla_official(official):
938 set_config("MOZILLA_OFFICIAL", mozilla_official)
939 set_define("MOZILLA_OFFICIAL", mozilla_official)
940 add_old_configure_assignment("MOZILLA_OFFICIAL", mozilla_official)
943 # Allow specifying custom paths to the version files used by the milestone() function below.
945 "--with-version-file-path",
947 help="Specify a custom path to app version files instead of auto-detecting",
952 @depends("--with-version-file-path")
953 def version_path(path):
957 # set RELEASE_OR_BETA and NIGHTLY_BUILD variables depending on the cycle we're in
958 # The logic works like this:
959 # - if we have "a1" in GRE_MILESTONE, we're building Nightly (define NIGHTLY_BUILD)
960 # - otherwise, if we have "a" in GRE_MILESTONE, we're building Nightly or Aurora
961 # - otherwise, we're building Release/Beta (define RELEASE_OR_BETA)
962 @depends(build_environment, build_project, version_path, "--help")
963 @imports(_from="__builtin__", _import="open")
966 def milestone(build_env, build_project, version_path, _):
968 paths = ["config/milestone.txt"]
969 if build_project == "js":
973 "browser/config/version.txt",
974 "browser/config/version_display.txt",
977 version_path = version_path[0]
979 version_path = os.path.join(build_project, "config")
980 for f in ("version.txt", "version_display.txt"):
981 f = os.path.join(version_path, f)
982 if not os.path.exists(os.path.join(build_env.topsrcdir, f)):
987 with open(os.path.join(build_env.topsrcdir, p), "r") as fh:
988 content = fh.read().splitlines()
990 die("Could not find a version number in {}".format(p))
991 versions.append(content[-1])
993 milestone, firefox_version, firefox_version_display = versions[:3]
995 # version.txt content from the project directory if there is one, otherwise
996 # the firefox version.
997 app_version = versions[3] if len(versions) > 3 else firefox_version
998 # version_display.txt content from the project directory if there is one,
999 # otherwise version.txt content from the project directory, otherwise the
1000 # firefox version for display.
1001 app_version_display = versions[-1] if len(versions) > 3 else firefox_version_display
1003 is_nightly = is_release_or_beta = is_early_beta_or_earlier = None
1005 if "a1" in milestone:
1007 elif "a" not in milestone:
1008 is_release_or_beta = True
1010 major_version = milestone.split(".")[0]
1011 m = re.search(r"([ab]\d+)", milestone)
1012 ab_patch = m.group(1) if m else ""
1014 defines = os.path.join(build_env.topsrcdir, "build", "defines.sh")
1015 with open(defines, "r") as fh:
1016 for line in fh.read().splitlines():
1018 if not line or line.startswith("#"):
1020 name, _, value = line.partition("=")
1022 value = value.strip()
1023 if name != "EARLY_BETA_OR_EARLIER":
1025 "Only the EARLY_BETA_OR_EARLIER variable can be set in build/defines.sh"
1027 if value and any(x in app_version_display for x in "ab"):
1028 is_early_beta_or_earlier = True
1030 # Only expose the major version milestone in the UA string and hide the
1031 # patch leve (bugs 572659 and 870868).
1033 # Only expose major milestone and alpha version in the symbolversion
1034 # string; as the name suggests, we use it for symbol versioning on Linux.
1037 uaversion="%s.0" % major_version,
1038 symbolversion="%s%s" % (major_version, ab_patch),
1039 is_nightly=is_nightly,
1040 is_release_or_beta=is_release_or_beta,
1041 is_early_beta_or_earlier=is_early_beta_or_earlier,
1042 is_esr=app_version_display.endswith("esr") or None,
1043 app_version=app_version,
1044 app_version_display=app_version_display,
1048 set_config("GRE_MILESTONE", milestone.version)
1049 set_config("NIGHTLY_BUILD", milestone.is_nightly)
1050 set_define("NIGHTLY_BUILD", milestone.is_nightly)
1051 set_config("RELEASE_OR_BETA", milestone.is_release_or_beta)
1052 set_define("RELEASE_OR_BETA", milestone.is_release_or_beta)
1053 add_old_configure_assignment("RELEASE_OR_BETA", milestone.is_release_or_beta)
1054 set_config("MOZ_ESR", milestone.is_esr)
1055 set_define("MOZ_ESR", milestone.is_esr)
1056 set_config("EARLY_BETA_OR_EARLIER", milestone.is_early_beta_or_earlier)
1057 set_define("EARLY_BETA_OR_EARLIER", milestone.is_early_beta_or_earlier)
1058 add_old_configure_assignment(
1059 "EARLY_BETA_OR_EARLIER", milestone.is_early_beta_or_earlier
1061 set_define("MOZILLA_VERSION", depends(milestone)(lambda m: '"%s"' % m.version))
1062 set_config("MOZILLA_VERSION", milestone.version)
1063 set_define("MOZILLA_VERSION_U", milestone.version)
1064 set_define("MOZILLA_UAVERSION", depends(milestone)(lambda m: '"%s"' % m.uaversion))
1065 set_config("MOZILLA_SYMBOLVERSION", milestone.symbolversion)
1066 # JS configure still wants to look at these.
1067 add_old_configure_assignment("MOZILLA_VERSION", milestone.version)
1068 add_old_configure_assignment("MOZILLA_SYMBOLVERSION", milestone.symbolversion)
1070 set_config("MOZ_APP_VERSION", milestone.app_version)
1071 set_config("MOZ_APP_VERSION_DISPLAY", milestone.app_version_display)
1072 add_old_configure_assignment("MOZ_APP_VERSION", milestone.app_version)
1075 # The app update channel is 'default' when not supplied. The value is used in
1076 # the application's confvars.sh (and is made available to a project specific
1079 "--enable-update-channel",
1081 help="Select application update channel",
1086 @depends("--enable-update-channel")
1087 def update_channel(channel):
1088 if not channel or channel[0] == "":
1090 return channel[0].lower()
1093 set_config("MOZ_UPDATE_CHANNEL", update_channel)
1094 set_define("MOZ_UPDATE_CHANNEL", update_channel)
1095 add_old_configure_assignment("MOZ_UPDATE_CHANNEL", update_channel)
1099 env="MOZBUILD_STATE_PATH",
1101 help="Path to a persistent state directory for the build system "
1102 "and related tools",
1106 @depends("MOZBUILD_STATE_PATH", "--help")
1108 def mozbuild_state_path(path, _):
1110 return normalize_path(path[0])
1111 return normalize_path(os.path.expanduser(os.path.join("~", ".mozbuild")))
1114 # A template providing a shorthand for setting a variable. The created
1115 # option will only be settable with imply_option.
1116 # It is expected that a project-specific moz.configure will call imply_option
1117 # to set a value other than the default.
1118 # If required, the set_as_define and set_for_old_configure arguments
1119 # will additionally cause the variable to be set using set_define and
1120 # add_old_configure_assignment. util.configure would be an appropriate place for
1121 # this, but it uses add_old_configure_assignment, which is defined in this file.
1123 def project_flag(env=None, set_for_old_configure=False, set_as_define=False, **kwargs):
1126 configure_error("A project_flag must be passed a variable name to set.")
1128 opt = option(env=env, possible_origins=("implied",), **kwargs)
1130 @depends(opt.option)
1131 def option_implementation(value):
1137 set_config(env, option_implementation)
1139 set_define(env, option_implementation)
1140 if set_for_old_configure:
1141 add_old_configure_assignment(env, option_implementation)
1144 # milestone.is_nightly corresponds to cases NIGHTLY_BUILD is set.
1148 def enabled_in_nightly(milestone):
1149 return milestone.is_nightly
1153 # ==============================================================
1155 "--with-app-basename",
1156 env="MOZ_APP_BASENAME",
1158 help="Typically stays consistent for multiple branded versions of a "
1159 'given application (e.g. Aurora and Firefox both use "Firefox"), but '
1160 "may vary for full rebrandings (e.g. Iceweasel). Used for "
1161 'application.ini\'s "Name" field, which controls profile location in '
1162 'the absence of a "Profile" field (see below), and various system '
1163 "integration hooks (Unix remoting, Windows MessageWindow name, etc.",
1167 @depends("--with-app-basename", target_is_android)
1168 def moz_app_basename(value, target_is_android):
1171 if target_is_android:
1179 when=depends(build_project)(lambda p: p != "js"),