diff options
Diffstat (limited to 'python/mozbuild/mozbuild/config_status.py')
-rw-r--r-- | python/mozbuild/mozbuild/config_status.py | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/config_status.py b/python/mozbuild/mozbuild/config_status.py new file mode 100644 index 0000000000..8e8a7f625b --- /dev/null +++ b/python/mozbuild/mozbuild/config_status.py @@ -0,0 +1,184 @@ +# 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/. + +# Combined with build/autoconf/config.status.m4, ConfigStatus is an almost +# drop-in replacement for autoconf 2.13's config.status, with features +# borrowed from autoconf > 2.5, and additional features. + +import logging +import os +import sys +import time +from argparse import ArgumentParser +from itertools import chain + +from mach.logging import LoggingManager + +from mozbuild.backend import backends, get_backend_class +from mozbuild.backend.configenvironment import ConfigEnvironment +from mozbuild.base import MachCommandConditions +from mozbuild.frontend.emitter import TreeMetadataEmitter +from mozbuild.frontend.reader import BuildReader +from mozbuild.mozinfo import write_mozinfo +from mozbuild.util import FileAvoidWrite, process_time + +log_manager = LoggingManager() + + +ANDROID_IDE_ADVERTISEMENT = """ +============= +ADVERTISEMENT + +You are building GeckoView. After your build completes, you can open +the top source directory in Android Studio directly and build using Gradle. +See the documentation at + +https://firefox-source-docs.mozilla.org/mobile/android/geckoview/contributor/geckoview-quick-start.html#build-using-android-studio +============= +""".strip() + + +def config_status( + topobjdir=".", + topsrcdir=".", + defines=None, + substs=None, + source=None, + mozconfig=None, + args=sys.argv[1:], +): + """Main function, providing config.status functionality. + + Contrary to config.status, it doesn't use CONFIG_FILES or CONFIG_HEADERS + variables. + + Without the -n option, this program acts as config.status and considers + the current directory as the top object directory, even when config.status + is in a different directory. It will, however, treat the directory + containing config.status as the top object directory with the -n option. + + The options to this function are passed when creating the + ConfigEnvironment. These lists, as well as the actual wrapper script + around this function, are meant to be generated by configure. + See build/autoconf/config.status.m4. + """ + + if "CONFIG_FILES" in os.environ: + raise Exception( + "Using the CONFIG_FILES environment variable is not " "supported." + ) + if "CONFIG_HEADERS" in os.environ: + raise Exception( + "Using the CONFIG_HEADERS environment variable is not " "supported." + ) + + if not os.path.isabs(topsrcdir): + raise Exception( + "topsrcdir must be defined as an absolute directory: " "%s" % topsrcdir + ) + + default_backends = ["RecursiveMake"] + default_backends = (substs or {}).get("BUILD_BACKENDS", ["RecursiveMake"]) + + parser = ArgumentParser() + parser.add_argument( + "-v", + "--verbose", + dest="verbose", + action="store_true", + help="display verbose output", + ) + parser.add_argument( + "-n", + dest="not_topobjdir", + action="store_true", + help="do not consider current directory as top object directory", + ) + parser.add_argument( + "-d", "--diff", action="store_true", help="print diffs of changed files." + ) + parser.add_argument( + "-b", + "--backend", + nargs="+", + choices=sorted(backends), + default=default_backends, + help="what backend to build (default: %s)." % " ".join(default_backends), + ) + parser.add_argument( + "--dry-run", action="store_true", help="do everything except writing files out." + ) + options = parser.parse_args(args) + + # Without -n, the current directory is meant to be the top object directory + if not options.not_topobjdir: + topobjdir = os.path.realpath(".") + + env = ConfigEnvironment( + topsrcdir, + topobjdir, + defines=defines, + substs=substs, + source=source, + mozconfig=mozconfig, + ) + + with FileAvoidWrite(os.path.join(topobjdir, "mozinfo.json")) as f: + write_mozinfo(f, env, os.environ) + + cpu_start = process_time() + time_start = time.monotonic() + + # Make appropriate backend instances, defaulting to RecursiveMakeBackend, + # or what is in BUILD_BACKENDS. + selected_backends = [get_backend_class(b)(env) for b in options.backend] + + if options.dry_run: + for b in selected_backends: + b.dry_run = True + + reader = BuildReader(env) + emitter = TreeMetadataEmitter(env) + # This won't actually do anything because of the magic of generators. + definitions = emitter.emit(reader.read_topsrcdir()) + + log_level = logging.DEBUG if options.verbose else logging.INFO + log_manager.add_terminal_logging(level=log_level) + log_manager.enable_unstructured() + + print("Reticulating splines...", file=sys.stderr) + if len(selected_backends) > 1: + definitions = list(definitions) + + for the_backend in selected_backends: + the_backend.consume(definitions) + + execution_time = 0.0 + for obj in chain((reader, emitter), selected_backends): + summary = obj.summary() + print(summary, file=sys.stderr) + execution_time += summary.execution_time + if hasattr(obj, "gyp_summary"): + summary = obj.gyp_summary() + print(summary, file=sys.stderr) + + cpu_time = process_time() - cpu_start + wall_time = time.monotonic() - time_start + efficiency = cpu_time / wall_time if wall_time else 100 + untracked = wall_time - execution_time + + print( + "Total wall time: {:.2f}s; CPU time: {:.2f}s; Efficiency: " + "{:.0%}; Untracked: {:.2f}s".format(wall_time, cpu_time, efficiency, untracked), + file=sys.stderr, + ) + + if options.diff: + for the_backend in selected_backends: + for path, diff in sorted(the_backend.file_diffs.items()): + print("\n".join(diff)) + + # Advertise Android Studio if it is appropriate. + if MachCommandConditions.is_android(env): + print(ANDROID_IDE_ADVERTISEMENT) |