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

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

Issue 1066963002: Improve generated Makefile rules for rules with 2 outputs. (Closed) Base URL: https://chromium.googlesource.com/external/gyp.git@master
Patch Set: no changes Created 5 years, 8 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 | « no previous file | test/actions-multiple-outputs/gyptest-multiple-outputs.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) 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 # Notes: 5 # Notes:
6 # 6 #
7 # This is all roughly based on the Makefile system used by the Linux 7 # This is all roughly based on the Makefile system used by the Linux
8 # kernel, but is a non-recursive make -- we put the entire dependency 8 # kernel, but is a non-recursive make -- we put the entire dependency
9 # graph in front of make and let it figure it out. 9 # graph in front of make and let it figure it out.
10 # 10 #
(...skipping 1001 matching lines...) Expand 10 before | Expand all | Expand 10 after
1012 outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs] 1012 outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs]
1013 inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs] 1013 inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs]
1014 1014
1015 outputs = map(self.Absolutify, outputs) 1015 outputs = map(self.Absolutify, outputs)
1016 all_outputs += outputs 1016 all_outputs += outputs
1017 # Only write the 'obj' and 'builddir' rules for the "primary" output 1017 # Only write the 'obj' and 'builddir' rules for the "primary" output
1018 # (:1); it's superfluous for the "extra outputs", and this avoids 1018 # (:1); it's superfluous for the "extra outputs", and this avoids
1019 # accidentally writing duplicate dummy rules for those outputs. 1019 # accidentally writing duplicate dummy rules for those outputs.
1020 self.WriteLn('%s: obj := $(abs_obj)' % outputs[0]) 1020 self.WriteLn('%s: obj := $(abs_obj)' % outputs[0])
1021 self.WriteLn('%s: builddir := $(abs_builddir)' % outputs[0]) 1021 self.WriteLn('%s: builddir := $(abs_builddir)' % outputs[0])
1022 self.WriteMakeRule(outputs, inputs + ['FORCE_DO_CMD'], actions) 1022 self.WriteMakeRule(outputs, inputs, actions,
1023 command="%s_%d" % (name, count))
1023 # Spaces in rule filenames are not supported, but rule variables have 1024 # Spaces in rule filenames are not supported, but rule variables have
1024 # spaces in them (e.g. RULE_INPUT_PATH expands to '$(abspath $<)'). 1025 # spaces in them (e.g. RULE_INPUT_PATH expands to '$(abspath $<)').
1025 # The spaces within the variables are valid, so remove the variables 1026 # The spaces within the variables are valid, so remove the variables
1026 # before checking. 1027 # before checking.
1027 variables_with_spaces = re.compile(r'\$\([^ ]* \$<\)') 1028 variables_with_spaces = re.compile(r'\$\([^ ]* \$<\)')
1028 for output in outputs: 1029 for output in outputs:
1029 output = re.sub(variables_with_spaces, '', output) 1030 output = re.sub(variables_with_spaces, '', output)
1030 assert ' ' not in output, ( 1031 assert ' ' not in output, (
1031 "Spaces in rule filenames not yet supported (%s)" % output) 1032 "Spaces in rule filenames not yet supported (%s)" % output)
1032 self.WriteLn('all_deps += %s' % ' '.join(outputs)) 1033 self.WriteLn('all_deps += %s' % ' '.join(outputs))
(...skipping 648 matching lines...) Expand 10 before | Expand all | Expand 10 after
1681 This makes the outputs dependent on the command line that was run, 1682 This makes the outputs dependent on the command line that was run,
1682 as well as support the V= make command line flag. 1683 as well as support the V= make command line flag.
1683 """ 1684 """
1684 suffix = '' 1685 suffix = ''
1685 if postbuilds: 1686 if postbuilds:
1686 assert ',' not in command 1687 assert ',' not in command
1687 suffix = ',,1' # Tell do_cmd to honor $POSTBUILDS 1688 suffix = ',,1' # Tell do_cmd to honor $POSTBUILDS
1688 self.WriteMakeRule(outputs, inputs, 1689 self.WriteMakeRule(outputs, inputs,
1689 actions = ['$(call do_cmd,%s%s)' % (command, suffix)], 1690 actions = ['$(call do_cmd,%s%s)' % (command, suffix)],
1690 comment = comment, 1691 comment = comment,
1692 command = command,
1691 force = True) 1693 force = True)
1692 # Add our outputs to the list of targets we read depfiles from. 1694 # Add our outputs to the list of targets we read depfiles from.
1693 # all_deps is only used for deps file reading, and for deps files we replace 1695 # all_deps is only used for deps file reading, and for deps files we replace
1694 # spaces with ? because escaping doesn't work with make's $(sort) and 1696 # spaces with ? because escaping doesn't work with make's $(sort) and
1695 # other functions. 1697 # other functions.
1696 outputs = [QuoteSpaces(o, SPACE_REPLACEMENT) for o in outputs] 1698 outputs = [QuoteSpaces(o, SPACE_REPLACEMENT) for o in outputs]
1697 self.WriteLn('all_deps += %s' % ' '.join(outputs)) 1699 self.WriteLn('all_deps += %s' % ' '.join(outputs))
1698 1700
1699 1701
1700 def WriteMakeRule(self, outputs, inputs, actions=None, comment=None, 1702 def WriteMakeRule(self, outputs, inputs, actions=None, comment=None,
1701 order_only=False, force=False, phony=False): 1703 order_only=False, force=False, phony=False, command=None):
1702 """Write a Makefile rule, with some extra tricks. 1704 """Write a Makefile rule, with some extra tricks.
1703 1705
1704 outputs: a list of outputs for the rule (note: this is not directly 1706 outputs: a list of outputs for the rule (note: this is not directly
1705 supported by make; see comments below) 1707 supported by make; see comments below)
1706 inputs: a list of inputs for the rule 1708 inputs: a list of inputs for the rule
1707 actions: a list of shell commands to run for the rule 1709 actions: a list of shell commands to run for the rule
1708 comment: a comment to put in the Makefile above the rule (also useful 1710 comment: a comment to put in the Makefile above the rule (also useful
1709 for making this Python script's code self-documenting) 1711 for making this Python script's code self-documenting)
1710 order_only: if true, makes the dependency order-only 1712 order_only: if true, makes the dependency order-only
1711 force: if true, include FORCE_DO_CMD as an order-only dep 1713 force: if true, include FORCE_DO_CMD as an order-only dep
1712 phony: if true, the rule does not actually generate the named output, the 1714 phony: if true, the rule does not actually generate the named output, the
1713 output is just a name to run the rule 1715 output is just a name to run the rule
1716 command: (optional) command name to generate unambiguous labels
1714 """ 1717 """
1715 outputs = map(QuoteSpaces, outputs) 1718 outputs = map(QuoteSpaces, outputs)
1716 inputs = map(QuoteSpaces, inputs) 1719 inputs = map(QuoteSpaces, inputs)
1717 1720
1718 if comment: 1721 if comment:
1719 self.WriteLn('# ' + comment) 1722 self.WriteLn('# ' + comment)
1720 if phony: 1723 if phony:
1721 self.WriteLn('.PHONY: ' + ' '.join(outputs)) 1724 self.WriteLn('.PHONY: ' + ' '.join(outputs))
1722 # TODO(evanm): just make order_only a list of deps instead of these hacks.
1723 if order_only:
1724 order_insert = '| '
1725 pick_output = ' '.join(outputs)
1726 else:
1727 order_insert = ''
1728 pick_output = outputs[0]
1729 if force:
1730 force_append = ' FORCE_DO_CMD'
1731 else:
1732 force_append = ''
1733 if actions: 1725 if actions:
1734 self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0]) 1726 self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0])
1735 self.WriteLn('%s: %s%s%s' % (pick_output, order_insert, ' '.join(inputs), 1727 force_append = ' FORCE_DO_CMD' if force else ''
1736 force_append)) 1728
1729 if order_only:
1730 # Order only rule: Just write a simple rule.
1731 # TODO(evanm): just make order_only a list of deps instead of this hack.
1732 self.WriteLn('%s: | %s%s' %
1733 (' '.join(outputs), ' '.join(inputs), force_append))
1734 elif len(outputs) == 1:
1735 # Regular rule, one output: Just write a simple rule.
1736 self.WriteLn('%s: %s%s' % (outputs[0], ' '.join(inputs), force_append))
1737 else:
1738 # Regular rule, more than one output: Multiple outputs are tricky in
1739 # make. We will write three rules:
1740 # - All outputs depend on an intermediate file.
1741 # - Make .INTERMEDIATE depend on the intermediate.
1742 # - The intermediate file depends on the inputs and executes the
1743 # actual command.
1744 #
1745 # For an explanation of the problem and several solutions that don't
1746 # work, see this:
1747 # http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html
1748 intermediate = "%s.intermediate" % (command if command else self.target)
1749 self.WriteLn('%s: %s' % (' '.join(outputs), intermediate))
1750 self.WriteLn('%s: %s' % ('.INTERMEDIATE', intermediate))
1751 self.WriteLn('%s: %s%s' %
1752 (intermediate, ' '.join(inputs), force_append))
1753
1737 if actions: 1754 if actions:
1738 for action in actions: 1755 for action in actions:
1739 self.WriteLn('\t%s' % action) 1756 self.WriteLn('\t%s' % action)
1740 if not order_only and len(outputs) > 1:
1741 # If we have more than one output, a rule like
1742 # foo bar: baz
1743 # that for *each* output we must run the action, potentially
1744 # in parallel. That is not what we're trying to write -- what
1745 # we want is that we run the action once and it generates all
1746 # the files.
1747 # http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html
1748 # discusses this problem and has this solution:
1749 # 1) Write the naive rule that would produce parallel runs of
1750 # the action.
1751 # 2) Make the outputs seralized on each other, so we won't start
1752 # a parallel run until the first run finishes, at which point
1753 # we'll have generated all the outputs and we're done.
1754 self.WriteLn('%s: %s' % (' '.join(outputs[1:]), outputs[0]))
1755 # Add a dummy command to the "extra outputs" rule, otherwise make seems to
1756 # think these outputs haven't (couldn't have?) changed, and thus doesn't
1757 # flag them as changed (i.e. include in '$?') when evaluating dependent
1758 # rules, which in turn causes do_cmd() to skip running dependent commands.
1759 self.WriteLn('%s: ;' % (' '.join(outputs[1:])))
1760 self.WriteLn() 1757 self.WriteLn()
1761 1758
1762 1759
1763 def WriteAndroidNdkModuleRule(self, module_name, all_sources, link_deps): 1760 def WriteAndroidNdkModuleRule(self, module_name, all_sources, link_deps):
1764 """Write a set of LOCAL_XXX definitions for Android NDK. 1761 """Write a set of LOCAL_XXX definitions for Android NDK.
1765 1762
1766 These variable definitions will be used by Android NDK but do nothing for 1763 These variable definitions will be used by Android NDK but do nothing for
1767 non-Android applications. 1764 non-Android applications.
1768 1765
1769 Arguments: 1766 Arguments:
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after
2203 root_makefile.write("endif\n") 2200 root_makefile.write("endif\n")
2204 root_makefile.write('\n') 2201 root_makefile.write('\n')
2205 2202
2206 if (not generator_flags.get('standalone') 2203 if (not generator_flags.get('standalone')
2207 and generator_flags.get('auto_regeneration', True)): 2204 and generator_flags.get('auto_regeneration', True)):
2208 WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files) 2205 WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
2209 2206
2210 root_makefile.write(SHARED_FOOTER) 2207 root_makefile.write(SHARED_FOOTER)
2211 2208
2212 root_makefile.close() 2209 root_makefile.close()
OLDNEW
« no previous file with comments | « no previous file | test/actions-multiple-outputs/gyptest-multiple-outputs.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698