From df578254a1241a6cab122aa6d5396995d928e24a Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 3 Nov 2011 17:56:06 +0000 Subject: [PATCH] llvm-build: Sketch code to load LLVMBuild.txt files. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@143621 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/llvm-build/llvmbuild/componentinfo.py | 134 ++++++++++++++++++++ utils/llvm-build/llvmbuild/main.py | 47 +++++++ 2 files changed, 181 insertions(+) create mode 100644 utils/llvm-build/llvmbuild/componentinfo.py diff --git a/utils/llvm-build/llvmbuild/componentinfo.py b/utils/llvm-build/llvmbuild/componentinfo.py new file mode 100644 index 00000000000..a434bd884c0 --- /dev/null +++ b/utils/llvm-build/llvmbuild/componentinfo.py @@ -0,0 +1,134 @@ +""" +Descriptor objects for entities that are part of the LLVM project. +""" + +import ConfigParser +import sys + +class ComponentInfo(object): + """ + Base class for component descriptions. + """ + + type_name = None + + def __init__(self, subpath, name, dependencies, parent): + if not subpath.startswith('/'): + raise ValueError,"invalid subpath: %r" % subpath + self.subpath = subpath + self.name = name + self.dependencies = list(dependencies) + + # The name of the parent component to logically group this component + # under. + self.parent = parent + +class GroupComponentInfo(ComponentInfo): + """ + Group components have no semantics as far as the build system are concerned, + but exist to help organize other components into a logical tree structure. + """ + + type_name = 'Group' + + def __init__(self, subpath, name, parent): + ComponentInfo.__init__(self, subpath, name, [], parent) + +class LibraryComponentInfo(ComponentInfo): + type_name = 'Library' + + def __init__(self, subpath, name, dependencies, parent, library_name = None, + required_libraries = [], add_to_library_groups = []): + ComponentInfo.__init__(self, subpath, name, dependencies, parent) + + # If given, the name to use for the library instead of deriving it from + # the component name. + self.library_name = library_name + + # The names of the library components which are required when linking + # with this component. + self.required_libraries = list(required_libraries) + + # The names of the library group components this component should be + # considered part of. + self.add_to_library_groups = list(add_to_library_groups) + +class LibraryGroupComponentInfo(ComponentInfo): + type_name = 'LibraryGroup' + + def __init__(self, subpath, name, parent, required_libraries = [], + add_to_library_groups = []): + ComponentInfo.__init__(self, subpath, name, [], parent) + + # The names of the library components which are required when linking + # with this component. + self.required_libraries = list(required_libraries) + + # The names of the library group components this component should be + # considered part of. + self.add_to_library_groups = list(add_to_library_groups) + +class ToolComponentInfo(ComponentInfo): + type_name = 'Tool' + + def __init__(self, subpath, name, dependencies, parent, + required_libraries = []): + ComponentInfo.__init__(self, subpath, name, dependencies, parent) + + # The names of the library components which are required to link this + # tool. + self.required_libraries = list(required_libraries) + +class BuildToolComponentInfo(ToolComponentInfo): + type_name = 'BuildTool' + +_component_type_map = dict( + (t.type_name, t) + for t in (GroupComponentInfo, + LibraryComponentInfo, LibraryGroupComponentInfo, + ToolComponentInfo, BuildToolComponentInfo)) +def load_from_path(path, subpath): + # Load the LLVMBuild.txt file as an .ini format file. + parser = ConfigParser.RawConfigParser() + parser.read(path) + + # We load each section which starts with 'component' as a distinct component + # description (so multiple components can be described in one file). + for section in parser.sections(): + if not section.startswith('component'): + # We don't expect arbitrary sections currently, warn the user. + print >>sys.stderr, "warning: ignoring unknown section %r in %r" % ( + section, path) + continue + + # Load the component that this section describes. For now we just do + # this the trivial way by letting python validate the argument + # assignment. This is simple, but means users see lame diagnostics. We + # should audit the component manually, eventually. + if not parser.has_option(section, 'type'): + print >>sys.stderr, "error: invalid component %r in %r: %s" % ( + section, path, "no component type") + raise SystemExit, 1 + + type_name = parser.get(section, 'type') + type_class = _component_type_map.get(type_name) + if type_class is None: + print >>sys.stderr, "error: invalid component %r in %r: %s" % ( + section, path, "invalid component type: %r" % type_name) + raise SystemExit, 1 + + items = dict(parser.items(section)) + items['subpath'] = subpath + items.pop('type') + + # Instantiate the component based on the remaining values. + try: + info = type_class(**items) + except TypeError: + print >>sys.stderr, "error: invalid component %r in %r: %s" % ( + section, path, "unable to instantiate: %r" % type_name) + import traceback + traceback.print_exc() + raise SystemExit, 1 + + yield info diff --git a/utils/llvm-build/llvmbuild/main.py b/utils/llvm-build/llvmbuild/main.py index 0d990a78f6a..57233a070e3 100644 --- a/utils/llvm-build/llvmbuild/main.py +++ b/utils/llvm-build/llvmbuild/main.py @@ -1,11 +1,53 @@ +import pprint import os +import componentinfo + +class LLVMProjectInfo(object): + @staticmethod + def load_infos_from_path(llvmbuild_source_root): + # FIXME: Implement a simple subpath file list cache, so we don't restat + # directories we have already traversed. + + # First, discover all the LLVMBuild.txt files. + for dirpath,dirnames,filenames in os.walk(llvmbuild_source_root, + followlinks = True): + # If there is no LLVMBuild.txt file in a directory, we don't recurse + # past it. This is a simple way to prune our search, although it + # makes it easy for users to add LLVMBuild.txt files in places they + # won't be seen. + if 'LLVMBuild.txt' not in filenames: + del dirnames[:] + continue + + # Otherwise, load the LLVMBuild file in this directory. + assert dirpath.startswith(llvmbuild_source_root) + subpath = '/' + dirpath[len(llvmbuild_source_root)+1:] + llvmbuild_path = os.path.join(dirpath, 'LLVMBuild.txt') + for info in componentinfo.load_from_path(llvmbuild_path, subpath): + yield info + + @staticmethod + def load_from_path(source_root, llvmbuild_source_root): + infos = list( + LLVMProjectInfo.load_infos_from_path(llvmbuild_source_root)) + + return LLVMProjectInfo(source_root, infos) + + def __init__(self, source_root, component_infos): + self.source_root = source_root + self.component_infos = component_infos + def main(): from optparse import OptionParser, OptionGroup parser = OptionParser("usage: %prog [options]") parser.add_option("", "--source-root", dest="source_root", metavar="PATH", help="Path to the LLVM source (inferred if not given)", 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. @@ -23,5 +65,10 @@ def main(): 'Function.cpp')): parser.error('unable to infer LLVM source root, please specify') + # Construct the LLVM project information. + llvmbuild_source_root = opts.llvmbuild_source_root or source_root + project_info = LLVMProjectInfo.load_from_path( + source_root, llvmbuild_source_root) + if __name__=='__main__': main()