componentinfo.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. """
  2. Descriptor objects for entities that are part of the LLVM project.
  3. """
  4. from __future__ import absolute_import
  5. try:
  6. import configparser
  7. except:
  8. import ConfigParser as configparser
  9. import sys
  10. from llvmbuild.util import fatal, warning
  11. class ParseError(Exception):
  12. pass
  13. class ComponentInfo(object):
  14. """
  15. Base class for component descriptions.
  16. """
  17. type_name = None
  18. @staticmethod
  19. def parse_items(items, has_dependencies = True):
  20. kwargs = {}
  21. kwargs['name'] = items.get_string('name')
  22. kwargs['parent'] = items.get_optional_string('parent')
  23. if has_dependencies:
  24. kwargs['dependencies'] = items.get_list('dependencies')
  25. return kwargs
  26. def __init__(self, subpath, name, dependencies, parent):
  27. if not subpath.startswith('/'):
  28. raise ValueError("invalid subpath: %r" % subpath)
  29. self.subpath = subpath
  30. self.name = name
  31. self.dependencies = list(dependencies)
  32. # The name of the parent component to logically group this component
  33. # under.
  34. self.parent = parent
  35. # The parent instance, once loaded.
  36. self.parent_instance = None
  37. self.children = []
  38. # The original source path.
  39. self._source_path = None
  40. # A flag to mark "special" components which have some amount of magic
  41. # handling (generally based on command line options).
  42. self._is_special_group = False
  43. def set_parent_instance(self, parent):
  44. assert parent.name == self.parent, "Unexpected parent!"
  45. self.parent_instance = parent
  46. self.parent_instance.children.append(self)
  47. def get_component_references(self):
  48. """get_component_references() -> iter
  49. Return an iterator over the named references to other components from
  50. this object. Items are of the form (reference-type, component-name).
  51. """
  52. # Parent references are handled specially.
  53. for r in self.dependencies:
  54. yield ('dependency', r)
  55. def get_llvmbuild_fragment(self):
  56. abstract
  57. def get_parent_target_group(self):
  58. """get_parent_target_group() -> ComponentInfo or None
  59. Return the nearest parent target group (if any), or None if the
  60. component is not part of any target group.
  61. """
  62. # If this is a target group, return it.
  63. if self.type_name == 'TargetGroup':
  64. return self
  65. # Otherwise recurse on the parent, if any.
  66. if self.parent_instance:
  67. return self.parent_instance.get_parent_target_group()
  68. class GroupComponentInfo(ComponentInfo):
  69. """
  70. Group components have no semantics as far as the build system are concerned,
  71. but exist to help organize other components into a logical tree structure.
  72. """
  73. type_name = 'Group'
  74. @staticmethod
  75. def parse(subpath, items):
  76. kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
  77. return GroupComponentInfo(subpath, **kwargs)
  78. def __init__(self, subpath, name, parent):
  79. ComponentInfo.__init__(self, subpath, name, [], parent)
  80. def get_llvmbuild_fragment(self):
  81. return """\
  82. type = %s
  83. name = %s
  84. parent = %s
  85. """ % (self.type_name, self.name, self.parent)
  86. class LibraryComponentInfo(ComponentInfo):
  87. type_name = 'Library'
  88. @staticmethod
  89. def parse_items(items):
  90. kwargs = ComponentInfo.parse_items(items)
  91. kwargs['library_name'] = items.get_optional_string('library_name')
  92. kwargs['required_libraries'] = items.get_list('required_libraries')
  93. kwargs['add_to_library_groups'] = items.get_list(
  94. 'add_to_library_groups')
  95. kwargs['installed'] = items.get_optional_bool('installed', True)
  96. return kwargs
  97. @staticmethod
  98. def parse(subpath, items):
  99. kwargs = LibraryComponentInfo.parse_items(items)
  100. return LibraryComponentInfo(subpath, **kwargs)
  101. def __init__(self, subpath, name, dependencies, parent, library_name,
  102. required_libraries, add_to_library_groups, installed):
  103. ComponentInfo.__init__(self, subpath, name, dependencies, parent)
  104. # If given, the name to use for the library instead of deriving it from
  105. # the component name.
  106. self.library_name = library_name
  107. # The names of the library components which are required when linking
  108. # with this component.
  109. self.required_libraries = list(required_libraries)
  110. # The names of the library group components this component should be
  111. # considered part of.
  112. self.add_to_library_groups = list(add_to_library_groups)
  113. # Whether or not this library is installed.
  114. self.installed = installed
  115. 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. def get_llvmbuild_fragment(self):
  123. result = """\
  124. type = %s
  125. name = %s
  126. parent = %s
  127. """ % (self.type_name, self.name, self.parent)
  128. if self.library_name is not None:
  129. result += 'library_name = %s\n' % self.library_name
  130. if self.required_libraries:
  131. result += 'required_libraries = %s\n' % ' '.join(
  132. self.required_libraries)
  133. if self.add_to_library_groups:
  134. result += 'add_to_library_groups = %s\n' % ' '.join(
  135. self.add_to_library_groups)
  136. if not self.installed:
  137. result += 'installed = 0\n'
  138. return result
  139. def get_library_name(self):
  140. return self.library_name or self.name
  141. def get_prefixed_library_name(self):
  142. """
  143. get_prefixed_library_name() -> str
  144. Return the library name prefixed by the project name. This is generally
  145. what the library name will be on disk.
  146. """
  147. basename = self.get_library_name()
  148. # FIXME: We need to get the prefix information from an explicit project
  149. # object, or something.
  150. if basename in ('gtest', 'gtest_main'):
  151. return basename
  152. return 'LLVM%s' % basename
  153. def get_llvmconfig_component_name(self):
  154. return self.get_library_name().lower()
  155. class OptionalLibraryComponentInfo(LibraryComponentInfo):
  156. type_name = "OptionalLibrary"
  157. @staticmethod
  158. def parse(subpath, items):
  159. kwargs = LibraryComponentInfo.parse_items(items)
  160. return OptionalLibraryComponentInfo(subpath, **kwargs)
  161. def __init__(self, subpath, name, dependencies, parent, library_name,
  162. required_libraries, add_to_library_groups, installed):
  163. LibraryComponentInfo.__init__(self, subpath, name, dependencies, parent,
  164. library_name, required_libraries,
  165. add_to_library_groups, installed)
  166. class LibraryGroupComponentInfo(ComponentInfo):
  167. type_name = 'LibraryGroup'
  168. @staticmethod
  169. def parse(subpath, items):
  170. kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
  171. kwargs['required_libraries'] = items.get_list('required_libraries')
  172. kwargs['add_to_library_groups'] = items.get_list(
  173. 'add_to_library_groups')
  174. return LibraryGroupComponentInfo(subpath, **kwargs)
  175. def __init__(self, subpath, name, parent, required_libraries = [],
  176. add_to_library_groups = []):
  177. ComponentInfo.__init__(self, subpath, name, [], parent)
  178. # The names of the library components which are required when linking
  179. # with this component.
  180. self.required_libraries = list(required_libraries)
  181. # The names of the library group components this component should be
  182. # considered part of.
  183. self.add_to_library_groups = list(add_to_library_groups)
  184. 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. def get_llvmbuild_fragment(self):
  192. result = """\
  193. type = %s
  194. name = %s
  195. parent = %s
  196. """ % (self.type_name, self.name, self.parent)
  197. if self.required_libraries and not self._is_special_group:
  198. result += 'required_libraries = %s\n' % ' '.join(
  199. self.required_libraries)
  200. if self.add_to_library_groups:
  201. result += 'add_to_library_groups = %s\n' % ' '.join(
  202. self.add_to_library_groups)
  203. return result
  204. def get_llvmconfig_component_name(self):
  205. return self.name.lower()
  206. class TargetGroupComponentInfo(ComponentInfo):
  207. type_name = 'TargetGroup'
  208. @staticmethod
  209. def parse(subpath, items):
  210. kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
  211. kwargs['required_libraries'] = items.get_list('required_libraries')
  212. kwargs['add_to_library_groups'] = items.get_list(
  213. 'add_to_library_groups')
  214. kwargs['has_jit'] = items.get_optional_bool('has_jit', False)
  215. kwargs['has_asmprinter'] = items.get_optional_bool('has_asmprinter',
  216. False)
  217. kwargs['has_asmparser'] = items.get_optional_bool('has_asmparser',
  218. False)
  219. kwargs['has_disassembler'] = items.get_optional_bool('has_disassembler',
  220. False)
  221. return TargetGroupComponentInfo(subpath, **kwargs)
  222. def __init__(self, subpath, name, parent, required_libraries = [],
  223. add_to_library_groups = [], has_jit = False,
  224. has_asmprinter = False, has_asmparser = False,
  225. has_disassembler = False):
  226. ComponentInfo.__init__(self, subpath, name, [], parent)
  227. # The names of the library components which are required when linking
  228. # with this component.
  229. self.required_libraries = list(required_libraries)
  230. # The names of the library group components this component should be
  231. # considered part of.
  232. self.add_to_library_groups = list(add_to_library_groups)
  233. # Whether or not this target supports the JIT.
  234. self.has_jit = bool(has_jit)
  235. # Whether or not this target defines an assembly printer.
  236. self.has_asmprinter = bool(has_asmprinter)
  237. # Whether or not this target defines an assembly parser.
  238. self.has_asmparser = bool(has_asmparser)
  239. # Whether or not this target defines an disassembler.
  240. self.has_disassembler = bool(has_disassembler)
  241. # Whether or not this target is enabled. This is set in response to
  242. # configuration parameters.
  243. self.enabled = False
  244. def get_component_references(self):
  245. for r in ComponentInfo.get_component_references(self):
  246. yield r
  247. for r in self.required_libraries:
  248. yield ('required library', r)
  249. for r in self.add_to_library_groups:
  250. yield ('library group', r)
  251. def get_llvmbuild_fragment(self):
  252. result = """\
  253. type = %s
  254. name = %s
  255. parent = %s
  256. """ % (self.type_name, self.name, self.parent)
  257. if self.required_libraries:
  258. result += 'required_libraries = %s\n' % ' '.join(
  259. self.required_libraries)
  260. if self.add_to_library_groups:
  261. result += 'add_to_library_groups = %s\n' % ' '.join(
  262. self.add_to_library_groups)
  263. for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
  264. 'has_jit'):
  265. if getattr(self, bool_key):
  266. result += '%s = 1\n' % (bool_key,)
  267. return result
  268. def get_llvmconfig_component_name(self):
  269. return self.name.lower()
  270. class ToolComponentInfo(ComponentInfo):
  271. type_name = 'Tool'
  272. @staticmethod
  273. def parse(subpath, items):
  274. kwargs = ComponentInfo.parse_items(items)
  275. kwargs['required_libraries'] = items.get_list('required_libraries')
  276. return ToolComponentInfo(subpath, **kwargs)
  277. def __init__(self, subpath, name, dependencies, parent,
  278. required_libraries):
  279. ComponentInfo.__init__(self, subpath, name, dependencies, parent)
  280. # The names of the library components which are required to link this
  281. # tool.
  282. self.required_libraries = list(required_libraries)
  283. def get_component_references(self):
  284. for r in ComponentInfo.get_component_references(self):
  285. yield r
  286. for r in self.required_libraries:
  287. yield ('required library', r)
  288. def get_llvmbuild_fragment(self):
  289. return """\
  290. type = %s
  291. name = %s
  292. parent = %s
  293. required_libraries = %s
  294. """ % (self.type_name, self.name, self.parent,
  295. ' '.join(self.required_libraries))
  296. class BuildToolComponentInfo(ToolComponentInfo):
  297. type_name = 'BuildTool'
  298. @staticmethod
  299. def parse(subpath, items):
  300. kwargs = ComponentInfo.parse_items(items)
  301. kwargs['required_libraries'] = items.get_list('required_libraries')
  302. return BuildToolComponentInfo(subpath, **kwargs)
  303. ###
  304. class IniFormatParser(dict):
  305. def get_list(self, key):
  306. # Check if the value is defined.
  307. value = self.get(key)
  308. if value is None:
  309. return []
  310. # Lists are just whitespace separated strings.
  311. return value.split()
  312. def get_optional_string(self, key):
  313. value = self.get_list(key)
  314. if not value:
  315. return None
  316. if len(value) > 1:
  317. raise ParseError("multiple values for scalar key: %r" % key)
  318. return value[0]
  319. def get_string(self, key):
  320. value = self.get_optional_string(key)
  321. if not value:
  322. raise ParseError("missing value for required string: %r" % key)
  323. return value
  324. def get_optional_bool(self, key, default = None):
  325. value = self.get_optional_string(key)
  326. if not value:
  327. return default
  328. if value not in ('0', '1'):
  329. raise ParseError("invalid value(%r) for boolean property: %r" % (
  330. value, key))
  331. return bool(int(value))
  332. def get_bool(self, key):
  333. value = self.get_optional_bool(key)
  334. if value is None:
  335. raise ParseError("missing value for required boolean: %r" % key)
  336. return value
  337. _component_type_map = dict(
  338. (t.type_name, t)
  339. for t in (GroupComponentInfo,
  340. LibraryComponentInfo, LibraryGroupComponentInfo,
  341. ToolComponentInfo, BuildToolComponentInfo,
  342. TargetGroupComponentInfo, OptionalLibraryComponentInfo))
  343. def load_from_path(path, subpath):
  344. # Load the LLVMBuild.txt file as an .ini format file.
  345. parser = configparser.RawConfigParser()
  346. parser.read(path)
  347. # Extract the common section.
  348. if parser.has_section("common"):
  349. common = IniFormatParser(parser.items("common"))
  350. parser.remove_section("common")
  351. else:
  352. common = IniFormatParser({})
  353. return common, _read_components_from_parser(parser, path, subpath)
  354. def _read_components_from_parser(parser, path, subpath):
  355. # We load each section which starts with 'component' as a distinct component
  356. # description (so multiple components can be described in one file).
  357. for section in parser.sections():
  358. if not section.startswith('component'):
  359. # We don't expect arbitrary sections currently, warn the user.
  360. warning("ignoring unknown section %r in %r" % (section, path))
  361. continue
  362. # Determine the type of the component to instantiate.
  363. if not parser.has_option(section, 'type'):
  364. fatal("invalid component %r in %r: %s" % (
  365. section, path, "no component type"))
  366. type_name = parser.get(section, 'type')
  367. type_class = _component_type_map.get(type_name)
  368. if type_class is None:
  369. fatal("invalid component %r in %r: %s" % (
  370. section, path, "invalid component type: %r" % type_name))
  371. # Instantiate the component based on the remaining values.
  372. try:
  373. info = type_class.parse(subpath,
  374. IniFormatParser(parser.items(section)))
  375. except TypeError:
  376. print >>sys.stderr, "error: invalid component %r in %r: %s" % (
  377. section, path, "unable to instantiate: %r" % type_name)
  378. import traceback
  379. traceback.print_exc()
  380. raise SystemExit(1)
  381. except ParseError:
  382. e = sys.exc_info()[1]
  383. fatal("unable to load component %r in %r: %s" % (
  384. section, path, e.message))
  385. info._source_path = path
  386. yield info