Bug 1092217 - Allow debugging gtests via mach gtests --debug. r=ted
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 24 Nov 2014 15:29:40 -0500
changeset 241575 9a00da3709395e699a9d006916dedcb42632422a
parent 241574 b66c71e822ca0da883458b9ae1491414d6c869b7
child 241576 0a6d23163848d24bc35fbb8e380a53e86aa62615
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs1092217
milestone36.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 1092217 - Allow debugging gtests via mach gtests --debug. r=ted
python/mozbuild/mozbuild/mach_commands.py
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -661,22 +661,38 @@ class GTestCommands(MachCommandBase):
         help="test_filter is a ':'-separated list of wildcard patterns (called the positive patterns),"
              "optionally followed by a '-' and another ':'-separated pattern list (called the negative patterns).")
     @CommandArgument('--jobs', '-j', default='1', nargs='?', metavar='jobs', type=int,
         help='Run the tests in parallel using multiple processes.')
     @CommandArgument('--tbpl-parser', '-t', action='store_true',
         help='Output test results in a format that can be parsed by TBPL.')
     @CommandArgument('--shuffle', '-s', action='store_true',
         help='Randomize the execution order of tests.')
-    def gtest(self, shuffle, jobs, gtest_filter, tbpl_parser):
+
+    @CommandArgumentGroup('debugging')
+    @CommandArgument('--debug', action='store_true', group='debugging',
+        help='Enable the debugger. Not specifying a --debugger option will result in the default debugger being used. The following arguments have no effect without this.')
+    @CommandArgument('--debugger', default=None, type=str, group='debugging',
+        help='Name of debugger to use.')
+    @CommandArgument('--debugger-args', default=None, metavar='params', type=str,
+        group='debugging',
+        help='Command-line arguments to pass to the debugger itself; split as the Bourne shell would.')
+
+    def gtest(self, shuffle, jobs, gtest_filter, tbpl_parser, debug, debugger,
+              debugger_args):
 
         # We lazy build gtest because it's slow to link
         self._run_make(directory="testing/gtest", target='gtest', ensure_exit_code=True)
 
         app_path = self.get_binary_path('app')
+        args = [app_path, '-unittest'];
+
+        if debug:
+            args = self.prepend_debugger_args(args, debugger, debugger_args)
+
         cwd = os.path.join(self.topobjdir, '_tests', 'gtest')
 
         if not os.path.isdir(cwd):
             os.makedirs(cwd)
 
         # Use GTest environment variable to control test execution
         # For details see:
         # https://code.google.com/p/googletest/wiki/AdvancedGuide#Running_Test_Programs:_Advanced_Options
@@ -690,17 +706,17 @@ class GTestCommands(MachCommandBase):
 
         if shuffle:
             gtest_env[b"GTEST_SHUFFLE"] = b"True"
 
         if tbpl_parser:
             gtest_env[b"MOZ_TBPL_PARSER"] = b"True"
 
         if jobs == 1:
-            return self.run_process([app_path, "-unittest"],
+            return self.run_process(args=args,
                                     append_env=gtest_env,
                                     cwd=cwd,
                                     ensure_exit_code=False,
                                     pass_thru=True)
 
         from mozprocess import ProcessHandlerMixin
         import functools
         def handle_line(job_id, line):
@@ -727,16 +743,53 @@ class GTestCommands(MachCommandBase):
 
         # Clamp error code to 255 to prevent overflowing multiple of
         # 256 into 0
         if exit_code > 255:
             exit_code = 255
 
         return exit_code
 
+    def prepend_debugger_args(self, args, debugger, debugger_args):
+        '''
+        Given an array with program arguments, prepend arguments to run it under a
+        debugger.
+
+        :param args: The executable and arguments used to run the process normally.
+        :param debugger: The debugger to use, or empty to use the default debugger.
+        :param debugger_args: Any additional parameters to pass to the debugger.
+        '''
+
+        import mozdebug
+
+        if not debugger:
+            # No debugger name was provided. Look for the default ones on
+            # current OS.
+            debugger = mozdebug.get_default_debugger_name(mozdebug.DebuggerSearch.KeepLooking)
+
+        debuggerInfo = mozdebug.get_debugger_info(debugger, debugger_args)
+        if not debuggerInfo:
+            print("Could not find a suitable debugger in your PATH.")
+            return 1
+
+        # Parameters come from the CLI. We need to convert them before
+        # their use.
+        if debugger_args:
+            import pymake.process
+            argv, badchar = pymake.process.clinetoargv(debugger_args, os.getcwd())
+            if badchar:
+                print("The --debugger_args you passed require a real shell to parse them.")
+                print("(We can't handle the %r character.)" % (badchar,))
+                return 1
+            debugger_args = argv;
+
+        # Prepend the debugger args.
+        args = [debuggerInfo.path] + debuggerInfo.args + args
+        return args
+
 @CommandProvider
 class ClangCommands(MachCommandBase):
     @Command('clang-complete', category='devenv',
         description='Generate a .clang_complete file.')
     def clang_complete(self):
         import shlex
 
         build_vars = {}