OSDN Git Service

llvm-build: Add "--write-library-table" option for generating the C++ library
authorDaniel Dunbar <daniel@zuster.org>
Thu, 3 Nov 2011 17:56:28 +0000 (17:56 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Thu, 3 Nov 2011 17:56:28 +0000 (17:56 +0000)
dependency table used by llvm-config.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@143628 91177308-0d34-0410-b5e6-96231b3b80d8

docs/CommandGuide/llvm-build.pod
utils/llvm-build/llvmbuild/componentinfo.py
utils/llvm-build/llvmbuild/main.py

index 6f70ffe..2ccc1a2 100644 (file)
@@ -36,6 +36,13 @@ the B<llvm-build> script itself.
 
 Print the component tree for the project.
 
+=item B<--write-library-table>
+
+Write out the C++ fragment which defines the components, library names, and
+required libraries. This C++ fragment is built into L<llvm-config|llvm-config>
+in order to provide clients with the list of required libraries for arbitrary
+component combinations.
+
 =item B<--write-llvmbuild>
 
 Write out new I<LLVMBuild.txt> files based on the loaded components. This is
index 3ea8001..fb45571 100644 (file)
@@ -135,6 +135,12 @@ class LibraryComponentInfo(ComponentInfo):
                 self.add_to_library_groups)
         return result.getvalue()
 
+    def get_library_name(self):
+        return self.library_name or self.name
+
+    def get_llvmconfig_component_name(self):
+        return self.get_library_name().lower()
+
 class LibraryGroupComponentInfo(ComponentInfo):
     type_name = 'LibraryGroup'
 
@@ -179,6 +185,9 @@ class LibraryGroupComponentInfo(ComponentInfo):
                 self.add_to_library_groups)
         return result.getvalue()
 
+    def get_llvmconfig_component_name(self):
+        return self.name.lower()
+
 class ToolComponentInfo(ComponentInfo):
     type_name = 'Tool'
 
index 16d8168..892242d 100644 (file)
@@ -54,6 +54,10 @@ class LLVMProjectInfo(object):
                         ci.name, ci.subpath, existing.subpath))
             self.component_info_map[ci.name] = ci
 
+        # Disallow 'all' as a component name, which is a special case.
+        if 'all' in self.component_info_map:
+            fatal("project is not allowed to define 'all' component")
+
         # Add the root component.
         if '$ROOT' in self.component_info_map:
             fatal("project is not allowed to define $ROOT component")
@@ -164,6 +168,94 @@ class LLVMProjectInfo(object):
                 print >>f
             f.close()
 
+    def write_library_table(self, output_path):
+        # Write out the mapping from component names to required libraries.
+        #
+        # We do this in topological order so that we know we can append the
+        # dependencies for added library groups.
+        entries = {}
+        for c in self.ordered_component_infos:
+            # Only Library and LibraryGroup components are in the table.
+            if c.type_name not in ('Library', 'LibraryGroup'):
+                continue
+
+            # Compute the llvm-config "component name". For historical reasons,
+            # this is lowercased based on the library name.
+            llvmconfig_component_name = c.get_llvmconfig_component_name()
+            
+            # Get the library name, or None for LibraryGroups.
+            if c.type_name == 'LibraryGroup':
+                library_name = None
+            else:
+                library_name = c.get_library_name()
+
+            # Get the component names of all the required libraries.
+            required_llvmconfig_component_names = [
+                self.component_info_map[dep].get_llvmconfig_component_name()
+                for dep in c.required_libraries]
+
+            # Insert the entries for library groups we should add to.
+            for dep in c.add_to_library_groups:
+                entries[dep][2].append(llvmconfig_component_name)
+
+            # Add the entry.
+            entries[c.name] = (llvmconfig_component_name, library_name,
+                               required_llvmconfig_component_names)
+
+        # Convert to a list of entries and sort by name.
+        entries = entries.values()
+
+        # Create an 'all' pseudo component. We keep the dependency list small by
+        # only listing entries that have no other dependents.
+        root_entries = set(e[0] for e in entries)
+        for _,_,deps in entries:
+            root_entries -= set(deps)
+        entries.append(('all', None, root_entries))
+
+        entries.sort()
+
+        # Compute the maximum number of required libraries, plus one so there is
+        # always a sentinel.
+        max_required_libraries = max(len(deps)
+                                     for _,_,deps in entries) + 1
+
+        # Write out the library table.
+        f = open(output_path, 'w')
+        print >>f, """\
+//===- llvm-build generated file --------------------------------*- C++ -*-===//
+//
+// Component Library Depenedency Table
+//
+// Automatically generated file, do not edit!
+//
+//===----------------------------------------------------------------------===//
+"""
+        print >>f, 'struct AvailableComponent {'
+        print >>f, '  /// The name of the component.'
+        print >>f, '  const char *Name;'
+        print >>f, ''
+        print >>f, '  /// The name of the library for this component (or NULL).'
+        print >>f, '  const char *Library;'
+        print >>f, ''
+        print >>f, '\
+  /// The list of libraries required when linking this component.'
+        print >>f, '  const char *RequiredLibraries[%d];' % (
+            max_required_libraries)
+        print >>f, '} AvailableComponents[%d] = {' % len(entries)
+        for name,library_name,required_names in entries:
+            if library_name is None:
+                library_name_as_cstr = '0'
+            else:
+                # If we had a project level component, we could derive the
+                # library prefix.
+                library_name_as_cstr = '"libLLVM%s.a"' % library_name
+            print >>f, '  { "%s", %s, { %s } },' % (
+                name, library_name_as_cstr,
+                ', '.join('"%s"' % dep
+                          for dep in required_names))
+        print >>f, '};'
+        f.close()
+
 def main():
     from optparse import OptionParser, OptionGroup
     parser = OptionParser("usage: %prog [options]")
@@ -176,10 +268,15 @@ def main():
     parser.add_option("", "--write-llvmbuild", dest="write_llvmbuild",
                       help="Write out the LLVMBuild.txt files to PATH",
                       action="store", default=None, metavar="PATH")
-    parser.add_option(
-        "", "--llvmbuild-source-root", dest="llvmbuild_source_root",
-        help="If given, an alternate path to search for LLVMBuild.txt files",
-        action="store", default=None, metavar="PATH")
+    parser.add_option("", "--write-library-table",
+                      dest="write_library_table", metavar="PATH",
+                      help="Write the C++ library dependency table to PATH",
+                      action="store", default=None)
+    parser.add_option("", "--llvmbuild-source-root",
+                      dest="llvmbuild_source_root",
+                      help=(
+            "If given, an alternate path to search for LLVMBuild.txt files"),
+                      action="store", default=None, metavar="PATH")
     (opts, args) = parser.parse_args()
 
     # Determine the LLVM source path, if not given.
@@ -211,5 +308,9 @@ def main():
     if opts.write_llvmbuild:
         project_info.write_components(opts.write_llvmbuild)
 
+    # Write out the required librariy, if requested.
+    if opts.write_library_table:
+        project_info.write_library_table(opts.write_library_table)
+
 if __name__=='__main__':
     main()