blob: 30ec23b83301d683d2d1d933f70c1bd32766d583 [file] [log] [blame]
Daniel Dunbardf578252011-11-03 17:56:06 +00001"""
2Descriptor objects for entities that are part of the LLVM project.
3"""
4
5import ConfigParser
6import sys
7
Daniel Dunbar9da6b122011-11-03 17:56:10 +00008from util import *
9
10class ParseError(Exception):
11 pass
12
Daniel Dunbardf578252011-11-03 17:56:06 +000013class ComponentInfo(object):
14 """
15 Base class for component descriptions.
16 """
17
18 type_name = None
19
Daniel Dunbar9da6b122011-11-03 17:56:10 +000020 @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
Daniel Dunbardf578252011-11-03 17:56:06 +000029 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
Daniel Dunbar86c119a2011-11-03 17:56:16 +000040 # The parent instance, once loaded.
41 self.parent_instance = None
42 self.children = []
43
44 def set_parent_instance(self, parent):
45 assert parent.name == self.parent, "Unexpected parent!"
46 self.parent_instance = parent
47 self.parent_instance.children.append(self)
48
Daniel Dunbar1cf14af2011-11-03 17:56:12 +000049 def get_component_references(self):
50 """get_component_references() -> iter
51
52 Return an iterator over the named references to other components from
53 this object. Items are of the form (reference-type, component-name).
54 """
55
56 # Parent references are handled specially.
57 for r in self.dependencies:
58 yield ('dependency', r)
59
Daniel Dunbardf578252011-11-03 17:56:06 +000060class GroupComponentInfo(ComponentInfo):
61 """
62 Group components have no semantics as far as the build system are concerned,
63 but exist to help organize other components into a logical tree structure.
64 """
65
66 type_name = 'Group'
67
Daniel Dunbar9da6b122011-11-03 17:56:10 +000068 @staticmethod
69 def parse(subpath, items):
70 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
71 return GroupComponentInfo(subpath, **kwargs)
72
Daniel Dunbardf578252011-11-03 17:56:06 +000073 def __init__(self, subpath, name, parent):
74 ComponentInfo.__init__(self, subpath, name, [], parent)
75
76class LibraryComponentInfo(ComponentInfo):
77 type_name = 'Library'
78
Daniel Dunbar9da6b122011-11-03 17:56:10 +000079 @staticmethod
80 def parse(subpath, items):
81 kwargs = ComponentInfo.parse_items(items)
82 kwargs['library_name'] = items.get_optional_string('name')
83 kwargs['required_libraries'] = items.get_list('required_libraries')
84 kwargs['add_to_library_groups'] = items.get_list(
85 'add_to_library_groups')
86 return LibraryComponentInfo(subpath, **kwargs)
87
88 def __init__(self, subpath, name, dependencies, parent, library_name,
89 required_libraries, add_to_library_groups):
Daniel Dunbardf578252011-11-03 17:56:06 +000090 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
91
92 # If given, the name to use for the library instead of deriving it from
93 # the component name.
94 self.library_name = library_name
95
96 # The names of the library components which are required when linking
97 # with this component.
98 self.required_libraries = list(required_libraries)
99
100 # The names of the library group components this component should be
101 # considered part of.
102 self.add_to_library_groups = list(add_to_library_groups)
103
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000104 def get_component_references(self):
105 for r in ComponentInfo.get_component_references(self):
106 yield r
107 for r in self.required_libraries:
108 yield ('required library', r)
109 for r in self.add_to_library_groups:
110 yield ('library group', r)
111
Daniel Dunbardf578252011-11-03 17:56:06 +0000112class LibraryGroupComponentInfo(ComponentInfo):
113 type_name = 'LibraryGroup'
114
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000115 @staticmethod
116 def parse(subpath, items):
117 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
118 kwargs['required_libraries'] = items.get_list('required_libraries')
119 kwargs['add_to_library_groups'] = items.get_list(
120 'add_to_library_groups')
121 return LibraryGroupComponentInfo(subpath, **kwargs)
122
Daniel Dunbardf578252011-11-03 17:56:06 +0000123 def __init__(self, subpath, name, parent, required_libraries = [],
124 add_to_library_groups = []):
125 ComponentInfo.__init__(self, subpath, name, [], parent)
126
127 # The names of the library components which are required when linking
128 # with this component.
129 self.required_libraries = list(required_libraries)
130
131 # The names of the library group components this component should be
132 # considered part of.
133 self.add_to_library_groups = list(add_to_library_groups)
134
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000135 def get_component_references(self):
136 for r in ComponentInfo.get_component_references(self):
137 yield r
138 for r in self.required_libraries:
139 yield ('required library', r)
140 for r in self.add_to_library_groups:
141 yield ('library group', r)
142
Daniel Dunbardf578252011-11-03 17:56:06 +0000143class ToolComponentInfo(ComponentInfo):
144 type_name = 'Tool'
145
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000146 @staticmethod
147 def parse(subpath, items):
148 kwargs = ComponentInfo.parse_items(items)
149 kwargs['required_libraries'] = items.get_list('required_libraries')
150 return ToolComponentInfo(subpath, **kwargs)
151
Daniel Dunbardf578252011-11-03 17:56:06 +0000152 def __init__(self, subpath, name, dependencies, parent,
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000153 required_libraries):
Daniel Dunbardf578252011-11-03 17:56:06 +0000154 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
155
156 # The names of the library components which are required to link this
157 # tool.
158 self.required_libraries = list(required_libraries)
159
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000160 def get_component_references(self):
161 for r in ComponentInfo.get_component_references(self):
162 yield r
163 for r in self.required_libraries:
164 yield ('required library', r)
165
Daniel Dunbardf578252011-11-03 17:56:06 +0000166class BuildToolComponentInfo(ToolComponentInfo):
167 type_name = 'BuildTool'
168
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000169 @staticmethod
170 def parse(subpath, items):
171 kwargs = ComponentInfo.parse_items(items)
172 kwargs['required_libraries'] = items.get_list('required_libraries')
173 return BuildToolComponentInfo(subpath, **kwargs)
174
175###
176
177class IniFormatParser(dict):
178 def get_list(self, key):
179 # Check if the value is defined.
180 value = self.get(key)
181 if value is None:
182 return []
183
184 # Lists are just whitespace separated strings.
185 return value.split()
186
187 def get_optional_string(self, key):
188 value = self.get_list(key)
189 if not value:
190 return None
191 if len(value) > 1:
192 raise ParseError("multiple values for scalar key: %r" % key)
193 return value[0]
194
195 def get_string(self, key):
196 value = self.get_optional_string(key)
197 if not value:
198 raise ParseError("missing value for required string: %r" % key)
199 return value
200
Daniel Dunbardf578252011-11-03 17:56:06 +0000201_component_type_map = dict(
202 (t.type_name, t)
203 for t in (GroupComponentInfo,
204 LibraryComponentInfo, LibraryGroupComponentInfo,
205 ToolComponentInfo, BuildToolComponentInfo))
206def load_from_path(path, subpath):
207 # Load the LLVMBuild.txt file as an .ini format file.
208 parser = ConfigParser.RawConfigParser()
209 parser.read(path)
210
211 # We load each section which starts with 'component' as a distinct component
212 # description (so multiple components can be described in one file).
213 for section in parser.sections():
214 if not section.startswith('component'):
215 # We don't expect arbitrary sections currently, warn the user.
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000216 warning("ignoring unknown section %r in %r" % (section, path))
Daniel Dunbardf578252011-11-03 17:56:06 +0000217 continue
218
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000219 # Determine the type of the component to instantiate.
Daniel Dunbardf578252011-11-03 17:56:06 +0000220 if not parser.has_option(section, 'type'):
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000221 fatal("invalid component %r in %r: %s" % (
222 section, path, "no component type"))
Daniel Dunbardf578252011-11-03 17:56:06 +0000223
224 type_name = parser.get(section, 'type')
225 type_class = _component_type_map.get(type_name)
226 if type_class is None:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000227 fatal("invalid component %r in %r: %s" % (
228 section, path, "invalid component type: %r" % type_name))
Daniel Dunbardf578252011-11-03 17:56:06 +0000229
230 # Instantiate the component based on the remaining values.
231 try:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000232 info = type_class.parse(subpath,
233 IniFormatParser(parser.items(section)))
Daniel Dunbardf578252011-11-03 17:56:06 +0000234 except TypeError:
235 print >>sys.stderr, "error: invalid component %r in %r: %s" % (
236 section, path, "unable to instantiate: %r" % type_name)
237 import traceback
238 traceback.print_exc()
239 raise SystemExit, 1
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000240 except ParseError,e:
241 fatal("unable to load component %r in %r: %s" % (
242 section, path, e.message))
Daniel Dunbardf578252011-11-03 17:56:06 +0000243
244 yield info