Bug 1027890 - Reject builds with pymake. r=gps
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 25 Jun 2014 08:38:12 +0900
changeset 211550 8aac3c8dc7bbe519da1accfe062adb34397296fb
parent 211549 85c88938e5207b3dcdff8258def2fcac86b76fbc
child 211551 6401390a005df7ae8b6b44f179cb75cc7de79ba9
child 211700 549e5f2e49d0b8cf50b232982ab437a270cd4249
push id3857
push userraliiev@mozilla.com
push dateTue, 02 Sep 2014 16:39:23 +0000
treeherdermozilla-beta@5638b907b505 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1027890
milestone33.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 1027890 - Reject builds with pymake. r=gps
b2g/installer/Makefile.in
build/pymake/make.py
config/baseconfig.mk
python/mozbuild/mozbuild/base.py
python/mozbuild/mozbuild/mach_commands.py
--- a/b2g/installer/Makefile.in
+++ b/b2g/installer/Makefile.in
@@ -92,16 +92,18 @@ ifdef MOZ_CHROME_MULTILOCALE
 	  printf '$(BINPATH)/chrome/'"$$LOCALE"'.manifest\n' >> $@; \
 	done
 endif
 
 GARBAGE += $(MOZ_PKG_MANIFEST)
 endif
 
 ifdef FXOS_SIMULATOR
+export MAKE
+
 .PHONY: simulator
 simulator: make-package
 	@echo 'Building simulator addon...'
 	$(PYTHON) $(topsrcdir)/b2g/simulator/build_xpi.py $(MOZ_PKG_PLATFORM)
 
 libs:: simulator
 
 # Ensure copying Simulator xpi to ftp
--- a/build/pymake/make.py
+++ b/build/pymake/make.py
@@ -13,23 +13,22 @@ import gc
 
 if __name__ == '__main__':
   if 'TINDERBOX_OUTPUT' in os.environ:
     # When building on mozilla build slaves, execute mozmake instead. Until bug
     # 978211, this is the easiest, albeit hackish, way to do this.
     import subprocess
     mozmake = os.path.join(os.path.dirname(__file__), '..', '..',
         'mozmake.exe')
-    if os.path.exists(mozmake):
-        cmd = [mozmake]
-        cmd.extend(sys.argv[1:])
-        shell = os.environ.get('SHELL')
-        if shell and not shell.lower().endswith('.exe'):
-            cmd += ['SHELL=%s.exe' % shell]
-        sys.exit(subprocess.call(cmd))
+    cmd = [mozmake]
+    cmd.extend(sys.argv[1:])
+    shell = os.environ.get('SHELL')
+    if shell and not shell.lower().endswith('.exe'):
+        cmd += ['SHELL=%s.exe' % shell]
+    sys.exit(subprocess.call(cmd))
 
   sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
   sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0)
 
   gc.disable()
 
   pymake.command.main(sys.argv[1:], os.environ, os.getcwd(), cb=sys.exit)
   pymake.process.ParallelContext.spin()
--- a/config/baseconfig.mk
+++ b/config/baseconfig.mk
@@ -20,37 +20,36 @@ endif
 endif
 
 # We do magic with OBJ_SUFFIX in config.mk, the following ensures we don't
 # manually use it before config.mk inclusion
 _OBJ_SUFFIX := $(OBJ_SUFFIX)
 OBJ_SUFFIX = $(error config/config.mk needs to be included before using OBJ_SUFFIX)
 
 ifeq ($(HOST_OS_ARCH),WINNT)
-# We only support building with pymake or a non-msys gnu make version
+# We only support building with a non-msys gnu make version
 # strictly above 4.0.
-ifndef .PYMAKE
+ifdef .PYMAKE
+$(error Pymake is no longer supported. Please upgrade to MozillaBuild 1.9 or newer and build with 'mach' or 'mozmake')
+endif
+
 ifeq (a,$(firstword a$(subst /, ,$(abspath .))))
 $(error MSYS make is not supported)
 endif
 # 4.0- happens to be greater than 4.0, lower than the mozmake version,
 # and lower than 4.0.1 or 4.1, whatever next version of gnu make will
 # be released.
 ifneq (4.0-,$(firstword $(sort 4.0- $(MAKE_VERSION))))
 $(error Make version too old. Only versions strictly greater than 4.0 are supported.)
 endif
