diff options
Diffstat (limited to 'build/moz.configure/old.configure')
-rw-r--r-- | build/moz.configure/old.configure | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/build/moz.configure/old.configure b/build/moz.configure/old.configure new file mode 100644 index 0000000000..a37fd265a2 --- /dev/null +++ b/build/moz.configure/old.configure @@ -0,0 +1,394 @@ +# -*- 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/. + + +m4 = check_prog( + "M4", + ( + "gm4", + "m4", + ), + paths=prefer_mozillabuild_path, +) + + +@depends(mozconfig) +def prepare_mozconfig(mozconfig): + if mozconfig["path"]: + items = {} + for key, value in mozconfig["vars"]["added"].items(): + items[key] = (value, "added") + for key, (old, value) in mozconfig["vars"]["modified"].items(): + items[key] = (value, "modified") + for t in ("env", "vars"): + for key in mozconfig[t]["removed"].keys(): + items[key] = (None, "removed " + t) + return items + + +@depends("OLD_CONFIGURE", build_project) +def old_configure(old_configure, build_project): + if not old_configure: + die("The OLD_CONFIGURE environment variable must be set") + + # os.path.abspath in the sandbox will ensure forward slashes on Windows, + # which is actually necessary because this path actually ends up literally + # as $0, and backslashes there breaks autoconf's detection of the source + # directory. + old_configure = os.path.abspath(old_configure[0]) + if build_project == "js": + old_configure_dir = os.path.dirname(old_configure) + if not old_configure_dir.endswith("/js/src"): + old_configure = os.path.join( + old_configure_dir, "js", "src", os.path.basename(old_configure) + ) + return old_configure + + +@depends(prepare_mozconfig, old_configure_assignments) +@imports(_from="__builtin__", _import="open") +@imports(_from="__builtin__", _import="print") +@imports(_from="mozbuild.shellutil", _import="quote") +def prepare_configure(mozconfig, old_configure_assignments): + assignments = {} + + with open("old-configure.vars", "w") as out: + log.debug("Injecting the following to old-configure:") + + def inject(command): + print(command, file=out) # noqa Python 2vs3 + log.debug("| %s", command) + + if mozconfig: + inject("# start of mozconfig values") + for key, (value, action) in sorted(mozconfig.items()): + if action.startswith("removed "): + inject("unset %s # from %s" % (key, action[len("removed ") :])) + else: + inject("%s=%s # %s" % (key, quote(value), action)) + assignments[key] = value + + inject("# end of mozconfig values") + + for k, v in old_configure_assignments: + inject("%s=%s" % (k, quote(v))) + assignments[k] = v + + return namespace(assignments=assignments) + + +@template +def old_configure_options(*options): + for opt in options: + option(opt, nargs="*", help="Help missing for old configure options") + + @dependable + def all_options(): + return list(options) + + return depends( + host_for_sub_configure, target_for_sub_configure, all_options, *options + ) + + +@old_configure_options( + "--cache-file", + "--datadir", + "--enable-official-branding", + "--includedir", + "--libdir", + "--prefix", + "--with-branding", + "--with-distribution-id", + "--with-macbundlename-prefix", + "--x-includes", + "--x-libraries", +) +def prepare_configure_options(host, target, all_options, *options): + # old-configure only supports the options listed in @old_configure_options + # so we don't need to pass it every single option we've been passed. Only + # the ones that are not supported by python configure need to. + options = [ + value.format(name) + for name, value in zip(all_options, options) + if value.origin != "default" + ] + [host, target] + + return namespace(options=options, all_options=all_options) + + +@template +def old_configure_for(old_configure_path, extra_env=None): + if extra_env is None: + extra_env = dependable(None) + + @depends( + prepare_configure, + prepare_configure_options, + prefer_mozillabuild_path, + altered_path, + extra_env, + build_environment, + old_configure_path, + awk, + m4, + shell, + "--cache-file", + ) + @imports(_from="__builtin__", _import="compile") + @imports(_from="__builtin__", _import="open") + @imports(_from="__builtin__", _import="OSError") + @imports("glob") + @imports("itertools") + @imports("logging") + @imports("os") + @imports("re") + @imports("subprocess") + @imports("sys") + @imports(_from="mozbuild.shellutil", _import="quote") + @imports(_from="mozbuild.shellutil", _import="split") + @imports(_from="tempfile", _import="NamedTemporaryFile") + @imports(_from="subprocess", _import="CalledProcessError") + @imports(_from="__builtin__", _import="exec") + def old_configure( + prepare_configure, + prepare_configure_options, + prefer_mozillabuild_path, + altered_path, + extra_env, + build_env, + old_configure, + awk, + m4, + shell, + cache_file_option, + ): + if altered_path: + path = altered_path + else: + path = os.pathsep.join(prefer_mozillabuild_path) + + cxx = prepare_configure.assignments.get("CXX") + cc = prepare_configure.assignments.get("CC") + + if cc and cxx: + if cache_file_option: + config_cache = cache_file_option[0] + else: + config_cache = "config.cache" + + if os.path.exists(config_cache): + remove = False + with open(config_cache, "r") as cfg_cache: + cxx_pattern = re.compile( + r"^ac_cv_prog_CXX=\${ac_cv_prog_CXX='(.*)'}$" + ) + cc_pattern = re.compile(r"^ac_cv_prog_CC=\${ac_cv_prog_CC='(.*)'}$") + for line in cfg_cache: + m = cc_pattern.match(line) + if m and m.group(1) != cc: + remove = True + break + m = cxx_pattern.match(line) + if m and m.group(1) != cxx: + remove = True + break + + if remove: + log.info("invalidating config.cache") + os.remove(config_cache) + + refresh = True + if os.path.exists(old_configure): + mtime = os.path.getmtime(old_configure) + aclocal = os.path.join(build_env.topsrcdir, "build", "autoconf", "*.m4") + for input in itertools.chain( + ( + old_configure + ".in", + os.path.join(os.path.dirname(old_configure), "aclocal.m4"), + ), + glob.iglob(aclocal), + ): + if os.path.getmtime(input) > mtime: + break + else: + refresh = False + + if refresh: + autoconf = os.path.join( + build_env.topsrcdir, "build", "autoconf", "autoconf.sh" + ) + log.info("Refreshing %s with %s", old_configure, autoconf) + env = dict(os.environ) + env["M4"] = m4 + env["AWK"] = awk + env["AC_MACRODIR"] = os.path.join(build_env.topsrcdir, "build", "autoconf") + env["PATH"] = path + + try: + script = subprocess.check_output( + [ + shell, + autoconf, + "--localdir=%s" % os.path.dirname(old_configure), + old_configure + ".in", + ], + # Fix the working directory, so that when m4 is called, that + # includes of relative paths are deterministically resolved + # relative to the directory containing old-configure. + cwd=os.path.dirname(old_configure), + env=env, + ) + except CalledProcessError as exc: + die("autoconf exited with return code {}".format(exc.returncode)) + + if not script: + die( + "Generated old-configure is empty! Check that your autoconf 2.13 program works!" + ) + + # Make old-configure append to config.log, where we put our own log. + # This could be done with a m4 macro, but it's way easier this way + script = script.replace(b">./config.log", b">>${CONFIG_LOG=./config.log}") + + with NamedTemporaryFile( + mode="wb", + prefix=os.path.basename(old_configure), + dir=os.path.dirname(old_configure), + delete=False, + ) as fh: + fh.write(script) + + try: + os.rename(fh.name, old_configure) + except OSError: + try: + # Likely the file already existed (on Windows). Retry after removing it. + os.remove(old_configure) + os.rename(fh.name, old_configure) + except OSError as e: + die("Failed re-creating old-configure: %s" % e.message) + + cmd = [shell, old_configure] + prepare_configure_options.options + + env = dict(os.environ) + + # For debugging purpose, in case it's not what we'd expect. + log.debug("Running %s", quote(*cmd)) + + # Our logging goes to config.log, the same file old.configure uses. + # We can't share the handle on the file, so close it. + logger = logging.getLogger("moz.configure") + config_log = None + for handler in logger.handlers: + if isinstance(handler, logging.FileHandler): + config_log = handler + config_log.close() + logger.removeHandler(config_log) + env["CONFIG_LOG"] = config_log.baseFilename + log_size = os.path.getsize(config_log.baseFilename) + break + + env["PATH"] = path + + if extra_env: + env.update(extra_env) + + env["OLD_CONFIGURE_VARS"] = os.path.join( + build_env.topobjdir, "old-configure.vars" + ) + proc = subprocess.Popen( + cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env + ) + while True: + line = proc.stdout.readline() + if not line: + break + log.info(line.rstrip()) + + ret = proc.wait() + if ret: + with log.queue_debug(): + if config_log: + with open(config_log.baseFilename, "r") as fh: + fh.seek(log_size) + for line in fh: + log.debug(line.rstrip()) + log.error("old-configure failed") + sys.exit(ret) + + if config_log: + # Create a new handler in append mode + handler = logging.FileHandler(config_log.baseFilename, mode="a", delay=True) + handler.setFormatter(config_log.formatter) + logger.addHandler(handler) + + raw_config = { + "split": split, + "unique_list": unique_list, + } + with open("config.data", "r") as fh: + code = compile(fh.read(), "config.data", "exec") + exec(code, raw_config) + + # Ensure all the flags known to old-configure appear in the + # @old_configure_options above. + all_options = set(prepare_configure_options.all_options) + for flag in raw_config["flags"]: + if flag not in all_options: + die( + "Missing option in `@old_configure_options` in %s: %s", + __file__, + flag, + ) + + # If the code execution above fails, we want to keep the file around for + # debugging. + os.remove("config.data") + + return namespace( + **{ + c: [ + (k[1:-1], v[1:-1] if isinstance(v, str) else v) + for k, v in raw_config[c] + # Eventually we'll want to filter out all lowercase keys. (bug 1869127) + # For now, we only filter out the most problematic one that + # we know is unused. + if k != " target_cpu " + ] + for c in ("substs", "defines") + } + ) + + return old_configure + + +old_configure = old_configure_for(old_configure) +set_config("OLD_CONFIGURE_SUBSTS", old_configure.substs) +set_config("OLD_CONFIGURE_DEFINES", old_configure.defines) + + +# Assuming no other option is declared after this function, handle the +# env options that were injected by mozconfig_options by creating dummy +# Option instances and having the sandbox's CommandLineHelper handle +# them. We only do so for options that haven't been declared so far, +# which should be a proxy for the options that old-configure handles +# and that we don't know anything about. +@depends("--help") +@imports("__sandbox__") +@imports(_from="mozbuild.configure.options", _import="Option") +def remaining_mozconfig_options(_): + helper = __sandbox__._helper + for arg in list(helper): + if helper._origins[arg] != "mozconfig": + continue + name = arg.split("=", 1)[0] + if name.isupper() and name not in __sandbox__._options: + option = Option(env=name, nargs="*", help=name) + helper.handle(option) + + +# Please do not add anything after remaining_mozconfig_options() |