Bug 1240990 - Define all backends in one place. r=gps
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 20 Jan 2016 11:07:58 +0900 (2016-01-20)
changeset 280876 f7a8480e3efaae4fdd07d2908671768b6e0ba15a
parent 280875 1a4c479ec7cd347ad7b939c434633234c8e20b2c
child 280877 452612abdc8c61d3923dd2dd2cd9c1d247088d8c
push id29922
push usercbook@mozilla.com
push dateThu, 21 Jan 2016 10:51:00 +0000 (2016-01-21)
treeherdermozilla-central@977d78a8dd78 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1240990
milestone46.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 1240990 - Define all backends in one place. r=gps When adding a backend, we currently have to add them in three different places so that they appear in the right places. Instead, keep the list in a single place.
build/autoconf/config.status.m4
configure.in
js/src/configure.in
python/mozbuild/mozbuild/backend/__init__.py
python/mozbuild/mozbuild/backend/android_eclipse.py
python/mozbuild/mozbuild/backend/cpp_eclipse.py
python/mozbuild/mozbuild/config_status.py
python/mozbuild/mozbuild/mach_commands.py
python/mozbuild/mozbuild/test/backend/common.py
--- a/build/autoconf/config.status.m4
+++ b/build/autoconf/config.status.m4
@@ -226,14 +226,14 @@ define([AC_CONFIG_HEADER],
 [m4_fatal([Use CONFIGURE_DEFINE_FILES in moz.build files to produce header files.])
 ])
 
 define([MOZ_BUILD_BACKEND],
 [
 BUILD_BACKENDS="RecursiveMake"
 
 MOZ_ARG_ENABLE_STRING(build-backend,
-[  --enable-build-backend={AndroidEclipse,CppEclipse,VisualStudio,FasterMake,CompileDB,ChromeMap}
+[  --enable-build-backend={$($(dirname ]$[0)/$1/mach python -c "from mozbuild.backend import backends; print ','.join(sorted(backends))")}
                          Enable additional build backends],
 [ BUILD_BACKENDS="RecursiveMake `echo $enableval | sed 's/,/ /g'`"])
 
 AC_SUBST_SET([BUILD_BACKENDS])
 ])
--- a/configure.in
+++ b/configure.in
@@ -134,17 +134,17 @@ EOF
   exit 1
   break
 fi
 MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd -P`
 DIST="$MOZ_BUILD_ROOT/dist"
 
 MOZ_PYTHON
 
-MOZ_BUILD_BACKEND
+MOZ_BUILD_BACKEND(.)
 
 MOZ_DEFAULT_COMPILER
 
 COMPILE_ENVIRONMENT=1
 MOZ_ARG_DISABLE_BOOL(compile-environment,
 [  --disable-compile-environment
                           Disable compiler/library checks.],
     COMPILE_ENVIRONMENT= )
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -109,17 +109,17 @@ if test "$_conflict_files"; then
 	*     2. gmake distclean
 	***
 	EOF
   exit 1
   break
 fi
 MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd -P`
 
-MOZ_BUILD_BACKEND
+MOZ_BUILD_BACKEND(../..)
 
 MOZ_DEFAULT_COMPILER
 
 COMPILE_ENVIRONMENT=1
 MOZ_ARG_DISABLE_BOOL(compile-environment,
 [  --disable-compile-environment
                           Disable compiler/library checks.],
     COMPILE_ENVIRONMENT= )
--- a/python/mozbuild/mozbuild/backend/__init__.py
+++ b/python/mozbuild/mozbuild/backend/__init__.py
@@ -0,0 +1,19 @@
+# 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/.
+
+backends = {
+    'AndroidEclipse': 'mozbuild.backend.android_eclipse',
+    'ChromeMap': 'mozbuild.codecoverage.chrome_map',
+    'CompileDB': 'mozbuild.compilation.database',
+    'CppEclipse': 'mozbuild.backend.cpp_eclipse',
+    'FasterMake': 'mozbuild.backend.fastermake',
+    'RecursiveMake': 'mozbuild.backend.recursivemake',
+    'VisualStudio': 'mozbuild.backend.visualstudio',
+}
+
+
+def get_backend_class(name):
+    class_name = '%sBackend' % name
+    module = __import__(backends[name], globals(), locals(), [class_name])
+    return getattr(module, class_name)
--- a/python/mozbuild/mozbuild/backend/android_eclipse.py
+++ b/python/mozbuild/mozbuild/backend/android_eclipse.py
@@ -19,30 +19,40 @@ import mozpack.path as mozpath
 from .common import CommonBackend
 from ..frontend.data import (
     AndroidEclipseProjectData,
     ContextDerived,
     ContextWrapped,
 )
 from ..makeutil import Makefile
 from ..util import ensureParentDir
-from mozbuild.base import ExecutionSummary
+from mozbuild.base import (
+    ExecutionSummary,
+    MachCommandConditions,
+)
 
 
 def pretty_print(element):
     """Return a pretty-printed XML string for an Element.
     """
     s = ET.tostring(element, 'utf-8')
     # minidom wraps element in a Document node; firstChild strips it.
     return minidom.parseString(s).firstChild.toprettyxml(indent='  ')
 
 
 class AndroidEclipseBackend(CommonBackend):
     """Backend that generates Android Eclipse project files.
     """
+    def __init__(self, environment):
+        if not MachCommandConditions.is_android(environment):
+            raise Exception(
+                'The Android Eclipse backend is not available with this '
+                'configuration.')
+
+        super(AndroidEclipseBackend, self).__init__(environment)
 
     def summary(self):
         return ExecutionSummary(
             'AndroidEclipse backend executed in {execution_time:.2f}s\n'
             'Wrote {projects:d} Android Eclipse projects to {path:s}; '
             '{created:d} created; {updated:d} updated',
             execution_time=self._execution_time,
             projects=self._created_count + self._updated_count,
--- a/python/mozbuild/mozbuild/backend/cpp_eclipse.py
+++ b/python/mozbuild/mozbuild/backend/cpp_eclipse.py
@@ -21,16 +21,22 @@ from mozbuild.base import ExecutionSumma
 # /Users/bgirard/mozilla/eclipse/eclipse/eclipse/eclipse -application org.eclipse.cdt.managedbuilder.core.headlessbuild -data $PWD/workspace -importAll $PWD/eclipse
 # Open eclipse:
 # /Users/bgirard/mozilla/eclipse/eclipse/eclipse/eclipse -data $PWD/workspace
 
 class CppEclipseBackend(CommonBackend):
     """Backend that generates Cpp Eclipse project files.
     """
 
+    def __init__(self, environment):
+        if os.name == 'nt':
+            raise Exception('Eclipse is not supported on Windows. '
+                            'Consider using Visual Studio instead.')
+        super(CppEclipseBackend, self).__init__(environment)
+
     def _init(self):
         CommonBackend._init(self)
 
         self._paths_to_defines = {}
         self._project_name = 'Gecko'
         self._workspace_dir = self._get_workspace_path()
         self._project_dir = os.path.join(self._workspace_dir, self._project_name)
         self._overwriting_workspace = os.path.isdir(self._workspace_dir)
--- a/python/mozbuild/mozbuild/config_status.py
+++ b/python/mozbuild/mozbuild/config_status.py
@@ -13,23 +13,27 @@ import os
 import subprocess
 import sys
 import time
 
 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
 
+from mozbuild.backend import (
+    backends,
+    get_backend_class,
+)
+
 
 log_manager = LoggingManager()
 
 
 ANDROID_IDE_ADVERTISEMENT = '''
 =============
 ADVERTISEMENT
 
@@ -103,20 +107,17 @@ def config_status(topobjdir='.', topsrcd
     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', 'CompileDB',
-                                 'ChromeMap'],
+    parser.add_argument('-b', '--backend', nargs='+', choices=sorted(backends),
                         default=default_backends,
                         help='what backend to build (default: %s).' %
                         ' '.join(default_backends))
     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('.')
@@ -124,72 +125,46 @@ def config_status(topobjdir='.', topsrcd
     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.
-    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)
-        elif backend == 'CompileDB':
-            from mozbuild.compilation.database import CompileDBBackend
-            backends_cls.append(CompileDBBackend)
-        elif backend == 'ChromeMap':
-            from mozbuild.codecoverage.chrome_map import ChromeMapBackend
-            backends_cls.append(ChromeMapBackend)
-        else:
-            backends_cls.append(RecursiveMakeBackend)
-
     cpu_start = time.clock()
     time_start = time.time()
 
-    backends = [cls(env) for cls in backends_cls]
+    # 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]
 
     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)
-    if len(backends) > 1:
+    if len(selected_backends) > 1:
         definitions = list(definitions)
 
-    for the_backend in backends:
+    for the_backend in selected_backends:
         the_backend.consume(definitions)
 
     execution_time = 0.0
-    for obj in chain((reader, emitter), backends):
+    for obj in chain((reader, emitter), selected_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
@@ -197,17 +172,17 @@ 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 the_backend in backends:
+        for the_backend in selected_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 'VisualStudio' not in options.backend:
         print(VISUAL_STUDIO_ADVERTISEMENT)
 
     # Advertise Eclipse if it is appropriate.
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -34,16 +34,18 @@ from mozbuild.base import (
     MozconfigLoadException,
     ObjdirMismatchException,
 )
 
 from mozpack.manifests import (
     InstallManifest,
 )
 
+from mozbuild.backend import backends
+
 
 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()
@@ -596,19 +598,17 @@ 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', nargs='+',
-        choices=['RecursiveMake', 'AndroidEclipse', 'CppEclipse',
-                 'VisualStudio', 'FasterMake', 'CompileDB', 'ChromeMap'],
+    @CommandArgument('-b', '--backend', nargs='+', choices=sorted(backends),
         help='Which backend to build.')
     def build_backend(self, backend, 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.'
--- a/python/mozbuild/mozbuild/test/backend/common.py
+++ b/python/mozbuild/mozbuild/test/backend/common.py
@@ -35,16 +35,17 @@ CONFIGS = defaultdict(lambda: {
 }, {
     'android_eclipse': {
         'defines': [
             ('MOZ_ANDROID_MIN_SDK_VERSION', '15'),
         ],
         'non_global_defines': [],
         'substs': [
             ('ANDROID_TARGET_SDK', '16'),
+            ('MOZ_WIDGET_TOOLKIT', 'android'),
         ],
     },
     'binary-components': {
         'defines': [],
         'non_global_defines': [],
         'substs': [
             ('LIB_PREFIX', 'lib'),
             ('LIB_SUFFIX', 'a'),