Bug 1415614 - Move code for invoking build system out of mach_commands.py; r=nalexander
The goal is to move this lower-level code somewhere where it can be
reused.
The only meaningful code change as part of the move was handling
of the mach context. Before, we could access self._mach_context.
After, we need to pass it as an argument. This also uncovered a bug
where "telemetry_handler" could be None but we called it
unconditionally. We now guard this call with an "if."
MozReview-Commit-ID: FWw4l6H1ayS
--- a/python/mozbuild/mozbuild/controller/building.py
+++ b/python/mozbuild/mozbuild/controller/building.py
@@ -9,40 +9,68 @@ import json
import logging
import os
import subprocess
import sys
import time
import which
from collections import (
+ Counter,
namedtuple,
OrderedDict,
)
+from textwrap import (
+ TextWrapper,
+)
try:
import psutil
except Exception:
psutil = None
from mach.mixin.logging import LoggingMixin
from mozsystemmonitor.resourcemonitor import SystemResourceMonitor
import mozpack.path as mozpath
-from ..base import MozbuildObject
-
-from ..testing import install_test_files
-
+from ..base import (
+ BuildEnvironmentNotFoundException,
+ MozbuildObject,
+)
+from ..backend import (
+ get_backend_class,
+)
+from ..testing import (
+ install_test_files,
+)
from ..compilation.warnings import (
WarningsCollector,
WarningsDatabase,
)
+from ..util import (
+ mkdir,
+ resolve_target_to_make,
+)
-from textwrap import TextWrapper
+
+FINDER_SLOW_MESSAGE = '''
+===================
+PERFORMANCE WARNING
+
+The OS X Finder application (file indexing used by Spotlight) used a lot of CPU
+during the build - an average of %f%% (100%% is 1 core). This made your build
+slower.
+
+Consider adding ".noindex" to the end of your object directory name to have
+Finder ignore it. Or, add an indexing exclusion through the Spotlight System
+Preferences.
+===================
+'''.strip()
+
INSTALL_TESTS_CLOBBER = ''.join([TextWrapper().fill(line) + '\n' for line in
'''
The build system was unable to install tests because the CLOBBER file has \
been updated. This means if you edited any test files, your changes may not \
be picked up until a full/clobber build is performed.
The easiest and fastest way to perform a clobber build is to run:
@@ -942,16 +970,313 @@ class CCacheStats(object):
return '%.1f Mbytes' % (float(v) / CCacheStats.MiB)
else:
return '%.1f Kbytes' % (float(v) / CCacheStats.KiB)
class BuildDriver(MozbuildObject):
"""Provides a high-level API for build actions."""
+ def build(self, what=None, disable_extra_make_dependencies=None, jobs=0,
+ directory=None, verbose=False, keep_going=False, mach_context=None):
+ """Invoke the build backend.
+
+ ``what`` defines the thing to build. If not defined, the default
+ target is used.
+ """
+ warnings_path = self._get_state_filename('warnings.json')
+ monitor = self._spawn(BuildMonitor)
+ monitor.init(warnings_path)
+ ccache_start = monitor.ccache_stats()
+ footer = BuildProgressFooter(self.log_manager.terminal, monitor)
+
+ # Disable indexing in objdir because it is not necessary and can slow
+ # down builds.
+ mkdir(self.topobjdir, not_indexed=True)
+
+ with BuildOutputManager(self.log_manager, monitor, footer) as output:
+ monitor.start()
+
+ if directory is not None and not what:
+ print('Can only use -C/--directory with an explicit target '
+ 'name.')
+ return 1
+
+ if directory is not None:
+ disable_extra_make_dependencies=True
+ directory = mozpath.normsep(directory)
+ if directory.startswith('/'):
+ directory = directory[1:]
+
+ status = None
+ monitor.start_resource_recording()
+ if what:
+ top_make = os.path.join(self.topobjdir, 'Makefile')
+ if not os.path.exists(top_make):
+ print('Your tree has not been configured yet. Please run '
+ '|mach build| with no arguments.')
+ return 1
+
+ # Collect target pairs.
+ target_pairs = []
+ for target in what:
+ path_arg = self._wrap_path_argument(target)
+
+ if directory is not None:
+ make_dir = os.path.join(self.topobjdir, directory)
+ make_target = target
+ else:
+ make_dir, make_target = \
+ resolve_target_to_make(self.topobjdir,
+ path_arg.relpath())
+
+ if make_dir is None and make_target is None:
+ return 1
+
+ # See bug 886162 - we don't want to "accidentally" build
+ # the entire tree (if that's really the intent, it's
+ # unlikely they would have specified a directory.)
+ if not make_dir and not make_target:
+ print("The specified directory doesn't contain a "
+ "Makefile and the first parent with one is the "
+ "root of the tree. Please specify a directory "
+ "with a Makefile or run |mach build| if you "
+ "want to build the entire tree.")
+ return 1
+
+ target_pairs.append((make_dir, make_target))
+
+ # Possibly add extra make depencies using dumbmake.
+ if not disable_extra_make_dependencies:
+ from dumbmake.dumbmake import (dependency_map,
+ add_extra_dependencies)
+ depfile = os.path.join(self.topsrcdir, 'build',
+ 'dumbmake-dependencies')
+ with open(depfile) as f:
+ dm = dependency_map(f.readlines())
+ new_pairs = list(add_extra_dependencies(target_pairs, dm))
+ self.log(logging.DEBUG, 'dumbmake',
+ {'target_pairs': target_pairs,
+ 'new_pairs': new_pairs},
+ 'Added extra dependencies: will build {new_pairs} ' +
+ 'instead of {target_pairs}.')
+ target_pairs = new_pairs
+
+ # Ensure build backend is up to date. The alternative is to
+ # have rules in the invoked Makefile to rebuild the build
+ # backend. But that involves make reinvoking itself and there
+ # are undesired side-effects of this. See bug 877308 for a
+ # comprehensive history lesson.
+ self._run_make(directory=self.topobjdir, target='backend',
+ line_handler=output.on_line, log=False,
+ print_directory=False, keep_going=keep_going)
+
+ # Build target pairs.
+ for make_dir, make_target in target_pairs:
+ # We don't display build status messages during partial
+ # tree builds because they aren't reliable there. This
+ # could potentially be fixed if the build monitor were more
+ # intelligent about encountering undefined state.
+ status = self._run_make(directory=make_dir, target=make_target,
+ line_handler=output.on_line, log=False, print_directory=False,
+ ensure_exit_code=False, num_jobs=jobs, silent=not verbose,
+ append_env={b'NO_BUILDSTATUS_MESSAGES': b'1'},
+ keep_going=keep_going)
+
+ if status != 0:
+ break
+ else:
+ # Try to call the default backend's build() method. This will
+ # run configure to determine BUILD_BACKENDS if it hasn't run
+ # yet.
+ config = None
+ try:
+ config = self.config_environment
+ except Exception:
+ config_rc = self.configure(buildstatus_messages=True,
+ line_handler=output.on_line)
+ if config_rc != 0:
+ return config_rc
+
+ # Even if configure runs successfully, we may have trouble
+ # getting the config_environment for some builds, such as
+ # OSX Universal builds. These have to go through client.mk
+ # regardless.
+ try:
+ config = self.config_environment
+ except Exception:
+ pass
+
+ if config:
+ active_backend = config.substs.get('BUILD_BACKENDS', [None])[0]
+ if active_backend:
+ backend_cls = get_backend_class(active_backend)(config)
+ status = backend_cls.build(self, output, jobs, verbose)
+
+ # If the backend doesn't specify a build() method, then just
+ # call client.mk directly.
+ if status is None:
+ status = self._run_make(srcdir=True, filename='client.mk',
+ line_handler=output.on_line, log=False, print_directory=False,
+ allow_parallel=False, ensure_exit_code=False, num_jobs=jobs,
+ silent=not verbose, keep_going=keep_going)
+
+ self.log(logging.WARNING, 'warning_summary',
+ {'count': len(monitor.warnings_database)},
+ '{count} compiler warnings present.')
+
+ # Print the collected compiler warnings. This is redundant with
+ # inline output from the compiler itself. However, unlike inline
+ # output, this list is sorted and grouped by file, making it
+ # easier to triage output.
+ #
+ # Only do this if we had a successful build. If the build failed,
+ # there are more important things in the log to look for than
+ # whatever code we warned about.
+ if not status:
+ # Suppress warnings for 3rd party projects in local builds
+ # until we suppress them for real.
+ # TODO remove entries/feature once we stop generating warnings
+ # in these directories.
+ pathToThirdparty = os.path.join(self.topsrcdir,
+ "tools",
+ "rewriting",
+ "ThirdPartyPaths.txt")
+
+ if os.path.exists(pathToThirdparty):
+ with open(pathToThirdparty) as f:
+ # Normalize the path (no trailing /)
+ LOCAL_SUPPRESS_DIRS = tuple(d.rstrip('/') for d in f.read().splitlines())
+ else:
+ # For application based on gecko like thunderbird
+ LOCAL_SUPPRESS_DIRS = ()
+
+ suppressed_by_dir = Counter()
+
+ for warning in sorted(monitor.instance_warnings):
+ path = mozpath.normsep(warning['filename'])
+ if path.startswith(self.topsrcdir):
+ path = path[len(self.topsrcdir) + 1:]
+
+ warning['normpath'] = path
+
+ if (path.startswith(LOCAL_SUPPRESS_DIRS) and
+ 'MOZ_AUTOMATION' not in os.environ):
+ for d in LOCAL_SUPPRESS_DIRS:
+ if path.startswith(d):
+ suppressed_by_dir[d] += 1
+ break
+
+ continue
+
+ if warning['column'] is not None:
+ self.log(logging.WARNING, 'compiler_warning', warning,
+ 'warning: {normpath}:{line}:{column} [{flag}] '
+ '{message}')
+ else:
+ self.log(logging.WARNING, 'compiler_warning', warning,
+ 'warning: {normpath}:{line} [{flag}] {message}')
+
+ for d, count in sorted(suppressed_by_dir.items()):
+ self.log(logging.WARNING, 'suppressed_warning',
+ {'dir': d, 'count': count},
+ '(suppressed {count} warnings in {dir})')
+
+ monitor.finish(record_usage=status==0)
+
+ high_finder, finder_percent = monitor.have_high_finder_usage()
+ if high_finder:
+ print(FINDER_SLOW_MESSAGE % finder_percent)
+
+ ccache_end = monitor.ccache_stats()
+
+ ccache_diff = None
+ if ccache_start and ccache_end:
+ ccache_diff = ccache_end - ccache_start
+ if ccache_diff:
+ self.log(logging.INFO, 'ccache',
+ {'msg': ccache_diff.hit_rate_message()}, "{msg}")
+
+ notify_minimum_time = 300
+ try:
+ notify_minimum_time = int(os.environ.get('MACH_NOTIFY_MINTIME', '300'))
+ except ValueError:
+ # Just stick with the default
+ pass
+
+ if monitor.elapsed > notify_minimum_time:
+ # Display a notification when the build completes.
+ self.notify('Build complete' if not status else 'Build failed')
+
+ if status:
+ return status
+
+ long_build = monitor.elapsed > 600
+
+ if long_build:
+ output.on_line('We know it took a while, but your build finally finished successfully!')
+ else:
+ output.on_line('Your build was successful!')
+
+ if monitor.have_resource_usage:
+ excessive, swap_in, swap_out = monitor.have_excessive_swapping()
+ # if excessive:
+ # print(EXCESSIVE_SWAP_MESSAGE)
+
+ print('To view resource usage of the build, run |mach '
+ 'resource-usage|.')
+
+ telemetry_handler = getattr(mach_context,
+ 'telemetry_handler', None)
+ telemetry_data = monitor.get_resource_usage()
+
+ # Record build configuration data. For now, we cherry pick
+ # items we need rather than grabbing everything, in order
+ # to avoid accidentally disclosing PII.
+ telemetry_data['substs'] = {}
+ try:
+ for key in ['MOZ_ARTIFACT_BUILDS', 'MOZ_USING_CCACHE', 'MOZ_USING_SCCACHE']:
+ value = self.substs.get(key, False)
+ telemetry_data['substs'][key] = value
+ except BuildEnvironmentNotFoundException:
+ pass
+
+ # Grab ccache stats if available. We need to be careful not
+ # to capture information that can potentially identify the
+ # user (such as the cache location)
+ if ccache_diff:
+ telemetry_data['ccache'] = {}
+ for key in [key[0] for key in ccache_diff.STATS_KEYS]:
+ try:
+ telemetry_data['ccache'][key] = ccache_diff._values[key]
+ except KeyError:
+ pass
+
+ if telemetry_handler:
+ telemetry_handler(mach_context, telemetry_data)
+
+ # Only for full builds because incremental builders likely don't
+ # need to be burdened with this.
+ if not what:
+ try:
+ # Fennec doesn't have useful output from just building. We should
+ # arguably make the build action useful for Fennec. Another day...
+ if self.substs['MOZ_BUILD_APP'] != 'mobile/android':
+ print('To take your build for a test drive, run: |mach run|')
+ app = self.substs['MOZ_BUILD_APP']
+ if app in ('browser', 'mobile/android'):
+ print('For more information on what to do now, see '
+ 'https://developer.mozilla.org/docs/Developer_Guide/So_You_Just_Built_Firefox')
+ except Exception:
+ # Ignore Exceptions in case we can't find config.status (such
+ # as when doing OSX Universal builds)
+ pass
+
+ return status
+
def install_tests(self, test_objs):
"""Install test files."""
if self.is_clobber_needed():
print(INSTALL_TESTS_CLOBBER.format(
clobber_file=os.path.join(self.topobjdir, 'CLOBBER')))
sys.exit(1)
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -26,51 +26,36 @@ from mach.decorators import (
Command,
SettingsProvider,
SubCommand,
)
from mach.main import Mach
from mozbuild.base import (
- BuildEnvironmentNotFoundException,
MachCommandBase,
MachCommandConditions as conditions,
MozbuildObject,
)
from mozbuild.util import ensureParentDir
from mozbuild.backend import (
backends,
- get_backend_class,
)
from mozbuild.shellutil import quote as shell_quote
BUILD_WHAT_HELP = '''
What to build. Can be a top-level make target or a relative directory. If
multiple options are provided, they will be built serially. Takes dependency
information from `topsrcdir/build/dumbmake-dependencies` to build additional
targets as needed. BUILDING ONLY PARTS OF THE TREE CAN RESULT IN BAD TREE
STATE. USE AT YOUR OWN RISK.
'''.strip()
-FINDER_SLOW_MESSAGE = '''
-===================
-PERFORMANCE WARNING
-
-The OS X Finder application (file indexing used by Spotlight) used a lot of CPU
-during the build - an average of %f%% (100%% is 1 core). This made your build
-slower.
-
-Consider adding ".noindex" to the end of your object directory name to have
-Finder ignore it. Or, add an indexing exclusion through the Spotlight System
-Preferences.
-===================
-'''.strip()
EXCESSIVE_SWAP_MESSAGE = '''
===================
PERFORMANCE WARNING
Your machine experienced a lot of swap activity during the build. This is
possibly a sign that your machine doesn't have enough physical memory or
not enough available memory to perform the build. It's also possible some
@@ -166,315 +151,30 @@ class Build(MachCommandBase):
* faster - builds JavaScript, XUL, CSS, etc files.
"binaries" and "faster" almost fully complement each other. However,
there are build actions not captured by either. If things don't appear to
be rebuilding, perform a vanilla `mach build` to rebuild the world.
"""
from mozbuild.controller.building import (
- BuildMonitor,
- BuildOutputManager,
- BuildProgressFooter,
- )
- from mozbuild.util import (
- mkdir,
- resolve_target_to_make,
+ BuildDriver,
)
self.log_manager.enable_all_structured_loggers()
- warnings_path = self._get_state_filename('warnings.json')
- monitor = self._spawn(BuildMonitor)
- monitor.init(warnings_path)
- ccache_start = monitor.ccache_stats()
- footer = BuildProgressFooter(self.log_manager.terminal, monitor)
-
- # Disable indexing in objdir because it is not necessary and can slow
- # down builds.
- mkdir(self.topobjdir, not_indexed=True)
-
- with BuildOutputManager(self.log_manager, monitor, footer) as output:
- monitor.start()
-
- if directory is not None and not what:
- print('Can only use -C/--directory with an explicit target '
- 'name.')
- return 1
-
- if directory is not None:
- disable_extra_make_dependencies=True
- directory = mozpath.normsep(directory)
- if directory.startswith('/'):
- directory = directory[1:]
-
- status = None
- monitor.start_resource_recording()
- if what:
- top_make = os.path.join(self.topobjdir, 'Makefile')
- if not os.path.exists(top_make):
- print('Your tree has not been configured yet. Please run '
- '|mach build| with no arguments.')
- return 1
-
- # Collect target pairs.
- target_pairs = []
- for target in what:
- path_arg = self._wrap_path_argument(target)
-
- if directory is not None:
- make_dir = os.path.join(self.topobjdir, directory)
- make_target = target
- else:
- make_dir, make_target = \
- resolve_target_to_make(self.topobjdir,
- path_arg.relpath())
-
- if make_dir is None and make_target is None:
- return 1
-
- # See bug 886162 - we don't want to "accidentally" build
- # the entire tree (if that's really the intent, it's
- # unlikely they would have specified a directory.)
- if not make_dir and not make_target:
- print("The specified directory doesn't contain a "
- "Makefile and the first parent with one is the "
- "root of the tree. Please specify a directory "
- "with a Makefile or run |mach build| if you "
- "want to build the entire tree.")
- return 1
-
- target_pairs.append((make_dir, make_target))
-
- # Possibly add extra make depencies using dumbmake.
- if not disable_extra_make_dependencies:
- from dumbmake.dumbmake import (dependency_map,
- add_extra_dependencies)
- depfile = os.path.join(self.topsrcdir, 'build',
- 'dumbmake-dependencies')
- with open(depfile) as f:
- dm = dependency_map(f.readlines())
- new_pairs = list(add_extra_dependencies(target_pairs, dm))
- self.log(logging.DEBUG, 'dumbmake',
- {'target_pairs': target_pairs,
- 'new_pairs': new_pairs},
- 'Added extra dependencies: will build {new_pairs} ' +
- 'instead of {target_pairs}.')
- target_pairs = new_pairs
-
- # Ensure build backend is up to date. The alternative is to
- # have rules in the invoked Makefile to rebuild the build
- # backend. But that involves make reinvoking itself and there
- # are undesired side-effects of this. See bug 877308 for a
- # comprehensive history lesson.
- self._run_make(directory=self.topobjdir, target='backend',
- line_handler=output.on_line, log=False,
- print_directory=False, keep_going=keep_going)
-
- # Build target pairs.
- for make_dir, make_target in target_pairs:
- # We don't display build status messages during partial
- # tree builds because they aren't reliable there. This
- # could potentially be fixed if the build monitor were more
- # intelligent about encountering undefined state.
- status = self._run_make(directory=make_dir, target=make_target,
- line_handler=output.on_line, log=False, print_directory=False,
- ensure_exit_code=False, num_jobs=jobs, silent=not verbose,
- append_env={b'NO_BUILDSTATUS_MESSAGES': b'1'},
- keep_going=keep_going)
-
- if status != 0:
- break
- else:
- # Try to call the default backend's build() method. This will
- # run configure to determine BUILD_BACKENDS if it hasn't run
- # yet.
- config = None
- try:
- config = self.config_environment
- except Exception:
- config_rc = self.configure(buildstatus_messages=True,
- line_handler=output.on_line)
- if config_rc != 0:
- return config_rc
-
- # Even if configure runs successfully, we may have trouble
- # getting the config_environment for some builds, such as
- # OSX Universal builds. These have to go through client.mk
- # regardless.
- try:
- config = self.config_environment
- except Exception:
- pass
-
- if config:
- active_backend = config.substs.get('BUILD_BACKENDS', [None])[0]
- if active_backend:
- backend_cls = get_backend_class(active_backend)(config)
- status = backend_cls.build(self, output, jobs, verbose)
-
- # If the backend doesn't specify a build() method, then just
- # call client.mk directly.
- if status is None:
- status = self._run_make(srcdir=True, filename='client.mk',
- line_handler=output.on_line, log=False, print_directory=False,
- allow_parallel=False, ensure_exit_code=False, num_jobs=jobs,
- silent=not verbose, keep_going=keep_going)
-
- self.log(logging.WARNING, 'warning_summary',
- {'count': len(monitor.warnings_database)},
- '{count} compiler warnings present.')
-
- # Print the collected compiler warnings. This is redundant with
- # inline output from the compiler itself. However, unlike inline
- # output, this list is sorted and grouped by file, making it
- # easier to triage output.
- #
- # Only do this if we had a successful build. If the build failed,
- # there are more important things in the log to look for than
- # whatever code we warned about.
- if not status:
- # Suppress warnings for 3rd party projects in local builds
- # until we suppress them for real.
- # TODO remove entries/feature once we stop generating warnings
- # in these directories.
- pathToThirdparty = os.path.join(self.topsrcdir,
- "tools",
- "rewriting",
- "ThirdPartyPaths.txt")
-
- if os.path.exists(pathToThirdparty):
- with open(pathToThirdparty) as f:
- # Normalize the path (no trailing /)
- LOCAL_SUPPRESS_DIRS = tuple(d.rstrip('/') for d in f.read().splitlines())
- else:
- # For application based on gecko like thunderbird
- LOCAL_SUPPRESS_DIRS = ()
-
- suppressed_by_dir = collections.Counter()
-
- for warning in sorted(monitor.instance_warnings):
- path = mozpath.normsep(warning['filename'])
- if path.startswith(self.topsrcdir):
- path = path[len(self.topsrcdir) + 1:]
-
- warning['normpath'] = path
-
- if (path.startswith(LOCAL_SUPPRESS_DIRS) and
- 'MOZ_AUTOMATION' not in os.environ):
- for d in LOCAL_SUPPRESS_DIRS:
- if path.startswith(d):
- suppressed_by_dir[d] += 1
- break
-
- continue
-
- if warning['column'] is not None:
- self.log(logging.WARNING, 'compiler_warning', warning,
- 'warning: {normpath}:{line}:{column} [{flag}] '
- '{message}')
- else:
- self.log(logging.WARNING, 'compiler_warning', warning,
- 'warning: {normpath}:{line} [{flag}] {message}')
-
- for d, count in sorted(suppressed_by_dir.items()):
- self.log(logging.WARNING, 'suppressed_warning',
- {'dir': d, 'count': count},
- '(suppressed {count} warnings in {dir})')
-
- monitor.finish(record_usage=status==0)
-
- high_finder, finder_percent = monitor.have_high_finder_usage()
- if high_finder:
- print(FINDER_SLOW_MESSAGE % finder_percent)
-
- ccache_end = monitor.ccache_stats()
-
- ccache_diff = None
- if ccache_start and ccache_end:
- ccache_diff = ccache_end - ccache_start
- if ccache_diff:
- self.log(logging.INFO, 'ccache',
- {'msg': ccache_diff.hit_rate_message()}, "{msg}")
-
- notify_minimum_time = 300
- try:
- notify_minimum_time = int(os.environ.get('MACH_NOTIFY_MINTIME', '300'))
- except ValueError:
- # Just stick with the default
- pass
-
- if monitor.elapsed > notify_minimum_time:
- # Display a notification when the build completes.
- self.notify('Build complete' if not status else 'Build failed')
-
- if status:
- return status
-
- long_build = monitor.elapsed > 600
-
- if long_build:
- output.on_line('We know it took a while, but your build finally finished successfully!')
- else:
- output.on_line('Your build was successful!')
-
- if monitor.have_resource_usage:
- excessive, swap_in, swap_out = monitor.have_excessive_swapping()
- # if excessive:
- # print(EXCESSIVE_SWAP_MESSAGE)
-
- print('To view resource usage of the build, run |mach '
- 'resource-usage|.')
-
- telemetry_handler = getattr(self._mach_context,
- 'telemetry_handler', None)
- telemetry_data = monitor.get_resource_usage()
-
- # Record build configuration data. For now, we cherry pick
- # items we need rather than grabbing everything, in order
- # to avoid accidentally disclosing PII.
- telemetry_data['substs'] = {}
- try:
- for key in ['MOZ_ARTIFACT_BUILDS', 'MOZ_USING_CCACHE', 'MOZ_USING_SCCACHE']:
- value = self.substs.get(key, False)
- telemetry_data['substs'][key] = value
- except BuildEnvironmentNotFoundException:
- pass
-
- # Grab ccache stats if available. We need to be careful not
- # to capture information that can potentially identify the
- # user (such as the cache location)
- if ccache_diff:
- telemetry_data['ccache'] = {}
- for key in [key[0] for key in ccache_diff.STATS_KEYS]:
- try:
- telemetry_data['ccache'][key] = ccache_diff._values[key]
- except KeyError:
- pass
-
- telemetry_handler(self._mach_context, telemetry_data)
-
- # Only for full builds because incremental builders likely don't
- # need to be burdened with this.
- if not what:
- try:
- # Fennec doesn't have useful output from just building. We should
- # arguably make the build action useful for Fennec. Another day...
- if self.substs['MOZ_BUILD_APP'] != 'mobile/android':
- print('To take your build for a test drive, run: |mach run|')
- app = self.substs['MOZ_BUILD_APP']
- if app in ('browser', 'mobile/android'):
- print('For more information on what to do now, see '
- 'https://developer.mozilla.org/docs/Developer_Guide/So_You_Just_Built_Firefox')
- except Exception:
- # Ignore Exceptions in case we can't find config.status (such
- # as when doing OSX Universal builds)
- pass
-
- return status
+ driver = self._spawn(BuildDriver)
+ return driver.build(
+ what=what,
+ disable_extra_make_dependencies=disable_extra_make_dependencies,
+ jobs=jobs,
+ directory=directory,
+ verbose=verbose,
+ keep_going=keep_going,
+ mach_context=self._mach_context)
@Command('configure', category='build',
description='Configure the tree (run configure and config.status).')
@CommandArgument('options', default=None, nargs=argparse.REMAINDER,
help='Configure options')
def configure(self, options=None, buildstatus_messages=False, line_handler=None):
self.log_manager.enable_all_structured_loggers()