blob: e15dbda756f9e3796cb9f497534b2bc2919026b2 [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
40class 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
Daniel Dunbar9da6b122011-11-03 17:56:10 +000048 @staticmethod
49 def parse(subpath, items):
50 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
51 return GroupComponentInfo(subpath, **kwargs)
52
Daniel Dunbardf578252011-11-03 17:56:06 +000053 def __init__(self, subpath, name, parent):
54 ComponentInfo.__init__(self, subpath, name, [], parent)
55
56class LibraryComponentInfo(ComponentInfo):
57 type_name = 'Library'
58
Daniel Dunbar9da6b122011-11-03 17:56:10 +000059 @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):
Daniel Dunbardf578252011-11-03 17:56:06 +000070 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
84class LibraryGroupComponentInfo(ComponentInfo):
85 type_name = 'LibraryGroup'
86
Daniel Dunbar9da6b122011-11-03 17:56:10 +000087 @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
Daniel Dunbardf578252011-11-03 17:56:06 +000095 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
107class ToolComponentInfo(ComponentInfo):
108 type_name = 'Tool'
109
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000110 @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
Daniel Dunbardf578252011-11-03 17:56:06 +0000116 def __init__(self, subpath, name, dependencies, parent,
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000117 required_libraries):
Daniel Dunbardf578252011-11-03 17:56:06 +0000118 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
124class BuildToolComponentInfo(ToolComponentInfo):
125 type_name = 'BuildTool'
126
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000127 @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
135class 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
Daniel Dunbardf578252011-11-03 17:56:06 +0000159_component_type_map = dict(
160 (t.type_name, t)
161 for t in (GroupComponentInfo,
162 LibraryComponentInfo, LibraryGroupComponentInfo,
163 ToolComponentInfo, BuildToolComponentInfo))
164def 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.
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000174 warning("ignoring unknown section %r in %r" % (section, path))
Daniel Dunbardf578252011-11-03 17:56:06 +0000175 continue
176
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000177 # Determine the type of the component to instantiate.
Daniel Dunbardf578252011-11-03 17:56:06 +0000178 if not parser.has_option(section, 'type'):
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000179 fatal("invalid component %r in %r: %s" % (
180 section, path, "no component type"))
Daniel Dunbardf578252011-11-03 17:56:06 +0000181
182 type_name = parser.get(section, 'type')
183 type_class = _component_type_map.get(type_name)
184 if type_class is None:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000185 fatal("invalid component %r in %r: %s" % (
186 section, path, "invalid component type: %r" % type_name))
Daniel Dunbardf578252011-11-03 17:56:06 +0000187
188 # Instantiate the component based on the remaining values.
189 try:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000190 info = type_class.parse(subpath,
191 IniFormatParser(parser.items(section)))
Daniel Dunbardf578252011-11-03 17:56:06 +0000192 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
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000198 except ParseError,e:
199 fatal("unable to load component %r in %r: %s" % (
200 section, path, e.message))
Daniel Dunbardf578252011-11-03 17:56:06 +0000201
202 yield info