blob: 079102f676ae53f07e1344ba2ba811a656178500 [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
Daniel Dunbar43120df2011-11-03 17:56:21 +00006import StringIO
Daniel Dunbardf578252011-11-03 17:56:06 +00007import sys
8
Daniel Dunbar9da6b122011-11-03 17:56:10 +00009from util import *
10
11class ParseError(Exception):
12 pass
13
Daniel Dunbardf578252011-11-03 17:56:06 +000014class ComponentInfo(object):
15 """
16 Base class for component descriptions.
17 """
18
19 type_name = None
20
Daniel Dunbar9da6b122011-11-03 17:56:10 +000021 @staticmethod
22 def parse_items(items, has_dependencies = True):
23 kwargs = {}
24 kwargs['name'] = items.get_string('name')
25 kwargs['parent'] = items.get_optional_string('parent')
26 if has_dependencies:
27 kwargs['dependencies'] = items.get_list('dependencies')
28 return kwargs
29
Daniel Dunbardf578252011-11-03 17:56:06 +000030 def __init__(self, subpath, name, dependencies, parent):
31 if not subpath.startswith('/'):
32 raise ValueError,"invalid subpath: %r" % subpath
33 self.subpath = subpath
34 self.name = name
35 self.dependencies = list(dependencies)
36
37 # The name of the parent component to logically group this component
38 # under.
39 self.parent = parent
40
Daniel Dunbar86c119a2011-11-03 17:56:16 +000041 # The parent instance, once loaded.
42 self.parent_instance = None
43 self.children = []
44
45 def set_parent_instance(self, parent):
46 assert parent.name == self.parent, "Unexpected parent!"
47 self.parent_instance = parent
48 self.parent_instance.children.append(self)
49
Daniel Dunbar1cf14af2011-11-03 17:56:12 +000050 def get_component_references(self):
51 """get_component_references() -> iter
52
53 Return an iterator over the named references to other components from
54 this object. Items are of the form (reference-type, component-name).
55 """
56
57 # Parent references are handled specially.
58 for r in self.dependencies:
59 yield ('dependency', r)
60
Daniel Dunbar43120df2011-11-03 17:56:21 +000061 def get_llvmbuild_fragment(self):
62 abstract
63
Daniel Dunbardf578252011-11-03 17:56:06 +000064class GroupComponentInfo(ComponentInfo):
65 """
66 Group components have no semantics as far as the build system are concerned,
67 but exist to help organize other components into a logical tree structure.
68 """
69
70 type_name = 'Group'
71
Daniel Dunbar9da6b122011-11-03 17:56:10 +000072 @staticmethod
73 def parse(subpath, items):
74 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
75 return GroupComponentInfo(subpath, **kwargs)
76
Daniel Dunbardf578252011-11-03 17:56:06 +000077 def __init__(self, subpath, name, parent):
78 ComponentInfo.__init__(self, subpath, name, [], parent)
79
Daniel Dunbar43120df2011-11-03 17:56:21 +000080 def get_llvmbuild_fragment(self):
81 result = StringIO.StringIO()
82 print >>result, 'type = %s' % self.type_name
83 print >>result, 'name = %s' % self.name
84 print >>result, 'parent = %s' % self.parent
85 return result.getvalue()
86
Daniel Dunbardf578252011-11-03 17:56:06 +000087class LibraryComponentInfo(ComponentInfo):
88 type_name = 'Library'
89
Daniel Dunbar9da6b122011-11-03 17:56:10 +000090 @staticmethod
91 def parse(subpath, items):
92 kwargs = ComponentInfo.parse_items(items)
Daniel Dunbar43120df2011-11-03 17:56:21 +000093 kwargs['library_name'] = items.get_optional_string('library_name')
Daniel Dunbar9da6b122011-11-03 17:56:10 +000094 kwargs['required_libraries'] = items.get_list('required_libraries')
95 kwargs['add_to_library_groups'] = items.get_list(
96 'add_to_library_groups')
97 return LibraryComponentInfo(subpath, **kwargs)
98
99 def __init__(self, subpath, name, dependencies, parent, library_name,
100 required_libraries, add_to_library_groups):
Daniel Dunbardf578252011-11-03 17:56:06 +0000101 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
102
103 # If given, the name to use for the library instead of deriving it from
104 # the component name.
105 self.library_name = library_name
106
107 # The names of the library components which are required when linking
108 # with this component.
109 self.required_libraries = list(required_libraries)
110
111 # The names of the library group components this component should be
112 # considered part of.
113 self.add_to_library_groups = list(add_to_library_groups)
114
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000115 def get_component_references(self):
116 for r in ComponentInfo.get_component_references(self):
117 yield r
118 for r in self.required_libraries:
119 yield ('required library', r)
120 for r in self.add_to_library_groups:
121 yield ('library group', r)
122
Daniel Dunbar43120df2011-11-03 17:56:21 +0000123 def get_llvmbuild_fragment(self):
124 result = StringIO.StringIO()
125 print >>result, 'type = %s' % self.type_name
126 print >>result, 'name = %s' % self.name
127 print >>result, 'parent = %s' % self.parent
128 if self.library_name is not None:
129 print >>result, 'library_name = %s' % self.library_name
130 if self.required_libraries:
131 print >>result, 'required_libraries = %s' % ' '.join(
132 self.required_libraries)
133 if self.add_to_library_groups:
134 print >>result, 'add_to_library_groups = %s' % ' '.join(
135 self.add_to_library_groups)
136 return result.getvalue()
137
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000138 def get_library_name(self):
139 return self.library_name or self.name
140
Daniel Dunbar5086de62011-11-29 00:06:50 +0000141 def get_prefixed_library_name(self):
142 """
143 get_prefixed_library_name() -> str
144
145 Return the library name prefixed by the project name. This is generally
146 what the library name will be on disk.
147 """
148
149 basename = self.get_library_name()
150
151 # FIXME: We need to get the prefix information from an explicit project
152 # object, or something.
153 if basename in ('gtest', 'gtest_main'):
154 return basename
155
156 return 'LLVM%s' % basename
157
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000158 def get_llvmconfig_component_name(self):
159 return self.get_library_name().lower()
160
Daniel Dunbardf578252011-11-03 17:56:06 +0000161class LibraryGroupComponentInfo(ComponentInfo):
162 type_name = 'LibraryGroup'
163
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000164 @staticmethod
165 def parse(subpath, items):
166 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
167 kwargs['required_libraries'] = items.get_list('required_libraries')
168 kwargs['add_to_library_groups'] = items.get_list(
169 'add_to_library_groups')
170 return LibraryGroupComponentInfo(subpath, **kwargs)
171
Daniel Dunbardf578252011-11-03 17:56:06 +0000172 def __init__(self, subpath, name, parent, required_libraries = [],
173 add_to_library_groups = []):
174 ComponentInfo.__init__(self, subpath, name, [], parent)
175
176 # The names of the library components which are required when linking
177 # with this component.
178 self.required_libraries = list(required_libraries)
179
180 # The names of the library group components this component should be
181 # considered part of.
182 self.add_to_library_groups = list(add_to_library_groups)
183
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000184 def get_component_references(self):
185 for r in ComponentInfo.get_component_references(self):
186 yield r
187 for r in self.required_libraries:
188 yield ('required library', r)
189 for r in self.add_to_library_groups:
190 yield ('library group', r)
191
Daniel Dunbar43120df2011-11-03 17:56:21 +0000192 def get_llvmbuild_fragment(self):
193 result = StringIO.StringIO()
194 print >>result, 'type = %s' % self.type_name
195 print >>result, 'name = %s' % self.name
196 print >>result, 'parent = %s' % self.parent
197 if self.required_libraries:
198 print >>result, 'required_libraries = %s' % ' '.join(
199 self.required_libraries)
200 if self.add_to_library_groups:
201 print >>result, 'add_to_library_groups = %s' % ' '.join(
202 self.add_to_library_groups)
203 return result.getvalue()
204
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000205 def get_llvmconfig_component_name(self):
206 return self.name.lower()
207
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000208class TargetGroupComponentInfo(ComponentInfo):
209 type_name = 'TargetGroup'
210
211 @staticmethod
212 def parse(subpath, items):
213 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
214 kwargs['required_libraries'] = items.get_list('required_libraries')
215 kwargs['add_to_library_groups'] = items.get_list(
216 'add_to_library_groups')
217 kwargs['has_jit'] = items.get_optional_bool('has_jit', False)
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000218 kwargs['has_asmprinter'] = items.get_optional_bool('has_asmprinter',
219 False)
220 kwargs['has_asmparser'] = items.get_optional_bool('has_asmparser',
221 False)
222 kwargs['has_disassembler'] = items.get_optional_bool('has_disassembler',
223 False)
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000224 return TargetGroupComponentInfo(subpath, **kwargs)
225
226 def __init__(self, subpath, name, parent, required_libraries = [],
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000227 add_to_library_groups = [], has_jit = False,
228 has_asmprinter = False, has_asmparser = False,
229 has_disassembler = False):
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000230 ComponentInfo.__init__(self, subpath, name, [], parent)
231
232 # The names of the library components which are required when linking
233 # with this component.
234 self.required_libraries = list(required_libraries)
235
236 # The names of the library group components this component should be
237 # considered part of.
238 self.add_to_library_groups = list(add_to_library_groups)
239
240 # Whether or not this target supports the JIT.
241 self.has_jit = bool(has_jit)
242
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000243 # Whether or not this target defines an assembly printer.
244 self.has_asmprinter = bool(has_asmprinter)
245
246 # Whether or not this target defines an assembly parser.
247 self.has_asmparser = bool(has_asmparser)
248
249 # Whether or not this target defines an disassembler.
250 self.has_disassembler = bool(has_disassembler)
251
Daniel Dunbaraffc6cf2011-11-10 00:50:07 +0000252 # Whether or not this target is enabled. This is set in response to
253 # configuration parameters.
254 self.enabled = False
255
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000256 def get_component_references(self):
257 for r in ComponentInfo.get_component_references(self):
258 yield r
259 for r in self.required_libraries:
260 yield ('required library', r)
261 for r in self.add_to_library_groups:
262 yield ('library group', r)
263
264 def get_llvmbuild_fragment(self):
265 result = StringIO.StringIO()
266 print >>result, 'type = %s' % self.type_name
267 print >>result, 'name = %s' % self.name
268 print >>result, 'parent = %s' % self.parent
269 if self.required_libraries:
270 print >>result, 'required_libraries = %s' % ' '.join(
271 self.required_libraries)
272 if self.add_to_library_groups:
273 print >>result, 'add_to_library_groups = %s' % ' '.join(
274 self.add_to_library_groups)
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000275 for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
276 'has_jit'):
277 if getattr(self, bool_key):
278 print >>result, '%s = 1' % (bool_key,)
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000279 return result.getvalue()
280
281 def get_llvmconfig_component_name(self):
282 return self.name.lower()
283
Daniel Dunbardf578252011-11-03 17:56:06 +0000284class ToolComponentInfo(ComponentInfo):
285 type_name = 'Tool'
286
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000287 @staticmethod
288 def parse(subpath, items):
289 kwargs = ComponentInfo.parse_items(items)
290 kwargs['required_libraries'] = items.get_list('required_libraries')
291 return ToolComponentInfo(subpath, **kwargs)
292
Daniel Dunbardf578252011-11-03 17:56:06 +0000293 def __init__(self, subpath, name, dependencies, parent,
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000294 required_libraries):
Daniel Dunbardf578252011-11-03 17:56:06 +0000295 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
296
297 # The names of the library components which are required to link this
298 # tool.
299 self.required_libraries = list(required_libraries)
300
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000301 def get_component_references(self):
302 for r in ComponentInfo.get_component_references(self):
303 yield r
304 for r in self.required_libraries:
305 yield ('required library', r)
306
Daniel Dunbar43120df2011-11-03 17:56:21 +0000307 def get_llvmbuild_fragment(self):
308 result = StringIO.StringIO()
309 print >>result, 'type = %s' % self.type_name
310 print >>result, 'name = %s' % self.name
311 print >>result, 'parent = %s' % self.parent
312 print >>result, 'required_libraries = %s' % ' '.join(
313 self.required_libraries)
314 return result.getvalue()
315
Daniel Dunbardf578252011-11-03 17:56:06 +0000316class BuildToolComponentInfo(ToolComponentInfo):
317 type_name = 'BuildTool'
318
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000319 @staticmethod
320 def parse(subpath, items):
321 kwargs = ComponentInfo.parse_items(items)
322 kwargs['required_libraries'] = items.get_list('required_libraries')
323 return BuildToolComponentInfo(subpath, **kwargs)
324
325###
326
327class IniFormatParser(dict):
328 def get_list(self, key):
329 # Check if the value is defined.
330 value = self.get(key)
331 if value is None:
332 return []
333
334 # Lists are just whitespace separated strings.
335 return value.split()
336
337 def get_optional_string(self, key):
338 value = self.get_list(key)
339 if not value:
340 return None
341 if len(value) > 1:
342 raise ParseError("multiple values for scalar key: %r" % key)
343 return value[0]
344
345 def get_string(self, key):
346 value = self.get_optional_string(key)
347 if not value:
348 raise ParseError("missing value for required string: %r" % key)
349 return value
350
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000351 def get_optional_bool(self, key, default = None):
352 value = self.get_optional_string(key)
353 if not value:
354 return default
355 if value not in ('0', '1'):
356 raise ParseError("invalid value(%r) for boolean property: %r" % (
357 value, key))
358 return bool(int(value))
359
360 def get_bool(self, key):
361 value = self.get_optional_bool(key)
362 if value is None:
363 raise ParseError("missing value for required boolean: %r" % key)
364 return value
365
Daniel Dunbardf578252011-11-03 17:56:06 +0000366_component_type_map = dict(
367 (t.type_name, t)
368 for t in (GroupComponentInfo,
369 LibraryComponentInfo, LibraryGroupComponentInfo,
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000370 ToolComponentInfo, BuildToolComponentInfo,
371 TargetGroupComponentInfo))
Daniel Dunbardf578252011-11-03 17:56:06 +0000372def load_from_path(path, subpath):
373 # Load the LLVMBuild.txt file as an .ini format file.
374 parser = ConfigParser.RawConfigParser()
375 parser.read(path)
376
377 # We load each section which starts with 'component' as a distinct component
378 # description (so multiple components can be described in one file).
379 for section in parser.sections():
380 if not section.startswith('component'):
381 # We don't expect arbitrary sections currently, warn the user.
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000382 warning("ignoring unknown section %r in %r" % (section, path))
Daniel Dunbardf578252011-11-03 17:56:06 +0000383 continue
384
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000385 # Determine the type of the component to instantiate.
Daniel Dunbardf578252011-11-03 17:56:06 +0000386 if not parser.has_option(section, 'type'):
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000387 fatal("invalid component %r in %r: %s" % (
388 section, path, "no component type"))
Daniel Dunbardf578252011-11-03 17:56:06 +0000389
390 type_name = parser.get(section, 'type')
391 type_class = _component_type_map.get(type_name)
392 if type_class is None:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000393 fatal("invalid component %r in %r: %s" % (
394 section, path, "invalid component type: %r" % type_name))
Daniel Dunbardf578252011-11-03 17:56:06 +0000395
396 # Instantiate the component based on the remaining values.
397 try:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000398 info = type_class.parse(subpath,
399 IniFormatParser(parser.items(section)))
Daniel Dunbardf578252011-11-03 17:56:06 +0000400 except TypeError:
401 print >>sys.stderr, "error: invalid component %r in %r: %s" % (
402 section, path, "unable to instantiate: %r" % type_name)
403 import traceback
404 traceback.print_exc()
405 raise SystemExit, 1
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000406 except ParseError,e:
407 fatal("unable to load component %r in %r: %s" % (
408 section, path, e.message))
Daniel Dunbardf578252011-11-03 17:56:06 +0000409
410 yield info