-endif
+
 ifdef INCLUDED_AUTOCONF_MK
 ifeq (a,$(firstword a$(subst /, ,$(srcdir))))
 $(error MSYS-style srcdir are not supported for Windows builds.)
 endif
 endif
 endif # WINNT
 
-ifdef .PYMAKE
-include_deps = $(eval $(if $(2),,-)includedeps $(1))
-else
 include_deps = $(eval $(if $(2),,-)include $(1))
-endif
 
 ifndef INCLUDED_AUTOCONF_MK
 default::
 endif
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -391,33 +391,32 @@ class MozbuildObject(ProcessExecutionMix
 
     def _wrap_path_argument(self, arg):
         return PathArgument(arg, self.topsrcdir, self.topobjdir)
 
     def _run_make(self, directory=None, filename=None, target=None, log=True,
             srcdir=False, allow_parallel=True, line_handler=None,
             append_env=None, explicit_env=None, ignore_errors=False,
             ensure_exit_code=0, silent=True, print_directory=True,
-            pass_thru=False, num_jobs=0, force_pymake=False):
+            pass_thru=False, num_jobs=0):
         """Invoke make.
 
         directory -- Relative directory to look for Makefile in.
         filename -- Explicit makefile to run.
         target -- Makefile target(s) to make. Can be a string or iterable of
             strings.
         srcdir -- If True, invoke make from the source directory tree.
             Otherwise, make will be invoked from the object directory.
         silent -- If True (the default), run make in silent mode.
         print_directory -- If True (the default), have make print directories
         while doing traversal.
-        force_pymake -- If True, pymake will be used instead of GNU make.
         """
         self._ensure_objdir_exists()
 
-        args = self._make_path(force_pymake=force_pymake)
+        args = self._make_path()
 
         if directory:
             args.extend(['-C', directory.replace(os.sep, '/')])
 
         if filename:
             args.extend(['-f', filename])
 
         if allow_parallel:
@@ -470,54 +469,55 @@ class MozbuildObject(ProcessExecutionMix
             'ignore_children': True,
         }
 
         if log:
             params['log_name'] = 'make'
 
         return fn(**params)
 
-    def _make_path(self, force_pymake=False):
-        if self._is_windows() and not force_pymake:
-            # Use gnumake if it's available and we can verify it's a working
-            # version.
-            baseconfig = os.path.join(self.topsrcdir, 'config', 'baseconfig.mk')
-            if os.path.exists(baseconfig):
-                try:
-                    make = which.which('gnumake')
-                    subprocess.check_call([make, '-f', baseconfig, 'HOST_OS_ARCH=WINNT'],
-                        stdout=open(os.devnull, 'wb'), stderr=subprocess.STDOUT)
-                    return [make]
-                except subprocess.CalledProcessError:
-                    pass
-                except which.WhichError:
-                    pass
+    def _make_path(self):
+        baseconfig = os.path.join(self.topsrcdir, 'config', 'baseconfig.mk')
 
-            # Use mozmake if it's available.
-            try:
-                return [which.which('mozmake')]
-            except which.WhichError:
-                pass
+        def validate_make(make):
+            if os.path.exists(baseconfig) and os.path.exists(make):
+                cmd = [make, '-f', baseconfig]
+                if self._is_windows():
+                    cmd.append('HOST_OS_ARCH=WINNT')
+                try:
+                    subprocess.check_call(cmd, stdout=open(os.devnull, 'wb'),
+                        stderr=subprocess.STDOUT)
+                except subprocess.CalledProcessError:
+                    return False
+                return True
+            return False
 
-        if self._is_windows() or force_pymake:
-            make_py = os.path.join(self.topsrcdir, 'build', 'pymake',
-                'make.py').replace(os.sep, '/')
+        possible_makes = ['gmake', 'make', 'mozmake', 'gnumake']
 
