Bug 1207893 - Allow to create multiple build backends at once. r=gps
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 25 Sep 2015 07:07:08 +0900
changeset 264885 55af918cafff6bfdfaa6a8c665e3a2bd240b52f3
parent 264884 75c3e053bcfa70f2cf6dd0df22458d916c41fd6b
child 264886 617e63c7c9aed85ba623dd9b47088956ea7d3b7a
push id29450
push usercbook@mozilla.com
push dateTue, 29 Sep 2015 10:00:39 +0000
treeherdermozilla-central@acdb22976ff8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1207893
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1207893 - Allow to create multiple build backends at once. r=gps When running mach `build-backend` or `config.status`, it is now possible to pass multiple backends to the --backend/-b option, so that they can share moz.build reading and object emitting. The command line syntax is however maybe a little awkward: mach build-backend -b Backend1 Backend2 but supporting with `-b Backend1 -b Backend2` requires more argument parser twiddling (action='append' doesn't work out of the box with choices, we'd need a custom action class)
python/mozbuild/mozbuild/config_status.py
python/mozbuild/mozbuild/mach_commands.py
--- a/python/mozbuild/mozbuild/config_status.py
+++ b/python/mozbuild/mozbuild/config_status.py
@@ -8,25 +8,26 @@
 
 from __future__ import absolute_import, print_function
 
 import logging
 import os
 import sys
 import time
 
-from optparse import OptionParser
+from argparse import ArgumentParser
 
 from mach.logging import LoggingManager
 from mozbuild.backend.configenvironment import ConfigEnvironment
 from mozbuild.backend.recursivemake import RecursiveMakeBackend
 from mozbuild.base import MachCommandConditions
 from mozbuild.frontend.emitter import TreeMetadataEmitter
 from mozbuild.frontend.reader import BuildReader
 from mozbuild.mozinfo import write_mozinfo
