aprantl created this revision.

This patch is the result of a discussion on lldb-dev, see 
http://lists.llvm.org/pipermail/lldb-dev/2018-January/013111.html for 
background.

This is a first sketch of how to move building of the testcases in the LLDB 
testsuite out of the source tree. The patch is buggy and incomplete, but I 
would like to develop this as much in the open as possible to solicit early 
feedback in case I'm unwittingly cutting any corners that will break somebody's 
platform.

For each test (should be eventually: each test configuration) a separate build 
directory is created and we execute `make VPATH=$srcdir/path/to/test -C 
$builddir/path/to/test -f $srcdir/path/to/test/Makefile -I 
$srcdir/path/to/test`.

In order to make this work all LLDB tests need to be updated to find the 
executable in the test build directory, since CWD still points at the test's 
source directory, which is a requirement for unittest2. That patch is very 
boring and therefore outsourced to https://reviews.llvm.org/D42280 to make this 
review easier to read.


https://reviews.llvm.org/D42281

Files:
  packages/Python/lldbsuite/test/configuration.py
  packages/Python/lldbsuite/test/dotest.py
  packages/Python/lldbsuite/test/dotest_args.py
  packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/Makefile
  
packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/TestStepNoDebug.py
  packages/Python/lldbsuite/test/lldbtest.py
  packages/Python/lldbsuite/test/plugins/builder_base.py

Index: packages/Python/lldbsuite/test/plugins/builder_base.py
===================================================================
--- packages/Python/lldbsuite/test/plugins/builder_base.py
+++ packages/Python/lldbsuite/test/plugins/builder_base.py
@@ -50,13 +50,23 @@
 
     return ("ARCHFLAG=" + archflag) if archflag else ""
 
-
-def getMake():
-    """Returns the name for GNU make"""
+def getMake(rel_testdir):
+    """Returns the invocation for GNU make"""
     if platform.system() == "FreeBSD" or platform.system() == "NetBSD":
-        return "gmake"
+        make = "gmake"
     else:
-        return "make"
+        make = "make"
+
+    # Construct the base make invocation.
+    lldb_test = os.environ["LLDB_TEST"]
+    lldb_build = os.environ["LLDB_BUILD"]
+    build_dir = os.path.join(lldb_build, rel_testdir)
+    test_dir = os.path.join(lldb_test, rel_testdir)
+    return [make,
+            "VPATH="+test_dir,
+            "-C", build_dir,
+            "-I", test_dir,
+            "-f", os.path.join(test_dir, "Makefile")]
 
 
 def getArchSpec(architecture):
@@ -121,12 +131,13 @@
         architecture=None,
         compiler=None,
         dictionary=None,
-        clean=True):
+        clean=True,
+        testdir=None):
     """Build the binaries the default way."""
     commands = []
     if clean:
-        commands.append([getMake(), "clean", getCmdLine(dictionary)])
-    commands.append([getMake(), getArchSpec(architecture),
+        commands.append(getMake(testdir) + ["clean", getCmdLine(dictionary)])
+    commands.append(getMake(testdir) + [getArchSpec(architecture),
                      getCCSpec(compiler), getCmdLine(dictionary)])
 
     runBuildCommands(commands, sender=sender)
@@ -140,12 +151,13 @@
         architecture=None,
         compiler=None,
         dictionary=None,
-        clean=True):
+        clean=True,
+        testdir=None):
     """Build the binaries with dwarf debug info."""
     commands = []
     if clean:
-        commands.append([getMake(), "clean", getCmdLine(dictionary)])
-    commands.append([getMake(), "MAKE_DSYM=NO", getArchSpec(
+        commands.append(getMake(testdir) + ["clean", getCmdLine(dictionary)])
+    commands.append(getMake(testdir) + ["MAKE_DSYM=NO", getArchSpec(
         architecture), getCCSpec(compiler), getCmdLine(dictionary)])
 
     runBuildCommands(commands, sender=sender)
@@ -158,13 +170,17 @@
         architecture=None,
         compiler=None,
         dictionary=None,
-        clean=True):
+        clean=True,
+        testdir=None):
     """Build the binaries with dwarf debug info."""
     commands = []
     if clean:
-        commands.append([getMake(), "clean", getCmdLine(dictionary)])
-    commands.append([getMake(), "MAKE_DSYM=NO", "MAKE_DWO=YES", getArchSpec(
-        architecture), getCCSpec(compiler), getCmdLine(dictionary)])
+        commands.append(getMake(testdir) + ["clean", getCmdLine(dictionary)])
+    commands.append(getMake(testdir) +
+                    ["MAKE_DSYM=NO", "MAKE_DWO=YES",
+                     getArchSpec(architecture),
+                     getCCSpec(compiler),
+                     getCmdLine(dictionary)])
 
     runBuildCommands(commands, sender=sender)
     # True signifies that we can handle building dwo.
@@ -176,12 +192,13 @@
         architecture=None,
         compiler=None,
         dictionary=None,
-        clean=True):
+        clean=True,
+        testdir=None):
     """Build the binaries with dwarf debug info."""
     commands = []
     if clean:
