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 import copy | 5 import copy |
6 import gyp | 6 import gyp |
7 import gyp.common | 7 import gyp.common |
8 import gyp.msvs_emulation | 8 import gyp.msvs_emulation |
9 import gyp.MSVSVersion | 9 import gyp.MSVSVersion |
10 import gyp.system_test | 10 import gyp.system_test |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
182 # All paths as written into the .ninja files are relative to the build | 182 # All paths as written into the .ninja files are relative to the build |
183 # directory. Call these paths "ninja paths". | 183 # directory. Call these paths "ninja paths". |
184 # | 184 # |
185 # We translate between these two notions of paths with two helper | 185 # We translate between these two notions of paths with two helper |
186 # functions: | 186 # functions: |
187 # | 187 # |
188 # - GypPathToNinja translates a gyp path (i.e. relative to the .gyp file) | 188 # - GypPathToNinja translates a gyp path (i.e. relative to the .gyp file) |
189 # into the equivalent ninja path. | 189 # into the equivalent ninja path. |
190 # | 190 # |
191 # - GypPathToUniqueOutput translates a gyp path into a ninja path to write | 191 # - GypPathToUniqueOutput translates a gyp path into a ninja path to write |
192 # an output file; the result can be namespaced such that is unique | 192 # an output file; the result can be namespaced such that it is unique |
193 # to the input file name as well as the output target name. | 193 # to the input file name as well as the output target name. |
194 | 194 |
195 class NinjaWriter: | 195 class NinjaWriter: |
196 def __init__(self, target_outputs, base_dir, build_dir, output_file, flavor, | 196 def __init__(self, qualified_target, target_outputs, base_dir, build_dir, |
197 abs_build_dir=None): | 197 output_file, flavor, abs_build_dir=None): |
198 """ | 198 """ |
199 base_dir: path from source root to directory containing this gyp file, | 199 base_dir: path from source root to directory containing this gyp file, |
200 by gyp semantics, all input paths are relative to this | 200 by gyp semantics, all input paths are relative to this |
201 build_dir: path from source root to build output | 201 build_dir: path from source root to build output |
202 abs_build_dir: absolute path to the build directory | 202 abs_build_dir: absolute path to the build directory |
203 """ | 203 """ |
204 | 204 |
205 self.qualified_target = qualified_target | |
205 self.target_outputs = target_outputs | 206 self.target_outputs = target_outputs |
206 self.base_dir = base_dir | 207 self.base_dir = base_dir |
207 self.build_dir = build_dir | 208 self.build_dir = build_dir |
208 self.ninja = ninja_syntax.Writer(output_file) | 209 self.ninja = ninja_syntax.Writer(output_file) |
209 self.flavor = flavor | 210 self.flavor = flavor |
210 self.abs_build_dir = abs_build_dir | 211 self.abs_build_dir = abs_build_dir |
211 self.obj_ext = '.obj' if flavor == 'win' else '.o' | 212 self.obj_ext = '.obj' if flavor == 'win' else '.o' |
212 | 213 |
213 # Relative path from build output dir to base dir. | 214 # Relative path from build output dir to base dir. |
214 self.build_to_base = os.path.join(InvertRelativePath(build_dir), base_dir) | 215 self.build_to_base = os.path.join(InvertRelativePath(build_dir), base_dir) |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
406 if self.is_mac_bundle: | 407 if self.is_mac_bundle: |
407 mac_bundle_depends.append(output) | 408 mac_bundle_depends.append(output) |
408 | 409 |
409 # Bundle all of the above together, if needed. | 410 # Bundle all of the above together, if needed. |
410 if self.is_mac_bundle: | 411 if self.is_mac_bundle: |
411 output = self.WriteMacBundle(spec, mac_bundle_depends) | 412 output = self.WriteMacBundle(spec, mac_bundle_depends) |
412 | 413 |
413 if not output: | 414 if not output: |
414 return None | 415 return None |
415 | 416 |
416 if self.name != output and self.toolset == 'target': | |
417 # Write a short name to build this target. This benefits both the | |
418 # "build chrome" case as well as the gyp tests, which expect to be | |
419 # able to run actions and build libraries by their short name. | |
420 self.ninja.build(self.name, 'phony', output) | |
421 | |
422 assert self.target.FinalOutput(), output | 417 assert self.target.FinalOutput(), output |
423 return self.target | 418 return self.target |
424 | 419 |
425 def _WinIdlRule(self, source, prebuild, outputs): | 420 def _WinIdlRule(self, source, prebuild, outputs): |
426 """Handle the implicit VS .idl rule for one source file. Fills |outputs| | 421 """Handle the implicit VS .idl rule for one source file. Fills |outputs| |
427 with files that are generated.""" | 422 with files that are generated.""" |
428 outdir, output, vars, flags = self.msvs_settings.GetIdlBuildData( | 423 outdir, output, vars, flags = self.msvs_settings.GetIdlBuildData( |
429 source, self.config_name) | 424 source, self.config_name) |
430 outdir = self.GypPathToNinja(outdir) | 425 outdir = self.GypPathToNinja(outdir) |
431 def fix_path(path, rel=None): | 426 def fix_path(path, rel=None): |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
501 | 496 |
502 def WriteActions(self, actions, extra_sources, prebuild, | 497 def WriteActions(self, actions, extra_sources, prebuild, |
503 extra_mac_bundle_resources): | 498 extra_mac_bundle_resources): |
504 # Actions cd into the base directory. | 499 # Actions cd into the base directory. |
505 env = self.GetSortedXcodeEnv() | 500 env = self.GetSortedXcodeEnv() |
506 if self.flavor == 'win': | 501 if self.flavor == 'win': |
507 env = self.msvs_settings.GetVSMacroEnv('$!PRODUCT_DIR') | 502 env = self.msvs_settings.GetVSMacroEnv('$!PRODUCT_DIR') |
508 all_outputs = [] | 503 all_outputs = [] |
509 for action in actions: | 504 for action in actions: |
510 # First write out a rule for the action. | 505 # First write out a rule for the action. |
511 name = action['action_name'] | 506 name = '%s_%s' % (self.qualified_target, action['action_name']) |
Nico
2012/06/08 19:31:02
This will make target 'a' with rule 'b_c' clash wi
Steve Block
2012/06/11 09:33:55
Yes, but I think it's unlikely we'll hit such prob
| |
512 description = self.GenerateDescription('ACTION', | 507 description = self.GenerateDescription('ACTION', |
513 action.get('message', None), | 508 action.get('message', None), |
514 name) | 509 name) |
515 is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(action) | 510 is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(action) |
516 if self.flavor == 'win' else False) | 511 if self.flavor == 'win' else False) |
517 args = action['action'] | 512 args = action['action'] |
518 args = [self.msvs_settings.ConvertVSMacros(arg, self.base_to_build) | 513 args = [self.msvs_settings.ConvertVSMacros(arg, self.base_to_build) |
519 for arg in args] if self.flavor == 'win' else args | 514 for arg in args] if self.flavor == 'win' else args |
520 rule_name = self.WriteNewNinjaRule(name, args, description, | 515 rule_name = self.WriteNewNinjaRule(name, args, description, |
521 is_cygwin, env=env) | 516 is_cygwin, env=env) |
(...skipping 12 matching lines...) Expand all Loading... | |
534 | 529 |
535 self.ninja.newline() | 530 self.ninja.newline() |
536 | 531 |
537 return all_outputs | 532 return all_outputs |
538 | 533 |
539 def WriteRules(self, rules, extra_sources, prebuild, | 534 def WriteRules(self, rules, extra_sources, prebuild, |
540 extra_mac_bundle_resources): | 535 extra_mac_bundle_resources): |
541 all_outputs = [] | 536 all_outputs = [] |
542 for rule in rules: | 537 for rule in rules: |
543 # First write out a rule for the rule action. | 538 # First write out a rule for the rule action. |
544 name = rule['rule_name'] | 539 name = '%s_%s' % (self.qualified_target, rule['rule_name']) |
545 # Skip a rule with no action and no inputs. | 540 # Skip a rule with no action and no inputs. |
546 if 'action' not in rule and not rule.get('rule_sources', []): | 541 if 'action' not in rule and not rule.get('rule_sources', []): |
547 continue | 542 continue |
548 args = rule['action'] | 543 args = rule['action'] |
549 description = self.GenerateDescription( | 544 description = self.GenerateDescription( |
550 'RULE', | 545 'RULE', |
551 rule.get('message', None), | 546 rule.get('message', None), |
552 ('%s ' + generator_default_variables['RULE_INPUT_PATH']) % name) | 547 ('%s ' + generator_default_variables['RULE_INPUT_PATH']) % name) |
553 is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(rule) | 548 is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(rule) |
554 if self.flavor == 'win' else False) | 549 if self.flavor == 'win' else False) |
(...skipping 535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1090 | 1085 |
1091 Returns the name of the new rule.""" | 1086 Returns the name of the new rule.""" |
1092 | 1087 |
1093 # TODO: we shouldn't need to qualify names; we do it because | 1088 # TODO: we shouldn't need to qualify names; we do it because |
1094 # currently the ninja rule namespace is global, but it really | 1089 # currently the ninja rule namespace is global, but it really |
1095 # should be scoped to the subninja. | 1090 # should be scoped to the subninja. |
1096 rule_name = self.name | 1091 rule_name = self.name |
1097 if self.toolset == 'target': | 1092 if self.toolset == 'target': |
1098 rule_name += '.' + self.toolset | 1093 rule_name += '.' + self.toolset |
1099 rule_name += '.' + name | 1094 rule_name += '.' + name |
1100 rule_name = re.sub('[^a-zA-Z0-9_]', '_', rule_name) | 1095 rule_name = re.sub('[^a-zA-Z0-9_]', '_', rule_name) |
Nico
2012/06/08 19:31:02
Likewise, one issue with this is that 'a+b' and 'a
| |
1101 | 1096 |
1102 args = args[:] | 1097 args = args[:] |
1103 | 1098 |
1104 if self.flavor == 'win': | 1099 if self.flavor == 'win': |
1105 description = self.msvs_settings.ConvertVSMacros(description) | 1100 description = self.msvs_settings.ConvertVSMacros(description) |
1106 | 1101 |
1107 # gyp dictates that commands are run from the base directory. | 1102 # gyp dictates that commands are run from the base directory. |
1108 # cd into the directory before running, and adjust paths in | 1103 # cd into the directory before running, and adjust paths in |
1109 # the arguments to point to the proper locations. | 1104 # the arguments to point to the proper locations. |
1110 if self.flavor == 'win': | 1105 if self.flavor == 'win': |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1480 all_targets = set() | 1475 all_targets = set() |
1481 for build_file in params['build_files']: | 1476 for build_file in params['build_files']: |
1482 for target in gyp.common.AllTargets(target_list, | 1477 for target in gyp.common.AllTargets(target_list, |
1483 target_dicts, | 1478 target_dicts, |
1484 os.path.normpath(build_file)): | 1479 os.path.normpath(build_file)): |
1485 all_targets.add(target) | 1480 all_targets.add(target) |
1486 all_outputs = set() | 1481 all_outputs = set() |
1487 | 1482 |
1488 # target_outputs is a map from qualified target name to a Target object. | 1483 # target_outputs is a map from qualified target name to a Target object. |
1489 target_outputs = {} | 1484 target_outputs = {} |
1485 # target_short_names is a map from target short name to a list of Target | |
1486 # objects. | |
1487 target_short_names = {} | |
1490 for qualified_target in target_list: | 1488 for qualified_target in target_list: |
1491 # qualified_target is like: third_party/icu/icu.gyp:icui18n#target | 1489 # qualified_target is like: third_party/icu/icu.gyp:icui18n#target |
1492 build_file, name, toolset = \ | 1490 build_file, name, toolset = \ |
1493 gyp.common.ParseQualifiedTarget(qualified_target) | 1491 gyp.common.ParseQualifiedTarget(qualified_target) |
1494 | 1492 |
1495 this_make_global_settings = data[build_file].get('make_global_settings', []) | 1493 this_make_global_settings = data[build_file].get('make_global_settings', []) |
1496 assert make_global_settings == this_make_global_settings, ( | 1494 assert make_global_settings == this_make_global_settings, ( |
1497 "make_global_settings needs to be the same for all targets.") | 1495 "make_global_settings needs to be the same for all targets.") |
1498 | 1496 |
1499 spec = target_dicts[qualified_target] | 1497 spec = target_dicts[qualified_target] |
1500 if flavor == 'mac': | 1498 if flavor == 'mac': |
1501 gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec) | 1499 gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec) |
1502 | 1500 |
1503 build_file = gyp.common.RelativePath(build_file, options.toplevel_dir) | 1501 build_file = gyp.common.RelativePath(build_file, options.toplevel_dir) |
1504 | 1502 |
1505 base_path = os.path.dirname(build_file) | 1503 base_path = os.path.dirname(build_file) |
1506 obj = 'obj' | 1504 obj = 'obj' |
1507 if toolset != 'target': | 1505 if toolset != 'target': |
1508 obj += '.' + toolset | 1506 obj += '.' + toolset |
1509 output_file = os.path.join(obj, base_path, name + '.ninja') | 1507 output_file = os.path.join(obj, base_path, name + '.ninja') |
1510 | 1508 |
1511 abs_build_dir = os.path.abspath(toplevel_build) | 1509 abs_build_dir = os.path.abspath(toplevel_build) |
1512 writer = NinjaWriter(target_outputs, base_path, build_dir, | 1510 writer = NinjaWriter(qualified_target, target_outputs, base_path, build_dir, |
1513 OpenOutput(os.path.join(toplevel_build, output_file)), | 1511 OpenOutput(os.path.join(toplevel_build, output_file)), |
1514 flavor, abs_build_dir=abs_build_dir) | 1512 flavor, abs_build_dir=abs_build_dir) |
1515 master_ninja.subninja(output_file) | 1513 master_ninja.subninja(output_file) |
1516 | 1514 |
1517 target = writer.WriteSpec(spec, config_name, generator_flags) | 1515 target = writer.WriteSpec(spec, config_name, generator_flags) |
1518 if target: | 1516 if target: |
1517 if name != target.FinalOutput() and spec['toolset'] == 'target': | |
1518 target_short_names.setdefault(name, []).append(target) | |
1519 target_outputs[qualified_target] = target | 1519 target_outputs[qualified_target] = target |
1520 if qualified_target in all_targets: | 1520 if qualified_target in all_targets: |
1521 all_outputs.add(target.FinalOutput()) | 1521 all_outputs.add(target.FinalOutput()) |
1522 | 1522 |
1523 if target_short_names: | |
1524 # Write a short name to build this target. This benefits both the | |
1525 # "build chrome" case as well as the gyp tests, which expect to be | |
1526 # able to run actions and build libraries by their short name. | |
1527 master_ninja.newline() | |
1528 master_ninja.comment('Short names for targets.') | |
1529 for short_name in target_short_names: | |
1530 master_ninja.build(short_name, 'phony', [x.FinalOutput() for x in | |
1531 target_short_names[short_name]]) | |
1532 | |
1523 if all_outputs: | 1533 if all_outputs: |
1524 master_ninja.newline() | 1534 master_ninja.newline() |
1525 master_ninja.build('all', 'phony', list(all_outputs)) | 1535 master_ninja.build('all', 'phony', list(all_outputs)) |
1526 master_ninja.default('all') | 1536 master_ninja.default('all') |
1527 | 1537 |
1528 | 1538 |
1529 def GenerateOutput(target_list, target_dicts, data, params): | 1539 def GenerateOutput(target_list, target_dicts, data, params): |
1530 if params['options'].generator_output: | 1540 if params['options'].generator_output: |
1531 raise NotImplementedError, "--generator_output not implemented for ninja" | 1541 raise NotImplementedError, "--generator_output not implemented for ninja" |
1532 | 1542 |
1533 user_config = params.get('generator_flags', {}).get('config', None) | 1543 user_config = params.get('generator_flags', {}).get('config', None) |
1534 if user_config: | 1544 if user_config: |
1535 GenerateOutputForConfig(target_list, target_dicts, data, params, | 1545 GenerateOutputForConfig(target_list, target_dicts, data, params, |
1536 user_config) | 1546 user_config) |
1537 else: | 1547 else: |
1538 config_names = target_dicts[target_list[0]]['configurations'].keys() | 1548 config_names = target_dicts[target_list[0]]['configurations'].keys() |
1539 for config_name in config_names: | 1549 for config_name in config_names: |
1540 GenerateOutputForConfig(target_list, target_dicts, data, params, | 1550 GenerateOutputForConfig(target_list, target_dicts, data, params, |
1541 config_name) | 1551 config_name) |
OLD | NEW |