Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2012 Google Inc. All rights reserved. | 1 # Copyright (c) 2012 Google Inc. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """ | 5 """ |
| 6 This module contains classes that help to emulate xcodebuild behavior on top of | 6 This module contains classes that help to emulate xcodebuild behavior on top of |
| 7 other build systems, such as make and ninja. | 7 other build systems, such as make and ninja. |
| 8 """ | 8 """ |
| 9 | 9 |
| 10 import gyp.common | 10 import gyp.common |
| (...skipping 961 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 972 string = string.replace('${' + k + '}', expansions[k]) | 972 string = string.replace('${' + k + '}', expansions[k]) |
| 973 string = string.replace('$(' + k + ')', expansions[k]) | 973 string = string.replace('$(' + k + ')', expansions[k]) |
| 974 string = string.replace('$' + k, expansions[k]) | 974 string = string.replace('$' + k, expansions[k]) |
| 975 return string | 975 return string |
| 976 | 976 |
| 977 | 977 |
| 978 def TopologicallySortedEnvVarKeys(env): | 978 def TopologicallySortedEnvVarKeys(env): |
| 979 """Takes a dict |env| whose values are strings that can refer to other keys, | 979 """Takes a dict |env| whose values are strings that can refer to other keys, |
| 980 for example env['foo'] = '$(bar) and $(baz)'. Returns a list L of all keys of | 980 for example env['foo'] = '$(bar) and $(baz)'. Returns a list L of all keys of |
| 981 env such that key2 is after key1 in L if env[key2] refers to env[key1]. | 981 env such that key2 is after key1 in L if env[key2] refers to env[key1]. |
| 982 (This is really reversed topological order). | |
|
Nico
2012/05/10 19:20:23
Remove useless comment addition
bradn
2012/05/10 20:17:56
Yeah the double reversing thing seems goofy.
I had
| |
| 982 | 983 |
| 983 Throws an Exception in case of dependency cycles. | 984 Throws an Exception in case of dependency cycles. |
| 984 """ | 985 """ |
| 985 # Since environment variables can refer to other variables, the evaluation | 986 # Since environment variables can refer to other variables, the evaluation |
| 986 # order is important. Below is the logic to compute the dependency graph | 987 # order is important. Below is the logic to compute the dependency graph |
| 987 # and sort it. | 988 # and sort it. |
| 988 regex = re.compile(r'\$\{([a-zA-Z0-9\-_]+)\}') | 989 regex = re.compile(r'\$\{([a-zA-Z0-9\-_]+)\}') |
| 989 | 990 def GetEdges(node): |
| 990 # First sort the list of keys. | 991 # Get all variable references for variable defined in env. |
| 991 key_list = sorted(env.keys()) | 992 matches = set([v for v in regex.findall(env[node]) if v in env]) |
| 992 | |
| 993 # Phase 1: Create a set of edges of (DEPENDEE, DEPENDER) where in the graph, | |
| 994 # DEPENDEE -> DEPENDER. Also create sets of dependers and dependees. | |
| 995 edges = set() | |
| 996 dependees = set() | |
| 997 dependers = set() | |
| 998 for k in key_list: | |
| 999 matches = regex.findall(env[k]) | |
| 1000 if not len(matches): | |
| 1001 continue | |
| 1002 | |
| 1003 depends_on_other_var = False | |
| 1004 for dependee in matches: | 993 for dependee in matches: |
| 1005 assert '${' not in dependee, 'Nested variables not supported: ' + dependee | 994 assert '${' not in dependee, 'Nested variables not supported: ' + dependee |
| 1006 if dependee in env: | 995 return matches |
| 1007 edges.add((dependee, k)) | |
| 1008 dependees.add(dependee) | |
| 1009 depends_on_other_var = True | |
| 1010 if depends_on_other_var: | |
| 1011 dependers.add(k) | |
| 1012 | 996 |
| 1013 # Phase 2: Create a list of graph nodes with no incoming edges. | 997 try: |
| 1014 sorted_nodes = [] | 998 order = gyp.common.TopologicallySorted(env.keys(), GetEdges) |
| 1015 edgeless_nodes = dependees - dependers | 999 order.reverse() |
|
Nico
2012/05/10 19:20:23
Err g.c.TS also reverses last thing. Maybe it shou
bradn
2012/05/10 20:17:56
Yeah, I think I'll just move to forward topologica
| |
| 1016 | 1000 return order |
| 1017 # Phase 3: Perform Kahn topological sort. | 1001 except CycleError, e: |
| 1018 while len(edgeless_nodes): | 1002 raise Exception( |
| 1019 # Find a node with no incoming edges, add it to the sorted list, and | 1003 'Xcode environment variables are cyclically dependent: ' + str(e.nodes)) |
| 1020 # remove it from the list of nodes that aren't part of the graph. | |
| 1021 node = edgeless_nodes.pop() | |
| 1022 sorted_nodes.append(node) | |
| 1023 key_list.remove(node) | |
| 1024 | |
| 1025 # Find all the edges between |node| and other nodes. | |
| 1026 edges_to_node = [e for e in edges if e[0] == node] | |
| 1027 for edge in edges_to_node: | |
| 1028 edges.remove(edge) | |
| 1029 # If the node connected to |node| by |edge| has no other incoming edges, | |
| 1030 # add it to |edgeless_nodes|. | |
| 1031 if not len([e for e in edges if e[1] == edge[1]]): | |
| 1032 edgeless_nodes.add(edge[1]) | |
| 1033 | |
| 1034 # Any remaining edges indicate a cycle. | |
| 1035 if len(edges): | |
| 1036 raise Exception('Xcode environment variables are cyclically dependent: ' + | |
| 1037 str(edges)) | |
| 1038 | |
| 1039 # Append the "nodes" not in the graph to those that were just sorted. | |
| 1040 sorted_nodes.extend(key_list) | |
| 1041 | |
| 1042 return sorted_nodes | |
| 1043 | 1004 |
| 1044 | 1005 |
| 1045 def GetSpecPostbuildCommands(spec, quiet=False): | 1006 def GetSpecPostbuildCommands(spec, quiet=False): |
| 1046 """Returns the list of postbuilds explicitly defined on |spec|, in a form | 1007 """Returns the list of postbuilds explicitly defined on |spec|, in a form |
| 1047 executable by a shell.""" | 1008 executable by a shell.""" |
| 1048 postbuilds = [] | 1009 postbuilds = [] |
| 1049 for postbuild in spec.get('postbuilds', []): | 1010 for postbuild in spec.get('postbuilds', []): |
| 1050 if not quiet: | 1011 if not quiet: |
| 1051 postbuilds.append('echo POSTBUILD\\(%s\\) %s' % ( | 1012 postbuilds.append('echo POSTBUILD\\(%s\\) %s' % ( |
| 1052 spec['target_name'], postbuild['postbuild_name'])) | 1013 spec['target_name'], postbuild['postbuild_name'])) |
| 1053 postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action'])) | 1014 postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action'])) |
| 1054 return postbuilds | 1015 return postbuilds |
| OLD | NEW |