OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Adaptor script called through build/isolate.gypi. | 6 """Adaptor script called through build/isolate.gypi. |
7 | 7 |
8 Creates a wrapping .isolate which 'includes' the original one, that can be | 8 Creates a wrapping .isolate which 'includes' the original one, that can be |
9 consumed by tools/swarming_client/isolate.py. Path variables are determined | 9 consumed by tools/swarming_client/isolate.py. Path variables are determined |
10 based on the current working directory. The relative_cwd in the .isolated file | 10 based on the current working directory. The relative_cwd in the .isolated file |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 | 106 |
107 | 107 |
108 def using_blacklist(item): | 108 def using_blacklist(item): |
109 """Returns True if an item should be analyzed. | 109 """Returns True if an item should be analyzed. |
110 | 110 |
111 Ignores many rules that are assumed to not depend on a dynamic library. If | 111 Ignores many rules that are assumed to not depend on a dynamic library. If |
112 the assumption doesn't hold true anymore for a file format, remove it from | 112 the assumption doesn't hold true anymore for a file format, remove it from |
113 this list. This is simply an optimization. | 113 this list. This is simply an optimization. |
114 """ | 114 """ |
115 IGNORED = ( | 115 IGNORED = ( |
116 '.a', '.cc', '.css', '.def', '.h', '.html', '.js', '.json', '.manifest', | 116 '.a', '.cc', '.css', '.def', '.frag', '.h', '.html', '.js', '.json', |
117 '.o', '.obj', '.pak', '.png', '.pdb', '.strings', '.txt', | 117 '.manifest', '.o', '.obj', '.pak', '.png', '.pdb', '.strings', '.test', |
| 118 '.txt', '.vert', |
118 ) | 119 ) |
119 # ninja files use native path format. | 120 # ninja files use native path format. |
120 ext = os.path.splitext(item)[1] | 121 ext = os.path.splitext(item)[1] |
121 if ext in IGNORED: | 122 if ext in IGNORED: |
122 return False | 123 return False |
123 # Special case Windows, keep .dll.lib but discard .lib. | 124 # Special case Windows, keep .dll.lib but discard .lib. |
124 if item.endswith('.dll.lib'): | 125 if item.endswith('.dll.lib'): |
125 return True | 126 return True |
126 if ext == '.lib': | 127 if ext == '.lib': |
127 return False | 128 return False |
128 return item not in ('', '|', '||') | 129 return item not in ('', '|', '||') |
129 | 130 |
130 | 131 |
131 def raw_build_to_deps(item): | 132 def raw_build_to_deps(item): |
132 """Converts a raw ninja build statement into the list of interesting | 133 """Converts a raw ninja build statement into the list of interesting |
133 dependencies. | 134 dependencies. |
134 """ | 135 """ |
135 # TODO(maruel): Use a whitelist instead? .stamp, .so.TOC, .dylib.TOC, | 136 # TODO(maruel): Use a whitelist instead? .stamp, .so.TOC, .dylib.TOC, |
136 # .dll.lib, .exe and empty. | 137 # .dll.lib, .exe and empty. |
137 # The first item is the build rule, e.g. 'link', 'cxx', 'phony', etc. | 138 # The first item is the build rule, e.g. 'link', 'cxx', 'phony', etc. |
138 return filter(using_blacklist, item.split(' ')[1:]) | 139 return filter(using_blacklist, item.split(' ')[1:]) |
139 | 140 |
140 | 141 |
141 def recurse(target, build_steps, rules_seen): | 142 def collect_deps(target, build_steps, dependencies_added, rules_seen): |
142 """Recursively returns all the interesting dependencies for root_item.""" | 143 """Recursively adds all the interesting dependencies for |target| |
143 out = [] | 144 into |dependencies_added|. |
| 145 """ |
144 if rules_seen is None: | 146 if rules_seen is None: |
145 rules_seen = set() | 147 rules_seen = set() |
146 if target in rules_seen: | 148 if target in rules_seen: |
147 # TODO(maruel): Figure out how it happens. | 149 # TODO(maruel): Figure out how it happens. |
148 logging.warning('Circular dependency for %s!', target) | 150 logging.warning('Circular dependency for %s!', target) |
149 return [] | 151 return |
150 rules_seen.add(target) | 152 rules_seen.add(target) |
151 try: | 153 try: |
152 dependencies = raw_build_to_deps(build_steps[target]) | 154 dependencies = raw_build_to_deps(build_steps[target]) |
153 except KeyError: | 155 except KeyError: |
154 logging.info('Failed to find a build step to generate: %s', target) | 156 logging.info('Failed to find a build step to generate: %s', target) |
155 return [] | 157 return |
156 logging.debug('recurse(%s) -> %s', target, dependencies) | 158 logging.debug('collect_deps(%s) -> %s', target, dependencies) |
157 for dependency in dependencies: | 159 for dependency in dependencies: |
158 out.append(dependency) | 160 dependencies_added.add(dependency) |
159 dependency_raw_dependencies = build_steps.get(dependency) | 161 collect_deps(dependency, build_steps, dependencies_added, rules_seen) |
160 if dependency_raw_dependencies: | |
161 for i in raw_build_to_deps(dependency_raw_dependencies): | |
162 out.extend(recurse(i, build_steps, rules_seen)) | |
163 else: | |
164 logging.info('Failed to find a build step to generate: %s', dependency) | |
165 return out | |
166 | 162 |
167 | 163 |
168 def post_process_deps(build_dir, dependencies): | 164 def post_process_deps(build_dir, dependencies): |
169 """Processes the dependency list with OS specific rules.""" | 165 """Processes the dependency list with OS specific rules.""" |
170 def filter_item(i): | 166 def filter_item(i): |
171 if i.endswith('.so.TOC'): | 167 if i.endswith('.so.TOC'): |
172 # Remove only the suffix .TOC, not the .so! | 168 # Remove only the suffix .TOC, not the .so! |
173 return i[:-4] | 169 return i[:-4] |
174 if i.endswith('.dylib.TOC'): | 170 if i.endswith('.dylib.TOC'): |
175 # Remove only the suffix .TOC, not the .dylib! | 171 # Remove only the suffix .TOC, not the .dylib! |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 | 208 |
213 # Relative path between the new and old .isolate file. | 209 # Relative path between the new and old .isolate file. |
214 isolate_relpath = os.path.relpath( | 210 isolate_relpath = os.path.relpath( |
215 '.', temp_isolate_dir).replace(os.path.sep, '/') | 211 '.', temp_isolate_dir).replace(os.path.sep, '/') |
216 | 212 |
217 # It's a big assumption here that the name of the isolate file matches the | 213 # It's a big assumption here that the name of the isolate file matches the |
218 # primary target '_run'. Fix accordingly if this doesn't hold true, e.g. | 214 # primary target '_run'. Fix accordingly if this doesn't hold true, e.g. |
219 # complain to maruel@. | 215 # complain to maruel@. |
220 target = isolate[:-len('.isolate')] + '_run' | 216 target = isolate[:-len('.isolate')] + '_run' |
221 build_steps = load_ninja(build_dir) | 217 build_steps = load_ninja(build_dir) |
222 binary_deps = post_process_deps(build_dir, recurse(target, build_steps, None)) | 218 binary_deps = set() |
| 219 collect_deps(target, build_steps, binary_deps, None) |
| 220 binary_deps = post_process_deps(build_dir, binary_deps) |
223 logging.debug( | 221 logging.debug( |
224 'Binary dependencies:%s', ''.join('\n ' + i for i in binary_deps)) | 222 'Binary dependencies:%s', ''.join('\n ' + i for i in binary_deps)) |
225 | 223 |
226 # Now do actual wrapping .isolate. | 224 # Now do actual wrapping .isolate. |
227 isolate_dict = { | 225 isolate_dict = { |
228 'includes': [ | 226 'includes': [ |
229 posixpath.join(isolate_relpath, isolate), | 227 posixpath.join(isolate_relpath, isolate), |
230 ], | 228 ], |
231 'variables': { | 229 'variables': { |
232 # Will look like ['<(PRODUCT_DIR)/lib/flibuser_prefs.so']. | 230 # Will look like ['<(PRODUCT_DIR)/lib/flibuser_prefs.so']. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 | 270 |
273 swarming_client = os.path.join(SRC_DIR, 'tools', 'swarming_client') | 271 swarming_client = os.path.join(SRC_DIR, 'tools', 'swarming_client') |
274 sys.stdout.flush() | 272 sys.stdout.flush() |
275 result = subprocess.call( | 273 result = subprocess.call( |
276 [sys.executable, os.path.join(swarming_client, 'isolate.py')] + args) | 274 [sys.executable, os.path.join(swarming_client, 'isolate.py')] + args) |
277 return result | 275 return result |
278 | 276 |
279 | 277 |
280 if __name__ == '__main__': | 278 if __name__ == '__main__': |
281 sys.exit(main()) | 279 sys.exit(main()) |
OLD | NEW |