-        commands.append([getMake(), "clean", getCmdLine(dictionary)])
-    commands.append([getMake(),
+        commands.append(getMake(testdir) + ["clean", getCmdLine(dictionary)])
+    commands.append([getMake(testdir),
                      "MAKE_DSYM=NO",
                      "MAKE_GMODULES=YES",
                      getArchSpec(architecture),
@@ -195,12 +212,13 @@
 
 def cleanup(sender=None, dictionary=None):
     """Perform a platform-specific cleanup after the test."""
-    #import traceback
-    # traceback.print_stack()
-    commands = []
-    if os.path.isfile("Makefile"):
-        commands.append([getMake(), "clean", getCmdLine(dictionary)])
-
-    runBuildCommands(commands, sender=sender)
-    # True signifies that we can handle cleanup.
     return True
+    #  #import traceback
+    #  # traceback.print_stack()
+    #  commands = []
+    #  if os.path.isfile("Makefile"):
+    #      commands.append(getMake("") + ["clean", getCmdLine(dictionary)])
+    #   
+    #  runBuildCommands(commands, sender=sender)
+    #  # True signifies that we can handle cleanup.
+    #  return True
Index: packages/Python/lldbsuite/test/lldbtest.py
===================================================================
--- packages/Python/lldbsuite/test/lldbtest.py
+++ packages/Python/lldbsuite/test/lldbtest.py
@@ -553,6 +553,7 @@
                 print("Change dir to:", full_dir, file=sys.stderr)
             os.chdir(os.path.join(os.environ["LLDB_TEST"], cls.mydir))
 
+        # TODO: Obsolete this by creating one working dir per configuration.
         if debug_confirm_directory_exclusivity:
             import lock
             cls.dir_lock = lock.Lock(os.path.join(full_dir, ".dirlock"))
@@ -1490,84 +1491,69 @@
             architecture=None,
             compiler=None,
             dictionary=None,
-            clean=True):
+            clean=True,
+            testdir=None):
         """Platform specific way to build the default binaries."""
         module = builder_module()
         dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
-        if not module.buildDefault(
-                self,
-                architecture,
-                compiler,
-                dictionary,
-                clean):
+        if not module.buildDefault(self, architecture, compiler,
+                                   dictionary, clean, testdir):
             raise Exception("Don't know how to build default binary")
 
     def buildDsym(
             self,
             architecture=None,
             compiler=None,
             dictionary=None,
-            clean=True):
+            clean=True,
+            testdir=None):
         """Platform specific way to build binaries with dsym info."""
         module = builder_module()
         dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
-        if not module.buildDsym(
-                self,
-                architecture,
-                compiler,
-                dictionary,
-                clean):
+        if not module.buildDsym(self, architecture, compiler,
+                                dictionary, clean, testdir):
             raise Exception("Don't know how to build binary with dsym")
 
     def buildDwarf(
             self,
             architecture=None,
             compiler=None,
             dictionary=None,
-            clean=True):
+            clean=True,
+            testdir=None):
         """Platform specific way to build binaries with dwarf maps."""
         module = builder_module()
         dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
-        if not module.buildDwarf(
-                self,
-                architecture,
-                compiler,
-                dictionary,
-                clean):
+        if not module.buildDwarf(self, architecture, compiler,
+                                   dictionary, clean, testdir):
             raise Exception("Don't know how to build binary with dwarf")
 
     def buildDwo(
             self,
             architecture=None,
             compiler=None,
             dictionary=None,
-            clean=True):
+            clean=True,
+            testdir=None):
         """Platform specific way to build binaries with dwarf maps."""
         module = builder_module()
         dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
-        if not module.buildDwo(
-                self,
-                architecture,
-                compiler,
-                dictionary,
-                clean):
+        if not module.buildDwo(self, architecture, compiler,
+                                   dictionary, clean, testdir):
             raise Exception("Don't know how to build binary with dwo")
 
     def buildGModules(
             self,
             architecture=None,
             compiler=None,
             dictionary=None,
-            clean=True):
+            clean=True,
+            testdir=None):
         """Platform specific way to build binaries with gmodules info."""
         module = builder_module()
         dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
-        if not module.buildGModules(
-                self,
-                architecture,
-                compiler,
-                dictionary,
-                clean):
+        if not module.buildGModules(self, architecture, compiler,
+                                   dictionary, clean, testdir):
             raise Exception("Don't know how to build binary with gmodules")
 
     def buildGo(self):
@@ -2253,18 +2239,30 @@
             clean=True):
         """Platform specific way to build the default binaries."""
         module = builder_module()
