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

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

Issue 1506733002: GYP: Make GYP build deterministic (Closed) Base URL: https://chromium.googlesource.com/external/gyp.git@master
Patch Set: Windows-Fixes Created 5 years 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
OLDNEW
1 # Copyright (c) 2013 Google Inc. All rights reserved. 1 # Copyright (c) 2013 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 collections 5 import collections
6 import copy 6 import copy
7 import hashlib 7 import hashlib
8 import json 8 import json
9 import multiprocessing 9 import multiprocessing
10 import os.path 10 import os.path
11 import re 11 import re
12 import signal 12 import signal
13 import subprocess 13 import subprocess
14 import sys 14 import sys
15 import gyp 15 import gyp
16 import gyp.common 16 import gyp.common
17 from gyp.common import OrderedSet 17 from gyp.common import OrderedSet
18
Nico 2016/01/13 20:16:54 why this newline?
Zachary Forman 2016/01/18 20:44:36 Fixed
18 import gyp.msvs_emulation 19 import gyp.msvs_emulation
19 import gyp.MSVSUtil as MSVSUtil 20 import gyp.MSVSUtil as MSVSUtil
20 import gyp.xcode_emulation 21 import gyp.xcode_emulation
21 from cStringIO import StringIO 22 from cStringIO import StringIO
22 23
23 from gyp.common import GetEnvironFallback 24 from gyp.common import GetEnvironFallback
24 import gyp.ninja_syntax as ninja_syntax 25 import gyp.ninja_syntax as ninja_syntax
25 26
26 generator_default_variables = { 27 generator_default_variables = {
27 'EXECUTABLE_PREFIX': '', 28 'EXECUTABLE_PREFIX': '',
(...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after
649 650
650 # Rules can potentially make use of some special variables which 651 # Rules can potentially make use of some special variables which
651 # must vary per source file. 652 # must vary per source file.
652 # Compute the list of variables we'll need to provide. 653 # Compute the list of variables we'll need to provide.
653 special_locals = ('source', 'root', 'dirname', 'ext', 'name') 654 special_locals = ('source', 'root', 'dirname', 'ext', 'name')
654 needed_variables = set(['source']) 655 needed_variables = set(['source'])
655 for argument in args: 656 for argument in args:
656 for var in special_locals: 657 for var in special_locals:
657 if '${%s}' % var in argument: 658 if '${%s}' % var in argument:
658 needed_variables.add(var) 659 needed_variables.add(var)
660 needed_variables = sorted(needed_variables)
659 661
660 def cygwin_munge(path): 662 def cygwin_munge(path):
661 # pylint: disable=cell-var-from-loop 663 # pylint: disable=cell-var-from-loop
662 if is_cygwin: 664 if is_cygwin:
663 return path.replace('\\', '/') 665 return path.replace('\\', '/')
664 return path 666 return path
665 667
666 inputs = [self.GypPathToNinja(i, env) for i in rule.get('inputs', [])] 668 inputs = [self.GypPathToNinja(i, env) for i in rule.get('inputs', [])]
667 669
668 # If there are n source files matching the rule, and m additional rule 670 # If there are n source files matching the rule, and m additional rule
(...skipping 11 matching lines...) Expand all
680 # For each source file, write an edge that generates all the outputs. 682 # For each source file, write an edge that generates all the outputs.
681 for source in sources: 683 for source in sources:
682 source = os.path.normpath(source) 684 source = os.path.normpath(source)
683 dirname, basename = os.path.split(source) 685 dirname, basename = os.path.split(source)
684 root, ext = os.path.splitext(basename) 686 root, ext = os.path.splitext(basename)
685 687
686 # Gather the list of inputs and outputs, expanding $vars if possible. 688 # Gather the list of inputs and outputs, expanding $vars if possible.
687 outputs = [self.ExpandRuleVariables(o, root, dirname, 689 outputs = [self.ExpandRuleVariables(o, root, dirname,
688 source, ext, basename) 690 source, ext, basename)
689 for o in rule['outputs']] 691 for o in rule['outputs']]
690
Nico 2016/01/13 20:16:54 what was wrong with the 3 newlines here?
Zachary Forman 2016/01/18 20:44:36 Reverted
691 if int(rule.get('process_outputs_as_sources', False)): 692 if int(rule.get('process_outputs_as_sources', False)):
692 extra_sources += outputs 693 extra_sources += outputs
693
694 was_mac_bundle_resource = source in mac_bundle_resources 694 was_mac_bundle_resource = source in mac_bundle_resources
695 if was_mac_bundle_resource or \ 695 if was_mac_bundle_resource or \
696 int(rule.get('process_outputs_as_mac_bundle_resources', False)): 696 int(rule.get('process_outputs_as_mac_bundle_resources', False)):
697 extra_mac_bundle_resources += outputs 697 extra_mac_bundle_resources += outputs
698 # Note: This is n_resources * n_outputs_in_rule. Put to-be-removed 698 # Note: This is n_resources * n_outputs_in_rule. Put to-be-removed
699 # items in a set and remove them all in a single pass if this becomes 699 # items in a set and remove them all in a single pass if this becomes
700 # a performance issue. 700 # a performance issue.
701 if was_mac_bundle_resource: 701 if was_mac_bundle_resource:
702 mac_bundle_resources.remove(source) 702 mac_bundle_resources.remove(source)
703
704 extra_bindings = [] 703 extra_bindings = []
705 for var in needed_variables: 704 for var in needed_variables:
706 if var == 'root': 705 if var == 'root':
707 extra_bindings.append(('root', cygwin_munge(root))) 706 extra_bindings.append(('root', cygwin_munge(root)))
708 elif var == 'dirname': 707 elif var == 'dirname':
709 # '$dirname' is a parameter to the rule action, which means 708 # '$dirname' is a parameter to the rule action, which means
710 # it shouldn't be converted to a Ninja path. But we don't 709 # it shouldn't be converted to a Ninja path. But we don't
711 # want $!PRODUCT_DIR in there either. 710 # want $!PRODUCT_DIR in there either.
712 dirname_expanded = self.ExpandSpecial(dirname, self.base_to_build) 711 dirname_expanded = self.ExpandSpecial(dirname, self.base_to_build)
713 extra_bindings.append(('dirname', cygwin_munge(dirname_expanded))) 712 extra_bindings.append(('dirname', cygwin_munge(dirname_expanded)))
714 elif var == 'source': 713 elif var == 'source':
715 # '$source' is a parameter to the rule action, which means 714 # '$source' is a parameter to the rule action, which means
716 # it shouldn't be converted to a Ninja path. But we don't 715 # it shouldn't be converted to a Ninja path. But we don't
717 # want $!PRODUCT_DIR in there either. 716 # want $!PRODUCT_DIR in there either.
718 source_expanded = self.ExpandSpecial(source, self.base_to_build) 717 source_expanded = self.ExpandSpecial(source, self.base_to_build)
719 extra_bindings.append(('source', cygwin_munge(source_expanded))) 718 extra_bindings.append(('source', cygwin_munge(source_expanded)))
720 elif var == 'ext': 719 elif var == 'ext':
721 extra_bindings.append(('ext', ext)) 720 extra_bindings.append(('ext', ext))
722 elif var == 'name': 721 elif var == 'name':
723 extra_bindings.append(('name', cygwin_munge(basename))) 722 extra_bindings.append(('name', cygwin_munge(basename)))
724 else: 723 else:
725 assert var == None, repr(var) 724 assert var == None, repr(var)
726 725
727 outputs = [self.GypPathToNinja(o, env) for o in outputs] 726 outputs = [self.GypPathToNinja(o, env) for o in outputs]
728 if self.flavor == 'win': 727 if self.flavor == 'win':
729 # WriteNewNinjaRule uses unique_name for creating an rsp file on win. 728 # WriteNewNinjaRule uses unique_name for creating an rsp file on win.
730 extra_bindings.append(('unique_name', 729 extra_bindings.append(('unique_name',
731 hashlib.md5(outputs[0]).hexdigest())) 730 hashlib.md5(outputs[0]).hexdigest()))
731
732 self.ninja.build(outputs, rule_name, self.GypPathToNinja(source), 732 self.ninja.build(outputs, rule_name, self.GypPathToNinja(source),
733 implicit=inputs, 733 implicit=inputs,
734 order_only=prebuild, 734 order_only=prebuild,
735 variables=extra_bindings) 735 variables=extra_bindings)
736 736
737 all_outputs.extend(outputs) 737 all_outputs.extend(outputs)
738 738
739 return all_outputs 739 return all_outputs
740 740
741 def WriteCopies(self, copies, prebuild, mac_bundle_depends): 741 def WriteCopies(self, copies, prebuild, mac_bundle_depends):
(...skipping 503 matching lines...) Expand 10 before | Expand all | Expand 10 after
1245 command = command + '_notoc' 1245 command = command + '_notoc'
1246 elif self.flavor == 'win': 1246 elif self.flavor == 'win':
1247 extra_bindings.append(('binary', output)) 1247 extra_bindings.append(('binary', output))
1248 pdbname = self.msvs_settings.GetPDBName( 1248 pdbname = self.msvs_settings.GetPDBName(
1249 config_name, self.ExpandSpecial, output + '.pdb') 1249 config_name, self.ExpandSpecial, output + '.pdb')
1250 if pdbname: 1250 if pdbname:
1251 output = [output, pdbname] 1251 output = [output, pdbname]
1252 1252
1253 1253
1254 if len(solibs): 1254 if len(solibs):
1255 extra_bindings.append(('solibs', gyp.common.EncodePOSIXShellList(solibs))) 1255 extra_bindings.append(('solibs',
1256 gyp.common.EncodePOSIXShellList(sorted(solibs))))
1256 1257
1257 ninja_file.build(output, command + command_suffix, link_deps, 1258 ninja_file.build(output, command + command_suffix, link_deps,
1258 implicit=list(implicit_deps), 1259 implicit=sorted(implicit_deps),
1259 order_only=list(order_deps), 1260 order_only=list(order_deps),
1260 variables=extra_bindings) 1261 variables=extra_bindings)
1261 return linked_binary 1262 return linked_binary
1262 1263
1263 def WriteTarget(self, spec, config_name, config, link_deps, compile_deps): 1264 def WriteTarget(self, spec, config_name, config, link_deps, compile_deps):
1264 extra_link_deps = any(self.target_outputs.get(dep).Linkable() 1265 extra_link_deps = any(self.target_outputs.get(dep).Linkable()
1265 for dep in spec.get('dependencies', []) 1266 for dep in spec.get('dependencies', [])
1266 if dep in self.target_outputs) 1267 if dep in self.target_outputs)
1267 if spec['type'] == 'none' or (not link_deps and not extra_link_deps): 1268 if spec['type'] == 'none' or (not link_deps and not extra_link_deps):
1268 # TODO(evan): don't call this function for 'none' target types, as 1269 # TODO(evan): don't call this function for 'none' target types, as
(...skipping 625 matching lines...) Expand 10 before | Expand all | Expand 10 after
1894 if flavor == 'win': 1895 if flavor == 'win':
1895 configs = [target_dicts[qualified_target]['configurations'][config_name] 1896 configs = [target_dicts[qualified_target]['configurations'][config_name]
1896 for qualified_target in target_list] 1897 for qualified_target in target_list]
1897 shared_system_includes = None 1898 shared_system_includes = None
1898 if not generator_flags.get('ninja_use_custom_environment_files', 0): 1899 if not generator_flags.get('ninja_use_custom_environment_files', 0):
1899 shared_system_includes = \ 1900 shared_system_includes = \
1900 gyp.msvs_emulation.ExtractSharedMSVSSystemIncludes( 1901 gyp.msvs_emulation.ExtractSharedMSVSSystemIncludes(
1901 configs, generator_flags) 1902 configs, generator_flags)
1902 cl_paths = gyp.msvs_emulation.GenerateEnvironmentFiles( 1903 cl_paths = gyp.msvs_emulation.GenerateEnvironmentFiles(
1903 toplevel_build, generator_flags, shared_system_includes, OpenOutput) 1904 toplevel_build, generator_flags, shared_system_includes, OpenOutput)
1904 for arch, path in cl_paths.iteritems(): 1905 for arch, path in sorted(cl_paths.iteritems()):
1905 if clang_cl: 1906 if clang_cl:
1906 # If we have selected clang-cl, use that instead. 1907 # If we have selected clang-cl, use that instead.
1907 path = clang_cl 1908 path = clang_cl
1908 command = CommandWithWrapper('CC', wrappers, 1909 command = CommandWithWrapper('CC', wrappers,
1909 QuoteShellArgument(path, 'win')) 1910 QuoteShellArgument(path, 'win'))
1910 if clang_cl: 1911 if clang_cl:
1911 # Use clang-cl to cross-compile for x86 or x86_64. 1912 # Use clang-cl to cross-compile for x86 or x86_64.
1912 command += (' -m32' if arch == 'x86' else ' -m64') 1913 command += (' -m32' if arch == 'x86' else ' -m64')
1913 master_ninja.variable('cl_' + arch, command) 1914 master_ninja.variable('cl_' + arch, command)
1914 1915
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after
2330 non_empty_target_names.add(name) 2331 non_empty_target_names.add(name)
2331 else: 2332 else:
2332 empty_target_names.add(name) 2333 empty_target_names.add(name)
2333 2334
2334 if target_short_names: 2335 if target_short_names:
2335 # Write a short name to build this target. This benefits both the 2336 # Write a short name to build this target. This benefits both the
2336 # "build chrome" case as well as the gyp tests, which expect to be 2337 # "build chrome" case as well as the gyp tests, which expect to be
2337 # able to run actions and build libraries by their short name. 2338 # able to run actions and build libraries by their short name.
2338 master_ninja.newline() 2339 master_ninja.newline()
2339 master_ninja.comment('Short names for targets.') 2340 master_ninja.comment('Short names for targets.')
2340 for short_name in target_short_names: 2341 for short_name in sorted(target_short_names):
2341 master_ninja.build(short_name, 'phony', [x.FinalOutput() for x in 2342 master_ninja.build(short_name, 'phony', ([x.FinalOutput() for x in
Nico 2016/01/13 20:16:54 why the additional parens?
Zachary Forman 2016/01/18 20:44:36 Corrected.
2342 target_short_names[short_name]]) 2343 target_short_names[short_name]]))
2343 2344
2344 # Write phony targets for any empty targets that weren't written yet. As 2345 # Write phony targets for any empty targets that weren't written yet. As
2345 # short names are not necessarily unique only do this for short names that 2346 # short names are not necessarily unique only do this for short names that
2346 # haven't already been output for another target. 2347 # haven't already been output for another target.
2347 empty_target_names = empty_target_names - non_empty_target_names 2348 empty_target_names = empty_target_names - non_empty_target_names
2348 if empty_target_names: 2349 if empty_target_names:
2349 master_ninja.newline() 2350 master_ninja.newline()
2350 master_ninja.comment('Empty targets (output for completeness).') 2351 master_ninja.comment('Empty targets (output for completeness).')
2351 for name in sorted(empty_target_names): 2352 for name in sorted(empty_target_names):
2352 master_ninja.build(name, 'phony') 2353 master_ninja.build(name, 'phony')
2353 2354
2354 if all_outputs: 2355 if all_outputs:
2355 master_ninja.newline() 2356 master_ninja.newline()
2356 master_ninja.build('all', 'phony', list(all_outputs)) 2357 master_ninja.build('all', 'phony', sorted(all_outputs))
2357 master_ninja.default(generator_flags.get('default_target', 'all')) 2358 master_ninja.default(generator_flags.get('default_target', 'all'))
2358 2359
2359 master_ninja_file.close() 2360 master_ninja_file.close()
2360 2361
2361 2362
2362 def PerformBuild(data, configurations, params): 2363 def PerformBuild(data, configurations, params):
2363 options = params['options'] 2364 options = params['options']
2364 for config in configurations: 2365 for config in configurations:
2365 builddir = os.path.join(options.toplevel_dir, 'out', config) 2366 builddir = os.path.join(options.toplevel_dir, 'out', config)
2366 arguments = ['ninja', '-C', builddir] 2367 arguments = ['ninja', '-C', builddir]
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2401 arglists.append( 2402 arglists.append(
2402 (target_list, target_dicts, data, params, config_name)) 2403 (target_list, target_dicts, data, params, config_name))
2403 pool.map(CallGenerateOutputForConfig, arglists) 2404 pool.map(CallGenerateOutputForConfig, arglists)
2404 except KeyboardInterrupt, e: 2405 except KeyboardInterrupt, e:
2405 pool.terminate() 2406 pool.terminate()
2406 raise e 2407 raise e
2407 else: 2408 else:
2408 for config_name in config_names: 2409 for config_name in config_names:
2409 GenerateOutputForConfig(target_list, target_dicts, data, params, 2410 GenerateOutputForConfig(target_list, target_dicts, data, params,
2410 config_name) 2411 config_name)
OLDNEW
« no previous file with comments | « pylib/gyp/MSVSUtil.py ('k') | pylib/gyp/input.py » ('j') | pylib/gyp/input.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698