Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(552)

Side by Side Diff: pylib/gyp/generator/ninja.py

Issue 10447063: Fix make and ninja backends to sensibly handle duplicate target names in different directories (Closed) Base URL: http://git.chromium.org/external/gyp.git@master
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pylib/gyp/generator/make.py ('k') | test/intermediate_dir/gyptest-intermediate-dir.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 # All paths as written into the .ninja files are relative to the build 178 # All paths as written into the .ninja files are relative to the build
179 # directory. Call these paths "ninja paths". 179 # directory. Call these paths "ninja paths".
180 # 180 #
181 # We translate between these two notions of paths with two helper 181 # We translate between these two notions of paths with two helper
182 # functions: 182 # functions:
183 # 183 #
184 # - GypPathToNinja translates a gyp path (i.e. relative to the .gyp file) 184 # - GypPathToNinja translates a gyp path (i.e. relative to the .gyp file)
185 # into the equivalent ninja path. 185 # into the equivalent ninja path.
186 # 186 #
187 # - GypPathToUniqueOutput translates a gyp path into a ninja path to write 187 # - GypPathToUniqueOutput translates a gyp path into a ninja path to write
188 # an output file; the result can be namespaced such that is unique 188 # an output file; the result can be namespaced such that it is unique
189 # to the input file name as well as the output target name. 189 # to the input file name as well as the output target name.
190 190
191 class NinjaWriter: 191 class NinjaWriter:
192 def __init__(self, target_outputs, base_dir, build_dir, output_file, flavor, 192 def __init__(self, qualified_target, target_outputs, base_dir, build_dir,
193 abs_build_dir=None): 193 output_file, flavor, abs_build_dir=None):
194 """ 194 """
195 base_dir: path from source root to directory containing this gyp file, 195 base_dir: path from source root to directory containing this gyp file,
196 by gyp semantics, all input paths are relative to this 196 by gyp semantics, all input paths are relative to this
197 build_dir: path from source root to build output 197 build_dir: path from source root to build output
198 abs_build_dir: absolute path to the build directory 198 abs_build_dir: absolute path to the build directory
199 """ 199 """
200 200
201 self.qualified_target = qualified_target
201 self.target_outputs = target_outputs 202 self.target_outputs = target_outputs
202 self.base_dir = base_dir 203 self.base_dir = base_dir
203 self.build_dir = build_dir 204 self.build_dir = build_dir
204 self.ninja = ninja_syntax.Writer(output_file) 205 self.ninja = ninja_syntax.Writer(output_file)
205 self.flavor = flavor 206 self.flavor = flavor
206 self.abs_build_dir = abs_build_dir 207 self.abs_build_dir = abs_build_dir
207 self.obj_ext = '.obj' if flavor == 'win' else '.o' 208 self.obj_ext = '.obj' if flavor == 'win' else '.o'
208 209
209 # Relative path from build output dir to base dir. 210 # Relative path from build output dir to base dir.
210 self.build_to_base = os.path.join(InvertRelativePath(build_dir), base_dir) 211 self.build_to_base = os.path.join(InvertRelativePath(build_dir), base_dir)
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 if self.is_mac_bundle: 398 if self.is_mac_bundle:
398 mac_bundle_depends.append(output) 399 mac_bundle_depends.append(output)
399 400
400 # Bundle all of the above together, if needed. 401 # Bundle all of the above together, if needed.
401 if self.is_mac_bundle: 402 if self.is_mac_bundle:
402 output = self.WriteMacBundle(spec, mac_bundle_depends) 403 output = self.WriteMacBundle(spec, mac_bundle_depends)
403 404
404 if not output: 405 if not output:
405 return None 406 return None
406 407
407 if self.name != output and self.toolset == 'target':
408 # Write a short name to build this target. This benefits both the
409 # "build chrome" case as well as the gyp tests, which expect to be
410 # able to run actions and build libraries by their short name.
411 self.ninja.build(self.name, 'phony', output)
412
413 assert self.target.FinalOutput(), output 408 assert self.target.FinalOutput(), output
414 return self.target 409 return self.target
415 410
416 def _WinIdlRule(self, source, prebuild, outputs): 411 def _WinIdlRule(self, source, prebuild, outputs):
417 """Handle the implicit VS .idl rule for one source file. Fills |outputs| 412 """Handle the implicit VS .idl rule for one source file. Fills |outputs|
418 with files that are generated.""" 413 with files that are generated."""
419 outdir, output, vars, flags = self.msvs_settings.GetIdlBuildData( 414 outdir, output, vars, flags = self.msvs_settings.GetIdlBuildData(
420 source, self.config_name) 415 source, self.config_name)
421 outdir = self.GypPathToNinja(outdir) 416 outdir = self.GypPathToNinja(outdir)
422 def fix_path(path, rel=None): 417 def fix_path(path, rel=None):
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 487
493 def WriteActions(self, actions, extra_sources, prebuild, 488 def WriteActions(self, actions, extra_sources, prebuild,
494 extra_mac_bundle_resources): 489 extra_mac_bundle_resources):
495 # Actions cd into the base directory. 490 # Actions cd into the base directory.
496 env = self.GetXcodeEnv() 491 env = self.GetXcodeEnv()
497 if self.flavor == 'win': 492 if self.flavor == 'win':
498 env = self.msvs_settings.GetVSMacroEnv('$!PRODUCT_DIR') 493 env = self.msvs_settings.GetVSMacroEnv('$!PRODUCT_DIR')
499 all_outputs = [] 494 all_outputs = []
500 for action in actions: 495 for action in actions:
501 # First write out a rule for the action. 496 # First write out a rule for the action.
502 name = re.sub(r'[ {}$]', '_', action['action_name']) 497 name = re.sub(r'[^a-zA-Z0-9_]', '_', '%s_%s' % (self.qualified_target,
Nico 2012/06/04 23:10:20 nit: indent looks weird
Steve Block 2012/06/07 10:17:40 Done.
498 action['action_name']))
503 description = self.GenerateDescription('ACTION', 499 description = self.GenerateDescription('ACTION',
504 action.get('message', None), 500 action.get('message', None),
505 name) 501 name)
506 is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(action) 502 is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(action)
507 if self.flavor == 'win' else False) 503 if self.flavor == 'win' else False)
508 args = action['action'] 504 args = action['action']
509 args = [self.msvs_settings.ConvertVSMacros(arg, self.base_to_build) 505 args = [self.msvs_settings.ConvertVSMacros(arg, self.base_to_build)
510 for arg in args] if self.flavor == 'win' else args 506 for arg in args] if self.flavor == 'win' else args
511 rule_name = self.WriteNewNinjaRule(name, args, description, 507 rule_name = self.WriteNewNinjaRule(name, args, description,
512 is_cygwin, env=env) 508 is_cygwin, env=env)
(...skipping 12 matching lines...) Expand all
525 521
526 self.ninja.newline() 522 self.ninja.newline()
527 523
528 return all_outputs 524 return all_outputs
529 525
530 def WriteRules(self, rules, extra_sources, prebuild, 526 def WriteRules(self, rules, extra_sources, prebuild,
531 extra_mac_bundle_resources): 527 extra_mac_bundle_resources):
532 all_outputs = [] 528 all_outputs = []
533 for rule in rules: 529 for rule in rules:
534 # First write out a rule for the rule action. 530 # First write out a rule for the rule action.
535 name = rule['rule_name'] 531 name = '%s_%s' % (self.qualified_target, rule['rule_name'])
536 args = rule['action'] 532 args = rule['action']
537 description = self.GenerateDescription( 533 description = self.GenerateDescription(
538 'RULE', 534 'RULE',
539 rule.get('message', None), 535 rule.get('message', None),
540 ('%s ' + generator_default_variables['RULE_INPUT_PATH']) % name) 536 ('%s ' + generator_default_variables['RULE_INPUT_PATH']) % name)
541 is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(rule) 537 is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(rule)
542 if self.flavor == 'win' else False) 538 if self.flavor == 'win' else False)
543 args = [self.msvs_settings.ConvertVSMacros(arg, self.base_to_build) 539 args = [self.msvs_settings.ConvertVSMacros(arg, self.base_to_build)
544 for arg in args] if self.flavor == 'win' else args 540 for arg in args] if self.flavor == 'win' else args
545 rule_name = self.WriteNewNinjaRule(name, args, description, is_cygwin) 541 rule_name = self.WriteNewNinjaRule(name, args, description, is_cygwin)
(...skipping 897 matching lines...) Expand 10 before | Expand all | Expand 10 after
1443 all_targets = set() 1439 all_targets = set()
1444 for build_file in params['build_files']: 1440 for build_file in params['build_files']:
1445 for target in gyp.common.AllTargets(target_list, 1441 for target in gyp.common.AllTargets(target_list,
1446 target_dicts, 1442 target_dicts,
1447 os.path.normpath(build_file)): 1443 os.path.normpath(build_file)):
1448 all_targets.add(target) 1444 all_targets.add(target)
1449 all_outputs = set() 1445 all_outputs = set()
1450 1446
1451 # target_outputs is a map from qualified target name to a Target object. 1447 # target_outputs is a map from qualified target name to a Target object.
1452 target_outputs = {} 1448 target_outputs = {}
1449 # target_short_names is a map from target short name to a list of Target
1450 # objects.
1451 target_short_names = {}
1453 for qualified_target in target_list: 1452 for qualified_target in target_list:
1454 # qualified_target is like: third_party/icu/icu.gyp:icui18n#target 1453 # qualified_target is like: third_party/icu/icu.gyp:icui18n#target
1455 build_file, name, toolset = \ 1454 build_file, name, toolset = \
1456 gyp.common.ParseQualifiedTarget(qualified_target) 1455 gyp.common.ParseQualifiedTarget(qualified_target)
1457 1456
1458 this_make_global_settings = data[build_file].get('make_global_settings', []) 1457 this_make_global_settings = data[build_file].get('make_global_settings', [])
1459 assert make_global_settings == this_make_global_settings, ( 1458 assert make_global_settings == this_make_global_settings, (
1460 "make_global_settings needs to be the same for all targets.") 1459 "make_global_settings needs to be the same for all targets.")
1461 1460
1462 spec = target_dicts[qualified_target] 1461 spec = target_dicts[qualified_target]
1463 if flavor == 'mac': 1462 if flavor == 'mac':
1464 gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec) 1463 gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec)
1465 1464
1466 build_file = gyp.common.RelativePath(build_file, options.toplevel_dir) 1465 build_file = gyp.common.RelativePath(build_file, options.toplevel_dir)
1467 1466
1468 base_path = os.path.dirname(build_file) 1467 base_path = os.path.dirname(build_file)
1469 obj = 'obj' 1468 obj = 'obj'
1470 if toolset != 'target': 1469 if toolset != 'target':
1471 obj += '.' + toolset 1470 obj += '.' + toolset
1472 output_file = os.path.join(obj, base_path, name + '.ninja') 1471 output_file = os.path.join(obj, base_path, name + '.ninja')
1473 1472
1474 abs_build_dir = os.path.abspath(toplevel_build) 1473 abs_build_dir = os.path.abspath(toplevel_build)
1475 writer = NinjaWriter(target_outputs, base_path, build_dir, 1474 writer = NinjaWriter(qualified_target, target_outputs, base_path, build_dir,
1476 OpenOutput(os.path.join(toplevel_build, output_file)), 1475 OpenOutput(os.path.join(toplevel_build, output_file)),
1477 flavor, abs_build_dir=abs_build_dir) 1476 flavor, abs_build_dir=abs_build_dir)
1478 master_ninja.subninja(output_file) 1477 master_ninja.subninja(output_file)
1479 1478
1480 target = writer.WriteSpec(spec, config_name, generator_flags) 1479 target = writer.WriteSpec(spec, config_name, generator_flags)
1481 if target: 1480 if target:
1481 if name != target.FinalOutput() and spec['toolset'] == 'target':
1482 target_short_names.setdefault(name, []).append(target)
1482 target_outputs[qualified_target] = target 1483 target_outputs[qualified_target] = target
1483 if qualified_target in all_targets: 1484 if qualified_target in all_targets:
1484 all_outputs.add(target.FinalOutput()) 1485 all_outputs.add(target.FinalOutput())
1485 1486
1487 if target_short_names:
1488 # Write a short name to build this target. This benefits both the
1489 # "build chrome" case as well as the gyp tests, which expect to be
1490 # able to run actions and build libraries by their short name.
1491 master_ninja.newline()
1492 master_ninja.comment('Short names for targets.')
1493 for short_name in target_short_names:
1494 master_ninja.build(short_name, 'phony', [x.FinalOutput() for x in
1495 target_short_names[short_name]])
1496
1486 if all_outputs: 1497 if all_outputs:
1487 master_ninja.newline() 1498 master_ninja.newline()
1488 master_ninja.build('all', 'phony', list(all_outputs)) 1499 master_ninja.build('all', 'phony', list(all_outputs))
1489 master_ninja.default('all') 1500 master_ninja.default('all')
1490 1501
1491 1502
1492 def GenerateOutput(target_list, target_dicts, data, params): 1503 def GenerateOutput(target_list, target_dicts, data, params):
1493 if params['options'].generator_output: 1504 if params['options'].generator_output:
1494 raise NotImplementedError, "--generator_output not implemented for ninja" 1505 raise NotImplementedError, "--generator_output not implemented for ninja"
1495 1506
1496 user_config = params.get('generator_flags', {}).get('config', None) 1507 user_config = params.get('generator_flags', {}).get('config', None)
1497 if user_config: 1508 if user_config:
1498 GenerateOutputForConfig(target_list, target_dicts, data, params, 1509 GenerateOutputForConfig(target_list, target_dicts, data, params,
1499 user_config) 1510 user_config)
1500 else: 1511 else:
1501 config_names = target_dicts[target_list[0]]['configurations'].keys() 1512 config_names = target_dicts[target_list[0]]['configurations'].keys()
1502 for config_name in config_names: 1513 for config_name in config_names:
1503 GenerateOutputForConfig(target_list, target_dicts, data, params, 1514 GenerateOutputForConfig(target_list, target_dicts, data, params,
1504 config_name) 1515 config_name)
OLDNEW
« no previous file with comments | « pylib/gyp/generator/make.py ('k') | test/intermediate_dir/gyptest-intermediate-dir.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698