LLVMBuild: Introduce a common section which currently has a list of the
[oota-llvm.git] / utils / llvm-build / llvmbuild / main.py
index c77ffcd14b349e5671de9cf0248dee33193fe521..279a10f5f199743dfa643f1597bc3feb4237ab16 100644 (file)
@@ -1,3 +1,4 @@
+import StringIO
 import os
 import sys
 
@@ -213,14 +214,45 @@ class LLVMProjectInfo(object):
 
             info_basedir[ci.subpath] = info_basedir.get(ci.subpath, []) + [ci]
 
+        # Compute the list of subdirectories to scan.
+        subpath_subdirs = {}
+        for ci in self.component_infos:
+            # Ignore root components.
+            if ci.subpath == '/':
+                continue
+
+            # Otherwise, append this subpath to the parent list.
+            parent_path = os.path.dirname(ci.subpath)
+            subpath_subdirs[parent_path] = parent_list = subpath_subdirs.get(
+                parent_path, set())
+            parent_list.add(os.path.basename(ci.subpath))
+
         # Generate the build files.
         for subpath, infos in info_basedir.items():
             # Order the components by name to have a canonical ordering.
             infos.sort(key = lambda ci: ci.name)
 
             # Format the components into llvmbuild fragments.
-            fragments = filter(None, [ci.get_llvmbuild_fragment()
-                                      for ci in infos])
+            fragments = []
+
+            # Add the common fragments.
+            subdirectories = subpath_subdirs.get(subpath)
+            if subdirectories:
+                fragment = """\
+subdirectories = %s
+""" % (" ".join(sorted(subdirectories)),)
+                fragments.append(("common", fragment))
+
+            # Add the component fragments.
+            num_common_fragments = len(fragments)
+            for ci in infos:
+                fragment = ci.get_llvmbuild_fragment()
+                if fragment is None:
+                    continue
+
+                name = "component_%d" % (len(fragments) - num_common_fragments)
+                fragments.append((name, fragment))
+
             if not fragments:
                 continue
 
@@ -231,7 +263,22 @@ class LLVMProjectInfo(object):
             if not os.path.exists(directory_path):
                 os.makedirs(directory_path)
 
-            # Create the LLVMBuild file.
+            # In an effort to preserve comments (which aren't parsed), read in
+            # the original file and extract the comments. We only know how to
+            # associate comments that prefix a section name.
+            f = open(infos[0]._source_path)
+            comments_map = {}
+            comment_block = ""
+            for ln in f:
+                if ln.startswith(';'):
+                    comment_block += ln
+                elif ln.startswith('[') and ln.endswith(']\n'):
+                    comments_map[ln[1:-2]] = comment_block
+                else:
+                    comment_block = ""
+            f.close()
+
+            # Create the LLVMBuild fil[e.
             file_path = os.path.join(directory_path, 'LLVMBuild.txt')
             f = open(file_path, "w")
 
@@ -259,10 +306,16 @@ class LLVMProjectInfo(object):
 ;===------------------------------------------------------------------------===;
 """ % header_string
 
-            for i,fragment in enumerate(fragments):
-                print >>f, '[component_%d]' % i
+            # Write out each fragment.each component fragment.
+            for name,fragment in fragments:
+                comment = comments_map.get(name)
+                if comment is not None:
+                    f.write(comment)
+                print >>f, "[%s]" % name
                 f.write(fragment)
-                print >>f
+                if fragment is not fragments[-1][1]:
+                    print >>f
+
             f.close()
 
     def write_library_table(self, output_path):
@@ -397,9 +450,15 @@ class LLVMProjectInfo(object):
         # Construct a list of all the dependencies of the Makefile fragment
         # itself. These include all the LLVMBuild files themselves, as well as
         # all of our own sources.
+        #
+        # Many components may come from the same file, so we make sure to unique
+        # these.
+        build_paths = set()
         for ci in self.component_infos:
-            yield os.path.join(self.source_root, ci.subpath[1:],
-                               'LLVMBuild.txt')
+            p = os.path.join(self.source_root, ci.subpath[1:], 'LLVMBuild.txt')
+            if p not in build_paths:
+                yield p
+                build_paths.add(p)
 
         # Gather the list of necessary sources by just finding all loaded
         # modules that are inside the LLVM source tree.
@@ -639,6 +698,7 @@ def add_magic_target_components(parser, project, opts):
             fatal("special component %r must have empty %r list" % (
                     name, 'add_to_library_groups'))
 
+        info._is_special_group = True
         return info
 
     info_map = dict((ci.name, ci) for ci in project.component_infos)