+from itertools import chain
 
 
 log_manager = LoggingManager()
 
 
 ANDROID_IDE_ADVERTISEMENT = '''
 =============
 ADVERTISEMENT
@@ -82,87 +83,94 @@ def config_status(topobjdir='.', topsrcd
     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)
 
-    parser = OptionParser()
-    parser.add_option('--recheck', dest='recheck', action='store_true',
-                      help='update config.status by reconfiguring in the same conditions')
-    parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
-                      help='display verbose output')
-    parser.add_option('-n', dest='not_topobjdir', action='store_true',
-                      help='do not consider current directory as top object directory')
-    parser.add_option('-d', '--diff', action='store_true',
-                      help='print diffs of changed files.')
-    parser.add_option('-b', '--backend',
-                      choices=['RecursiveMake', 'AndroidEclipse', 'CppEclipse',
-                               'VisualStudio', 'FasterMake'],
-                      default='RecursiveMake',
-                      help='what backend to build (default: RecursiveMake).')
-    options, args = parser.parse_args()
+    parser = ArgumentParser()
+    parser.add_argument('--recheck', dest='recheck', action='store_true',
+                        help='update config.status by reconfiguring in the same conditions')
+    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=['RecursiveMake', 'AndroidEclipse', 'CppEclipse',
+                                 'VisualStudio', 'FasterMake'],
+                        default=['RecursiveMake'],
+                        help='what backend to build (default: RecursiveMake).')
+    options = parser.parse_args()
 
     # Without -n, the current directory is meant to be the top object directory
     if not options.not_topobjdir:
         topobjdir = os.path.abspath('.')
 
     env = ConfigEnvironment(topsrcdir, topobjdir, defines=defines,
             non_global_defines=non_global_defines, substs=substs, source=source)
 
     # mozinfo.json only needs written if configure changes and configure always
     # passes this environment variable.
     if 'WRITE_MOZINFO' in os.environ:
         write_mozinfo(os.path.join(topobjdir, 'mozinfo.json'), env, os.environ)
 
     # Make an appropriate backend instance, defaulting to RecursiveMakeBackend.
-    backend_cls = RecursiveMakeBackend
-    if options.backend == 'AndroidEclipse':
-        from mozbuild.backend.android_eclipse import AndroidEclipseBackend
-        if not MachCommandConditions.is_android(env):
-            raise Exception('The Android Eclipse backend is not available with this configuration.')
-        backend_cls = AndroidEclipseBackend
-    elif options.backend == 'CppEclipse':
-        from mozbuild.backend.cpp_eclipse import CppEclipseBackend
-        backend_cls = CppEclipseBackend
-        if os.name == 'nt':
-          raise Exception('Eclipse is not supported on Windows. Consider using Visual Studio instead.')
-    elif options.backend == 'VisualStudio':
-        from mozbuild.backend.visualstudio import VisualStudioBackend
-        backend_cls = VisualStudioBackend
-    elif options.backend == 'FasterMake':
-        from mozbuild.backend.fastermake import FasterMakeBackend
-        backend_cls = FasterMakeBackend
+    backends_cls = []
+    for backend in options.backend:
+        if backend == 'AndroidEclipse':
+            from mozbuild.backend.android_eclipse import AndroidEclipseBackend
+            if not MachCommandConditions.is_android(env):
+                raise Exception('The Android Eclipse backend is not available with this configuration.')
+            backends_cls.append(AndroidEclipseBackend)
+        elif backend == 'CppEclipse':
+            from mozbuild.backend.cpp_eclipse import CppEclipseBackend
+            backends_cls.append(CppEclipseBackend)
+            if os.name == 'nt':
+              raise Exception('Eclipse is not supported on Windows. Consider using Visual Studio instead.')
+        elif backend == 'VisualStudio':
+            from mozbuild.backend.visualstudio import VisualStudioBackend
+            backends_cls.append(VisualStudioBackend)
+        elif backend == 'FasterMake':
+            from mozbuild.backend.fastermake import FasterMakeBackend
+            backends_cls.append(FasterMakeBackend)
+        else:
+            backends_cls.append(RecursiveMakeBackend)
 
     cpu_start = time.clock()
     time_start = time.time()
 
-    the_backend = backend_cls(env)
+    backends = [cls(env) for cls in backends_cls]
 
     reader = BuildReader(env)
     emitter = TreeMetadataEmitter(env)
     # This won't actually do anything because of the magic of generators.
     definitions = emitter.emit(reader.read_topsrcdir())
 
     if options.recheck:
         # Execute configure from the top object directory
         os.chdir(topobjdir)
         os.execlp('sh', 'sh', '-c', ' '.join([os.path.join(topsrcdir, 'configure'), env.substs['ac_configure_args'], '--no-create', '--no-recursion']))
 
     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)
-    the_backend.consume(definitions)
+    if len(backends) > 1:
+        definitions = list(definitions)
+
+    for the_backend in backends:
+        the_backend.consume(definitions)
 
     execution_time = 0.0
-    for obj in (reader, emitter, the_backend):
+    for obj in chain((reader, emitter), backends):
         summary = obj.summary()
         print(summary, file=sys.stderr)
         execution_time += summary.execution_time
 
     cpu_time = time.clock() - cpu_start
     wall_time = time.time() - time_start
     efficiency = cpu_time / wall_time if wall_time else 100
     untracked = wall_time - execution_time
@@ -170,19 +178,20 @@ def config_status(topobjdir='.', topsrcd
     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 path, diff in sorted(the_backend.file_diffs.items()):
-            print('\n'.join(diff))
+        for the_backend in backends:
+            for path, diff in sorted(the_backend.file_diffs.items()):
+                print('\n'.join(diff))
 
     # Advertise Visual Studio if appropriate.
-    if os.name == 'nt' and options.backend == 'RecursiveMake':
+    if os.name == 'nt' and 'VisualStudio' not in options.backend:
         print(VISUAL_STUDIO_ADVERTISEMENT)
 
     # Advertise Eclipse if it is appropriate.
     if MachCommandConditions.is_android(env):
-        if options.backend == 'RecursiveMake':
+        if 'AndroidEclipse' not in options.backend:
             print(ANDROID_IDE_ADVERTISEMENT)
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -553,32 +553,32 @@ class Build(MachCommandBase):
         return ret
 
     @Command('build-backend', category='build',
         description='Generate a backend used to build the tree.')
     @CommandArgument('-d', '--diff', action='store_true',
         help='Show a diff of changes.')
     # It would be nice to filter the choices below based on
     # conditions, but that is for another day.
-    @CommandArgument('-b', '--backend',
+    @CommandArgument('-b', '--backend', nargs='+',
         choices=['RecursiveMake', 'AndroidEclipse', 'CppEclipse',
                  'VisualStudio', 'FasterMake'],
-        default='RecursiveMake',
+        default=['RecursiveMake'],
         help='Which backend to build (default: RecursiveMake).')
     def build_backend(self, backend='RecursiveMake', diff=False):
         python = self.virtualenv_manager.python_path
         config_status = os.path.join(self.topobjdir, 'config.status')
 
         if not os.path.exists(config_status):
             print('config.status not found.  Please run |mach configure| '
                   'or |mach build| prior to building the %s build backend.'
                   % backend)
             return 1
 
-        args = [python, config_status, '--backend=%s' % backend]
+        args = [python, config_status, '--backend'] + backend
         if diff:
             args.append('--diff')
 
         return self._run_command_in_objdir(args=args, pass_thru=True,
             ensure_exit_code=False)
 
 @CommandProvider
 class Doctor(MachCommandBase):