-            # We might want to consider invoking with the virtualenv's Python
-            # some day. But, there is a chicken-and-egg problem w.r.t. when the
-            # virtualenv is created.
-            return [sys.executable, make_py]
+        if 'MAKE' in os.environ:
+            make = os.environ['MAKE']
+            if os.path.isabs(make):
+                if validate_make(make):
+                    return [make]
+            else:
+                possible_makes.insert(0, make)
 
-        for test in ['gmake', 'make']:
+        for test in possible_makes:
             try:
-                return [which.which(test)]
+                make = which.which(test)
             except which.WhichError:
                 continue
+            if validate_make(make):
+                return [make]
 
-        raise Exception('Could not find a suitable make implementation.')
+        if self._is_windows():
+            raise Exception('Could not find a suitable make implementation.\n'
+                'Please use MozillaBuild 1.9 or newer')
+        else:
+            raise Exception('Could not find a suitable make implementation.')
 
     def _run_command_in_srcdir(self, **args):
         return self.run_process(cwd=self.topsrcdir, **args)
 
     def _run_command_in_objdir(self, **args):
         return self.run_process(cwd=self.topobjdir, **args)
 
     def _is_windows(self):
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -262,25 +262,23 @@ class BuildOutputManager(LoggingMixin):
 @CommandProvider
 class Build(MachCommandBase):
     """Interface to build the tree."""
 
     @Command('build', category='build', description='Build the tree.')
     @CommandArgument('--jobs', '-j', default='0', metavar='jobs', type=int,
         help='Number of concurrent jobs to run. Default is the number of CPUs.')
     @CommandArgument('what', default=None, nargs='*', help=BUILD_WHAT_HELP)
-    @CommandArgument('-p', '--pymake', action='store_true',
-        help='Force using pymake over GNU make.')
     @CommandArgument('-X', '--disable-extra-make-dependencies',
                      default=False, action='store_true',
                      help='Do not add extra make dependencies.')
     @CommandArgument('-v', '--verbose', action='store_true',
         help='Verbose output for what commands the build is running.')
-    def build(self, what=None, pymake=False,
-        disable_extra_make_dependencies=None, jobs=0, verbose=False):
+    def build(self, what=None, disable_extra_make_dependencies=None, jobs=0,
+        verbose=False):
         import which
         from mozbuild.controller.building import BuildMonitor
         from mozbuild.util import resolve_target_to_make
 
         self.log_manager.register_structured_logger(logging.getLogger('mozbuild'))
 
         warnings_path = self._get_state_filename('warnings.json')
         monitor = self._spawn(BuildMonitor)
@@ -338,49 +336,47 @@ class Build(MachCommandBase):
 
                 # 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.RecursiveMakeBackend',
-                    force_pymake=pymake, line_handler=output.on_line,
-                    log=False, print_directory=False)
+                    line_handler=output.on_line, log=False,
+                    print_directory=False)
 
                 # 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'},
-                        force_pymake=pymake)
+                        append_env={b'NO_BUILDSTATUS_MESSAGES': b'1'})
 
                     if status != 0:
                         break
             else:
                 monitor.start_resource_recording()
                 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, force_pymake=pymake)
+                    silent=not verbose)
 
                 make_extra = self.mozconfig['make_extra'] or []
                 make_extra = dict(m.split('=', 1) for m in make_extra)
 
                 moz_automation = os.getenv('MOZ_AUTOMATION') or make_extra.get('export MOZ_AUTOMATION', None)
                 if moz_automation and status == 0:
                     status = self._run_make(target='automation/build',
                         line_handler=output.on_line, log=False, print_directory=False,
-                        ensure_exit_code=False, num_jobs=jobs, silent=not verbose,
-                        force_pymake=pymake)
+                        ensure_exit_code=False, num_jobs=jobs, silent=not verbose)
 
                 self.log(logging.WARNING, 'warning_summary',
                     {'count': len(monitor.warnings_database)},
                     '{count} compiler warnings present.')
 
             monitor.finish(record_usage=status==0)
 
         high_finder, finder_percent = monitor.have_high_finder_usage()