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 |