+
+        # Create the test-specific working directory if ${LLDB_BUILD} is defined.
+        # See also dotest.py which sets up ${LLDB_BUILD}.
+        if ("LLDB_BUILD" in os.environ):
+            full_dir = os.path.join(os.environ["LLDB_BUILD"], self.mydir)
+            try: os.makedirs(full_dir)
+            except: pass
+ 
         dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
         if self.debug_info is None:
-            return self.buildDefault(architecture, compiler, dictionary, clean)
+            return self.buildDefault(architecture, compiler, dictionary,
+                                     clean, self.mydir)
         elif self.debug_info == "dsym":
-            return self.buildDsym(architecture, compiler, dictionary, clean)
+            return self.buildDsym(architecture, compiler, dictionary,
+                                  clean, self.mydir)
         elif self.debug_info == "dwarf":
-            return self.buildDwarf(architecture, compiler, dictionary, clean)
+            return self.buildDwarf(architecture, compiler, dictionary,
+                                   clean, self.mydir)
         elif self.debug_info == "dwo":
-            return self.buildDwo(architecture, compiler, dictionary, clean)
+            return self.buildDwo(architecture, compiler, dictionary,
+                                 clean, self.mydir)
         elif self.debug_info == "gmodules":
-            return self.buildGModules(
-                architecture, compiler, dictionary, clean)
+            return self.buildGModules(architecture, compiler, dictionary,
+                                      clean, self.mydir)
         else:
             self.fail("Can't build for debug info: %s" % self.debug_info)
 
Index: packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/TestStepNoDebug.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/TestStepNoDebug.py
+++ packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/TestStepNoDebug.py
@@ -92,7 +92,7 @@
             (name, pattern))
 
     def get_to_starting_point(self):
-        exe = os.path.join(os.getcwd(), "a.out")
+        exe = os.path.join(os.environ["LLDB_BUILD"], self.mydir, "a.out")
         error = lldb.SBError()
 
         self.target = self.dbg.CreateTarget(exe)
Index: packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/Makefile
===================================================================
--- packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/Makefile
+++ packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/Makefile
@@ -5,4 +5,4 @@
 include $(LEVEL)/Makefile.rules
 
 without-debug.o: without-debug.c
-	$(CC) $(CFLAGS_NO_DEBUG) -c without-debug.c	
+	$(CC) $(CFLAGS_NO_DEBUG) -c $<
Index: packages/Python/lldbsuite/test/dotest_args.py
===================================================================
--- packages/Python/lldbsuite/test/dotest_args.py
+++ packages/Python/lldbsuite/test/dotest_args.py
@@ -159,6 +159,11 @@
         metavar='Codesigning identity',
         default='lldb_codesign',
         help='The codesigning identity to use')
+    group.add_argument(
+        '--build-dir',
+        dest='test_build_dir',
+        metavar='Test build directory',
+        help='The root build directory for the tests')
 
     # Configuration options
     group = parser.add_argument_group('Remote platform options')
Index: packages/Python/lldbsuite/test/dotest.py
===================================================================
--- packages/Python/lldbsuite/test/dotest.py
+++ packages/Python/lldbsuite/test/dotest.py
@@ -472,6 +472,8 @@
         configuration.lldb_platform_url = args.lldb_platform_url
     if args.lldb_platform_working_dir:
         configuration.lldb_platform_working_dir = args.lldb_platform_working_dir
+    if args.test_build_dir:
+        configuration.test_build_dir = args.test_build_dir
 
     if args.event_add_entries and len(args.event_add_entries) > 0:
         entries = {}
@@ -620,6 +622,7 @@
         sys.exit(-1)
 
     os.environ["LLDB_TEST"] = scriptPath
+    os.environ["LLDB_BUILD"] = configuration.test_build_dir
 
     # Set up the LLDB_SRC environment variable, so that the tests can locate
     # the LLDB source code.
@@ -1185,6 +1188,15 @@
         configuration.lldb_platform_working_dir = None
         configuration.lldb_platform_url = None
 
+    # Set up the working directory.
+    # Note that it's not dotest's job to clean this directory.
+    orig_working_dir = os.getcwd()
+    if configuration.test_build_dir:
+        try: os.makedirs(configuration.test_build_dir, 448)
+        except: pass
+    else:
+        configuration.test_build_dir = os.getcwd()
+
     target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2]
 
     checkLibcxxSupport()
Index: packages/Python/lldbsuite/test/configuration.py
===================================================================
--- packages/Python/lldbsuite/test/configuration.py
+++ packages/Python/lldbsuite/test/configuration.py
@@ -141,6 +141,9 @@
 lldb_platform_url = None
 lldb_platform_working_dir = None
 
+# The base directory in which the tests are being built.
+test_build_dir = None
+
 # Parallel execution settings
 is_inferior_test_runner = False
 multiprocess_test_subdir = None
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to