From: Daniel Dunbar Date: Thu, 3 Nov 2011 17:56:12 +0000 (+0000) Subject: llvm-build: Validate information on the loaded components and form the topological... X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=1cf14aff1bd7aa9343262f26f39c7f10fae68c0e llvm-build: Validate information on the loaded components and form the topological ordering among them (as well as validating that there are no cycles). - Currently we require that all references between components (except the parent relation) fit into a DAG -- this could be relaxed later if it ever proves to be useful. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@143623 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/utils/llvm-build/llvmbuild/componentinfo.py b/utils/llvm-build/llvmbuild/componentinfo.py index e15dbda756f..22ce0b4fde7 100644 --- a/utils/llvm-build/llvmbuild/componentinfo.py +++ b/utils/llvm-build/llvmbuild/componentinfo.py @@ -37,6 +37,17 @@ class ComponentInfo(object): # under. self.parent = parent + def get_component_references(self): + """get_component_references() -> iter + + Return an iterator over the named references to other components from + this object. Items are of the form (reference-type, component-name). + """ + + # Parent references are handled specially. + for r in self.dependencies: + yield ('dependency', r) + class GroupComponentInfo(ComponentInfo): """ Group components have no semantics as far as the build system are concerned, @@ -81,6 +92,14 @@ class LibraryComponentInfo(ComponentInfo): # considered part of. self.add_to_library_groups = list(add_to_library_groups) + def get_component_references(self): + for r in ComponentInfo.get_component_references(self): + yield r + for r in self.required_libraries: + yield ('required library', r) + for r in self.add_to_library_groups: + yield ('library group', r) + class LibraryGroupComponentInfo(ComponentInfo): type_name = 'LibraryGroup' @@ -104,6 +123,14 @@ class LibraryGroupComponentInfo(ComponentInfo): # considered part of. self.add_to_library_groups = list(add_to_library_groups) + def get_component_references(self): + for r in ComponentInfo.get_component_references(self): + yield r + for r in self.required_libraries: + yield ('required library', r) + for r in self.add_to_library_groups: + yield ('library group', r) + class ToolComponentInfo(ComponentInfo): type_name = 'Tool' @@ -121,6 +148,12 @@ class ToolComponentInfo(ComponentInfo): # tool. self.required_libraries = list(required_libraries) + def get_component_references(self): + for r in ComponentInfo.get_component_references(self): + yield r + for r in self.required_libraries: + yield ('required library', r) + class BuildToolComponentInfo(ToolComponentInfo): type_name = 'BuildTool' diff --git a/utils/llvm-build/llvmbuild/main.py b/utils/llvm-build/llvmbuild/main.py index 57233a070e3..a734ac16414 100644 --- a/utils/llvm-build/llvmbuild/main.py +++ b/utils/llvm-build/llvmbuild/main.py @@ -1,8 +1,12 @@ -import pprint import os +import sys import componentinfo +from util import * + +### + class LLVMProjectInfo(object): @staticmethod def load_infos_from_path(llvmbuild_source_root): @@ -35,9 +39,62 @@ class LLVMProjectInfo(object): return LLVMProjectInfo(source_root, infos) def __init__(self, source_root, component_infos): + # Store our simple ivars. self.source_root = source_root self.component_infos = component_infos + # Create the component info map and validate that component names are + # unique. + self.component_info_map = {} + for ci in component_infos: + existing = self.component_info_map.get(ci.name) + if existing is not None: + # We found a duplicate component name, report it and error out. + fatal("found duplicate component %r (at %r and %r)" % ( + ci.name, ci.subpath, existing.subpath)) + self.component_info_map[ci.name] = ci + + # Topologically order the component information according to their + # component references. + def visit_component_info(ci, current_stack, current_set): + # Check for a cycles. + if ci in current_set: + # We found a cycle, report it and error out. + cycle_description = ' -> '.join( + '%r (%s)' % (ci.name, relation) + for relation,ci in current_stack) + fatal("found cycle to %r after following: %s -> %s" % ( + ci.name, cycle_description, ci.name)) + + # If we have already visited this item, we are done. + if ci not in components_to_visit: + return + + # Otherwise, mark the component info as visited and traverse. + components_to_visit.remove(ci) + + for relation,referent_name in ci.get_component_references(): + # Validate that the reference is ok. + referent = self.component_info_map.get(referent_name) + if referent is None: + fatal("component %r has invalid reference %r (via %r)" % ( + ci.name, referent_name, relation)) + + # Visit the reference. + current_stack.append((relation,ci)) + current_set.add(ci) + visit_component_info(referent, current_stack, current_set) + current_set.remove(ci) + current_stack.pop() + + # Finally, add the component info to the ordered list. + self.ordered_component_infos.append(ci) + + self.ordered_component_infos = [] + components_to_visit = set(component_infos) + while components_to_visit: + visit_component_info(iter(components_to_visit).next(), [], set()) + def main(): from optparse import OptionParser, OptionGroup parser = OptionParser("usage: %prog [options]")