e15dbda756f9e3796cb9f497534b2bc2919026b2
[oota-llvm.git] / utils / llvm-build / llvmbuild / componentinfo.py
1 """
2 Descriptor objects for entities that are part of the LLVM project.
3 """
4
5 import ConfigParser
6 import sys
7
8 from util import *
9
10 class ParseError(Exception):
11     pass
12
13 class ComponentInfo(object):
14     """
15     Base class for component descriptions.
16     """
17
18     type_name = None
19
20     @staticmethod
21     def parse_items(items, has_dependencies = True):
22         kwargs = {}
23         kwargs['name'] = items.get_string('name')
24         kwargs['parent'] = items.get_optional_string('parent')
25         if has_dependencies:
26             kwargs['dependencies'] = items.get_list('dependencies')
27         return kwargs
28
29     def __init__(self, subpath, name, dependencies, parent):
30         if not subpath.startswith('/'):
31             raise ValueError,"invalid subpath: %r" % subpath
32         self.subpath = subpath
33         self.name = name
34         self.dependencies = list(dependencies)
35
36         # The name of the parent component to logically group this component
37         # under.
38         self.parent = parent
39
40 class GroupComponentInfo(ComponentInfo):
41     """
42     Group components have no semantics as far as the build system are concerned,
43     but exist to help organize other components into a logical tree structure.
44     """
45
46     type_name = 'Group'
47
48     @staticmethod
49     def parse(subpath, items):
50         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
51         return GroupComponentInfo(subpath, **kwargs)
52
53     def __init__(self, subpath, name, parent):
54         ComponentInfo.__init__(self, subpath, name, [], parent)
55
56 class LibraryComponentInfo(ComponentInfo):
57     type_name = 'Library'
58
59     @staticmethod
60     def parse(subpath, items):
61         kwargs = ComponentInfo.parse_items(items)
62         kwargs['library_name'] = items.get_optional_string('name')
63         kwargs['required_libraries'] = items.get_list('required_libraries')
64         kwargs['add_to_library_groups'] = items.get_list(
65             'add_to_library_groups')
66         return LibraryComponentInfo(subpath, **kwargs)
67
68     def __init__(self, subpath, name, dependencies, parent, library_name,
69                  required_libraries, add_to_library_groups):
70         ComponentInfo.__init__(self, subpath, name, dependencies, parent)
71
72         # If given, the name to use for the library instead of deriving it from
73         # the component name.
74         self.library_name = library_name
75
76         # The names of the library components which are required when linking
77         # with this component.
78         self.required_libraries = list(required_libraries)
79
80         # The names of the library group components this component should be
81         # considered part of.
82         self.add_to_library_groups = list(add_to_library_groups)
83
84 class LibraryGroupComponentInfo(ComponentInfo):
85     type_name = 'LibraryGroup'
86
87     @staticmethod
88     def parse(subpath, items):
89         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
90         kwargs['required_libraries'] = items.get_list('required_libraries')
91         kwargs['add_to_library_groups'] = items.get_list(
92             'add_to_library_groups')
93         return LibraryGroupComponentInfo(subpath, **kwargs)
94
95     def __init__(self, subpath, name, parent, required_libraries = [],
96                  add_to_library_groups = []):
97         ComponentInfo.__init__(self, subpath, name, [], parent)
98
99         # The names of the library components which are required when linking
100         # with this component.
101         self.required_libraries = list(required_libraries)
102
103         # The names of the library group components this component should be
104         # considered part of.
105         self.add_to_library_groups = list(add_to_library_groups)
106
107 class ToolComponentInfo(ComponentInfo):
108     type_name = 'Tool'
109
110     @staticmethod
111     def parse(subpath, items):
112         kwargs = ComponentInfo.parse_items(items)
113         kwargs['required_libraries'] = items.get_list('required_libraries')
114         return ToolComponentInfo(subpath, **kwargs)
115
116     def __init__(self, subpath, name, dependencies, parent,
117                  required_libraries):
118         ComponentInfo.__init__(self, subpath, name, dependencies, parent)
119
120         # The names of the library components which are required to link this
121         # tool.
122         self.required_libraries = list(required_libraries)
123
124 class BuildToolComponentInfo(ToolComponentInfo):
125     type_name = 'BuildTool'
126
127     @staticmethod
128     def parse(subpath, items):
129         kwargs = ComponentInfo.parse_items(items)
130         kwargs['required_libraries'] = items.get_list('required_libraries')
131         return BuildToolComponentInfo(subpath, **kwargs)
132
133 ###
134
135 class IniFormatParser(dict):
136     def get_list(self, key):
137         # Check if the value is defined.
138         value = self.get(key)
139         if value is None:
140             return []
141
142         # Lists are just whitespace separated strings.
143         return value.split()
144
145     def get_optional_string(self, key):
146         value = self.get_list(key)
147         if not value:
148             return None
149         if len(value) > 1:
150             raise ParseError("multiple values for scalar key: %r" % key)
151         return value[0]
152
153     def get_string(self, key):
154         value = self.get_optional_string(key)
155         if not value:
156             raise ParseError("missing value for required string: %r" % key)
157         return value
158
159 _component_type_map = dict(
160     (t.type_name, t)
161     for t in (GroupComponentInfo,
162               LibraryComponentInfo, LibraryGroupComponentInfo,
163               ToolComponentInfo, BuildToolComponentInfo))
164 def load_from_path(path, subpath):
165     # Load the LLVMBuild.txt file as an .ini format file.
166     parser = ConfigParser.RawConfigParser()
167     parser.read(path)
168
169     # We load each section which starts with 'component' as a distinct component
170     # description (so multiple components can be described in one file).
171     for section in parser.sections():
172         if not section.startswith('component'):
173             # We don't expect arbitrary sections currently, warn the user.
174             warning("ignoring unknown section %r in %r" % (section, path))
175             continue
176
177         # Determine the type of the component to instantiate.
178         if not parser.has_option(section, 'type'):
179             fatal("invalid component %r in %r: %s" % (
180                     section, path, "no component type"))
181
182         type_name = parser.get(section, 'type')
183         type_class = _component_type_map.get(type_name)
184         if type_class is None:
185             fatal("invalid component %r in %r: %s" % (
186                     section, path, "invalid component type: %r" % type_name))
187
188         # Instantiate the component based on the remaining values.
189         try:
190             info = type_class.parse(subpath,
191                                     IniFormatParser(parser.items(section)))
192         except TypeError:
193             print >>sys.stderr, "error: invalid component %r in %r: %s" % (
194                 section, path, "unable to instantiate: %r" % type_name)
195             import traceback
196             traceback.print_exc()
197             raise SystemExit, 1
198         except ParseError,e:
199             fatal("unable to load component %r in %r: %s" % (
200                     section, path, e.message))
201
202         yield info