OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 | 2 |
3 # Copyright (c) 2011 Google Inc. All rights reserved. | 3 # Copyright (c) 2011 Google Inc. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 import gyp | 7 import gyp |
8 import gyp.common | 8 import gyp.common |
9 import gyp.system_test | 9 import gyp.system_test |
10 import os.path | 10 import os.path |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 | 213 |
214 if len(targets) > 1: | 214 if len(targets) > 1: |
215 stamp = self.GypPathToUniqueOutput(name + '.stamp') | 215 stamp = self.GypPathToUniqueOutput(name + '.stamp') |
216 targets = self.ninja.build(stamp, 'stamp', targets) | 216 targets = self.ninja.build(stamp, 'stamp', targets) |
217 self.ninja.newline() | 217 self.ninja.newline() |
218 return targets | 218 return targets |
219 | 219 |
220 def WriteSpec(self, spec, config): | 220 def WriteSpec(self, spec, config): |
221 """The main entry point for NinjaWriter: write the build rules for a spec. | 221 """The main entry point for NinjaWriter: write the build rules for a spec. |
222 | 222 |
223 Returns the path to the build output, or None.""" | 223 Returns the path to the build output, or None, and a list of targets for |
| 224 dependencies of its compile steps.""" |
224 | 225 |
225 self.name = spec['target_name'] | 226 self.name = spec['target_name'] |
226 self.toolset = spec['toolset'] | 227 self.toolset = spec['toolset'] |
227 | 228 |
228 if spec['type'] == 'settings': | 229 if spec['type'] == 'settings': |
229 # TODO: 'settings' is not actually part of gyp; it was | 230 # TODO: 'settings' is not actually part of gyp; it was |
230 # accidentally introduced somehow into just the Linux build files. | 231 # accidentally introduced somehow into just the Linux build files. |
231 # Remove this (or make it an error) once all the users are fixed. | 232 # Remove this (or make it an error) once all the users are fixed. |
232 print ("WARNING: %s uses invalid type 'settings'. " % self.name + | 233 print ("WARNING: %s uses invalid type 'settings'. " % self.name + |
233 "Please fix the source gyp file to use type 'none'.") | 234 "Please fix the source gyp file to use type 'none'.") |
234 print "See http://code.google.com/p/chromium/issues/detail?id=96629 ." | 235 print "See http://code.google.com/p/chromium/issues/detail?id=96629 ." |
235 spec['type'] = 'none' | 236 spec['type'] = 'none' |
236 | 237 |
237 # Compute predepends for all rules. | 238 # Compute predepends for all rules. |
238 # prebuild is the dependencies this target depends on before | 239 # actions_depends is the dependencies this target depends on before running |
239 # running any of its internal steps. | 240 # any of its action/rule/copy steps. |
240 prebuild = [] | 241 # compile_depends is the dependencies this target depends on before running |
| 242 # any of its compile steps. |
| 243 actions_depends = [] |
| 244 compile_depends = [] |
241 if 'dependencies' in spec: | 245 if 'dependencies' in spec: |
242 for dep in spec['dependencies']: | 246 for dep in spec['dependencies']: |
243 if dep in self.target_outputs: | 247 if dep in self.target_outputs: |
244 prebuild.append(self.target_outputs[dep][0]) | 248 input, precompile_input, linkable = self.target_outputs[dep] |
245 prebuild = self.WriteCollapsedDependencies('predepends', prebuild) | 249 actions_depends.append(input) |
| 250 compile_depends.extend(precompile_input) |
| 251 actions_depends = self.WriteCollapsedDependencies('actions_depends', |
| 252 actions_depends) |
246 | 253 |
247 # Write out actions, rules, and copies. These must happen before we | 254 # Write out actions, rules, and copies. These must happen before we |
248 # compile any sources, so compute a list of predependencies for sources | 255 # compile any sources, so compute a list of predependencies for sources |
249 # while we do it. | 256 # while we do it. |
250 extra_sources = [] | 257 extra_sources = [] |
251 sources_predepends = self.WriteActionsRulesCopies(spec, extra_sources, | 258 sources_depends = self.WriteActionsRulesCopies(spec, extra_sources, |
252 prebuild) | 259 actions_depends) |
| 260 |
| 261 # If we have actions/rules/copies, we depend directly on those, but |
| 262 # otherwise we depend on dependent target's actions/rules/copies etc. |
| 263 # We never need to explicitly depend on previous target's link steps, |
| 264 # because no compile ever depends on them. |
| 265 compile_depends = self.WriteCollapsedDependencies('compile_depends', |
| 266 sources_depends or compile_depends) |
253 | 267 |
254 # Write out the compilation steps, if any. | 268 # Write out the compilation steps, if any. |
255 link_deps = [] | 269 link_deps = [] |
256 sources = spec.get('sources', []) + extra_sources | 270 sources = spec.get('sources', []) + extra_sources |
257 if sources: | 271 if sources: |
258 link_deps = self.WriteSources(config, sources, | 272 link_deps = self.WriteSources(config, sources, compile_depends) |
259 sources_predepends or prebuild) | |
260 # Some actions/rules output 'sources' that are already object files. | 273 # Some actions/rules output 'sources' that are already object files. |
261 link_deps += [self.GypPathToNinja(f) for f in sources if f.endswith('.o')] | 274 link_deps += [self.GypPathToNinja(f) for f in sources if f.endswith('.o')] |
262 | 275 |
263 # The final output of our target depends on the last output of the | 276 # The final output of our target depends on the last output of the |
264 # above steps. | 277 # above steps. |
265 output = None | 278 output = None |
266 final_deps = link_deps or sources_predepends or prebuild | 279 final_deps = link_deps or sources_depends or actions_depends |
267 if final_deps: | 280 if final_deps: |
268 output = self.WriteTarget(spec, config, final_deps) | 281 output = self.WriteTarget(spec, config, final_deps, |
| 282 order_only=actions_depends) |
269 if self.name != output and self.toolset == 'target': | 283 if self.name != output and self.toolset == 'target': |
270 # Write a short name to build this target. This benefits both the | 284 # Write a short name to build this target. This benefits both the |
271 # "build chrome" case as well as the gyp tests, which expect to be | 285 # "build chrome" case as well as the gyp tests, which expect to be |
272 # able to run actions and build libraries by their short name. | 286 # able to run actions and build libraries by their short name. |
273 self.ninja.build(self.name, 'phony', output) | 287 self.ninja.build(self.name, 'phony', output) |
274 return output | 288 return output, compile_depends |
275 | 289 |
276 def WriteActionsRulesCopies(self, spec, extra_sources, prebuild): | 290 def WriteActionsRulesCopies(self, spec, extra_sources, prebuild): |
277 """Write out the Actions, Rules, and Copies steps. Return any outputs | 291 """Write out the Actions, Rules, and Copies steps. Return any outputs |
278 of these steps (or a stamp file if there are lots of outputs).""" | 292 of these steps (or a stamp file if there are lots of outputs).""" |
279 outputs = [] | 293 outputs = [] |
280 | 294 |
281 if 'actions' in spec: | 295 if 'actions' in spec: |
282 outputs += self.WriteActions(spec['actions'], extra_sources, prebuild) | 296 outputs += self.WriteActions(spec['actions'], extra_sources, prebuild) |
283 if 'rules' in spec: | 297 if 'rules' in spec: |
284 outputs += self.WriteRules(spec['rules'], extra_sources, prebuild) | 298 outputs += self.WriteRules(spec['rules'], extra_sources, prebuild) |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
441 # TODO: should we assert here on unexpected extensions? | 455 # TODO: should we assert here on unexpected extensions? |
442 continue | 456 continue |
443 input = self.GypPathToNinja(source) | 457 input = self.GypPathToNinja(source) |
444 output = self.GypPathToUniqueOutput(filename + '.o') | 458 output = self.GypPathToUniqueOutput(filename + '.o') |
445 self.ninja.build(output, command, input, | 459 self.ninja.build(output, command, input, |
446 order_only=predepends) | 460 order_only=predepends) |
447 outputs.append(output) | 461 outputs.append(output) |
448 self.ninja.newline() | 462 self.ninja.newline() |
449 return outputs | 463 return outputs |
450 | 464 |
451 def WriteTarget(self, spec, config, final_deps): | 465 def WriteTarget(self, spec, config, final_deps, order_only): |
452 if spec['type'] == 'none': | 466 if spec['type'] == 'none': |
453 # This target doesn't have any explicit final output, but is instead | 467 # This target doesn't have any explicit final output, but is instead |
454 # used for its effects before the final output (e.g. copies steps). | 468 # used for its effects before the final output (e.g. copies steps). |
455 # Reuse the existing output if it's easy. | 469 # Reuse the existing output if it's easy. |
456 if len(final_deps) == 1: | 470 if len(final_deps) == 1: |
457 return final_deps[0] | 471 return final_deps[0] |
458 # Otherwise, fall through to writing out a stamp file. | 472 # Otherwise, fall through to writing out a stamp file. |
459 | 473 |
460 output = self.ComputeOutput(spec) | 474 output = self.ComputeOutput(spec) |
461 | 475 |
462 output_uses_linker = spec['type'] in ('executable', 'loadable_module', | 476 output_uses_linker = spec['type'] in ('executable', 'loadable_module', |
463 'shared_library') | 477 'shared_library') |
464 | 478 |
465 implicit_deps = set() | 479 implicit_deps = set() |
466 if 'dependencies' in spec: | 480 if 'dependencies' in spec: |
467 # Two kinds of dependencies: | 481 # Two kinds of dependencies: |
468 # - Linkable dependencies (like a .a or a .so): add them to the link line. | 482 # - Linkable dependencies (like a .a or a .so): add them to the link line. |
469 # - Non-linkable dependencies (like a rule that generates a file | 483 # - Non-linkable dependencies (like a rule that generates a file |
470 # and writes a stamp file): add them to implicit_deps | 484 # and writes a stamp file): add them to implicit_deps |
471 if output_uses_linker: | 485 if output_uses_linker: |
472 extra_deps = set() | 486 extra_deps = set() |
473 for dep in spec['dependencies']: | 487 for dep in spec['dependencies']: |
474 input, linkable = self.target_outputs.get(dep, (None, False)) | 488 input, _, linkable = self.target_outputs.get(dep, (None, [], False)) |
475 if not input: | 489 if not input: |
476 continue | 490 continue |
477 if linkable: | 491 if linkable: |
478 extra_deps.add(input) | 492 extra_deps.add(input) |
479 else: | 493 else: |
480 # TODO: Chrome-specific HACK. Chrome runs this lastchange rule on | 494 # TODO: Chrome-specific HACK. Chrome runs this lastchange rule on |
481 # every build, but we don't want to rebuild when it runs. | 495 # every build, but we don't want to rebuild when it runs. |
482 if 'lastchange' not in input: | 496 if 'lastchange' not in input: |
483 implicit_deps.add(input) | 497 implicit_deps.add(input) |
484 final_deps.extend(list(extra_deps)) | 498 final_deps.extend(list(extra_deps)) |
(...skipping 13 matching lines...) Expand all Loading... |
498 self.WriteVariableList('libs', | 512 self.WriteVariableList('libs', |
499 gyp.common.uniquer(map(self.ExpandSpecial, | 513 gyp.common.uniquer(map(self.ExpandSpecial, |
500 spec.get('libraries', [])))) | 514 spec.get('libraries', [])))) |
501 | 515 |
502 extra_bindings = [] | 516 extra_bindings = [] |
503 if command in ('solink', 'solink_module'): | 517 if command in ('solink', 'solink_module'): |
504 extra_bindings.append(('soname', os.path.split(output)[1])) | 518 extra_bindings.append(('soname', os.path.split(output)[1])) |
505 | 519 |
506 self.ninja.build(output, command, final_deps, | 520 self.ninja.build(output, command, final_deps, |
507 implicit=list(implicit_deps), | 521 implicit=list(implicit_deps), |
| 522 order_only=order_only, |
508 variables=extra_bindings) | 523 variables=extra_bindings) |
509 | 524 |
510 return output | 525 return output |
511 | 526 |
512 def ComputeOutputFileName(self, spec): | 527 def ComputeOutputFileName(self, spec): |
513 """Compute the filename of the final output for the current target.""" | 528 """Compute the filename of the final output for the current target.""" |
514 | 529 |
515 # Compute filename prefix: the product prefix, or a default for | 530 # Compute filename prefix: the product prefix, or a default for |
516 # the product type. | 531 # the product type. |
517 DEFAULT_PREFIX = { | 532 DEFAULT_PREFIX = { |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
715 output_file = os.path.join(obj, base_path, name + '.ninja') | 730 output_file = os.path.join(obj, base_path, name + '.ninja') |
716 spec = target_dicts[qualified_target] | 731 spec = target_dicts[qualified_target] |
717 config = spec['configurations'][config_name] | 732 config = spec['configurations'][config_name] |
718 | 733 |
719 writer = NinjaWriter(target_outputs, base_path, builddir, | 734 writer = NinjaWriter(target_outputs, base_path, builddir, |
720 OpenOutput(os.path.join(options.toplevel_dir, | 735 OpenOutput(os.path.join(options.toplevel_dir, |
721 builddir, | 736 builddir, |
722 output_file))) | 737 output_file))) |
723 master_ninja.subninja(output_file) | 738 master_ninja.subninja(output_file) |
724 | 739 |
725 output = writer.WriteSpec(spec, config) | 740 output, compile_depends = writer.WriteSpec(spec, config) |
726 if output: | 741 if output: |
727 linkable = spec['type'] in ('static_library', 'shared_library') | 742 linkable = spec['type'] in ('static_library', 'shared_library') |
728 target_outputs[qualified_target] = (output, linkable) | 743 target_outputs[qualified_target] = (output, compile_depends, linkable) |
729 | 744 |
730 if qualified_target in all_targets: | 745 if qualified_target in all_targets: |
731 all_outputs.add(output) | 746 all_outputs.add(output) |
732 | 747 |
733 if all_outputs: | 748 if all_outputs: |
734 master_ninja.build('all', 'phony', list(all_outputs)) | 749 master_ninja.build('all', 'phony', list(all_outputs)) |
OLD | NEW |