Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 29 Jan 2013 13:48:40 -0500
changeset 130127 6f3581295ea798d0f73c303678a06acda218b02f
parent 130126 b211a11259a7e4b622f57ca599a041cfed99149c (current diff)
parent 130071 6cca454559c8b9f0c785354f2e69441ae34650f1 (diff)
child 130128 f370ad0944a23bb3c3b2ae731fb21e111c816c2d
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone21.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
Merge m-c to inbound.
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -1,15 +1,16 @@
 # 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/.
 
 from __future__ import print_function, unicode_literals
 
 import logging
+import multiprocessing
 import os
 import subprocess
 import sys
 import which
 
 from mach.mixin.logging import LoggingMixin
 from mach.mixin.process import ProcessExecutionMixin
 
@@ -154,18 +155,18 @@ class MozbuildObject(ProcessExecutionMix
         args = [self._make_path]
 
         if directory:
             args.extend(['-C', directory])
 
         if filename:
             args.extend(['-f', filename])
 
-        #if allow_parallel:
-        #    args.append('-j%d' % self.settings.build.threads)
+        if allow_parallel:
+            args.append('-j%d' % multiprocessing.cpu_count())
 
         if ignore_errors:
             args.append('-k')
 
         if silent:
             args.append('-s')
 
         # Print entering/leaving directory messages. Some consumers look at
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -12,22 +12,30 @@ from mach.decorators import (
     CommandArgument,
     CommandProvider,
     Command,
 )
 
 from mozbuild.base import MachCommandBase
 
 
+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. BUILDING ONLY PARTS
+OF THE TREE CAN RESULT IN BAD TREE STATE. USE AT YOUR OWN RISK.
+'''.strip()
+
+
 @CommandProvider
 class Build(MachCommandBase):
     """Interface to build the tree."""
 
     @Command('build', help='Build the tree.')
-    def build(self):
+    @CommandArgument('what', default=None, nargs='*', help=BUILD_WHAT_HELP)
+    def build(self, what=None):
         # This code is only meant to be temporary until the more robust tree
         # building code in bug 780329 lands.
         from mozbuild.compilation.warnings import WarningsCollector
         from mozbuild.compilation.warnings import WarningsDatabase
 
         warnings_path = self._get_state_filename('warnings.json')
         warnings_database = WarningsDatabase()
 
@@ -47,27 +55,92 @@ class Build(MachCommandBase):
                     self.log(logging.INFO, 'compiler_warning', warning,
                         'Warning: {flag} in {filename}: {message}')
             except:
                 # This will get logged in the more robust implementation.
                 pass
 
             self.log(logging.INFO, 'build_output', {'line': line}, '{line}')
 
-        status = self._run_make(srcdir=True, filename='client.mk',
-            line_handler=on_line, log=False, print_directory=False,
-            ensure_exit_code=False)
+        def resolve_target_to_make(target):
+            if os.path.isabs(target):
+                print('Absolute paths for make targets are not allowed.')
+                return (None, None)
+
+            target = target.replace(os.sep, '/')
+
+            abs_target = os.path.join(self.topobjdir, target)
+
+            # For directories, run |make -C dir|. If the directory does not
+            # contain a Makefile, check parents until we find one. At worst,
+            # this will terminate at the root.
+            if os.path.isdir(abs_target):
+                current = abs_target
+
+                while True:
+                    make_path = os.path.join(current, 'Makefile')
+                    if os.path.exists(make_path):
+                        return (current[len(self.topobjdir) + 1:], None)
+
+                    current = os.path.dirname(current)
+
+            # If it's not in a directory, this is probably a top-level make
+            # target. Treat it as such.
+            if '/' not in target:
+                return (None, target)
+
+            # We have a relative path within the tree. We look for a Makefile
+            # as far into the path as possible. Then, we compute the make
+            # target as relative to that directory.
+            reldir = os.path.dirname(target)
+            target = os.path.basename(target)
+
+            while True:
+                make_path = os.path.join(self.topobjdir, reldir, 'Makefile')
 
-        self.log(logging.WARNING, 'warning_summary',
-            {'count': len(warnings_collector.database)},
-            '{count} compiler warnings present.')
+                if os.path.exists(make_path):
+                    return (reldir, target)
+
+                target = os.path.join(os.path.basename(reldir), target)
+                reldir = os.path.dirname(reldir)
+
+        # End of resolve_target_to_make.
+
+        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
+
+            for target in what:
+                make_dir, make_target = resolve_target_to_make(target)
+
+                if make_dir is None and make_target is None:
+                    return 1
+
+                status = self._run_make(directory=make_dir, target=make_target,
+                    line_handler=on_line, log=False, print_directory=False,
+                    ensure_exit_code=False)
+
+                if status != 0:
+                    break
+        else:
+            status = self._run_make(srcdir=True, filename='client.mk',
+                line_handler=on_line, log=False, print_directory=False,
+                allow_parallel=False, ensure_exit_code=False)
+
+            self.log(logging.WARNING, 'warning_summary',
+                {'count': len(warnings_collector.database)},
+                '{count} compiler warnings present.')
 
         warnings_database.prune()
+        warnings_database.save_to_file(warnings_path)
 
-        warnings_database.save_to_file(warnings_path)
+        print('Finished building. Built files are in %s' % self.topobjdir)
 
         return status
 
     @Command('clobber', help='Clobber the tree (delete the object directory).')
     def clobber(self):
         self.remove_objdir()
         return 0