OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 '''The 'grit build' tool along with integration for this tool with the | 6 '''The 'grit build' tool along with integration for this tool with the |
7 SCons build system. | 7 SCons build system. |
8 ''' | 8 ''' |
9 | 9 |
10 import filecmp | 10 import filecmp |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 -h HEADERFORMAT Custom format string to use for generating rc header files. | 102 -h HEADERFORMAT Custom format string to use for generating rc header files. |
103 The string should have two placeholders: {textual_id} | 103 The string should have two placeholders: {textual_id} |
104 and {numeric_id}. E.g. "#define {textual_id} {numeric_id}" | 104 and {numeric_id}. E.g. "#define {textual_id} {numeric_id}" |
105 Otherwise it will use the default "#define SYMBOL 1234" | 105 Otherwise it will use the default "#define SYMBOL 1234" |
106 | 106 |
107 --output-all-resource-defines | 107 --output-all-resource-defines |
108 --no-output-all-resource-defines If specified, overrides the value of the | 108 --no-output-all-resource-defines If specified, overrides the value of the |
109 output_all_resource_defines attribute of the root <grit> | 109 output_all_resource_defines attribute of the root <grit> |
110 element of the input .grd file. | 110 element of the input .grd file. |
111 | 111 |
| 112 --write-only-new flag |
| 113 If flag is non-0, write output files to a temporary file |
| 114 first, and copy it to the real output only if the new file |
| 115 is different from the old file. This allows some build |
| 116 systems to realize that dependent build steps might be |
| 117 unnecessary, at the cost of comparing the output data at |
| 118 grit time. |
| 119 |
| 120 |
112 Conditional inclusion of resources only affects the output of files which | 121 Conditional inclusion of resources only affects the output of files which |
113 control which resources get linked into a binary, e.g. it affects .rc files | 122 control which resources get linked into a binary, e.g. it affects .rc files |
114 meant for compilation but it does not affect resource header files (that define | 123 meant for compilation but it does not affect resource header files (that define |
115 IDs). This helps ensure that values of IDs stay the same, that all messages | 124 IDs). This helps ensure that values of IDs stay the same, that all messages |
116 are exported to translation interchange files (e.g. XMB files), etc. | 125 are exported to translation interchange files (e.g. XMB files), etc. |
117 ''' | 126 ''' |
118 | 127 |
119 def ShortDescription(self): | 128 def ShortDescription(self): |
120 return 'A tool that builds RC files for compilation.' | 129 return 'A tool that builds RC files for compilation.' |
121 | 130 |
122 def Run(self, opts, args): | 131 def Run(self, opts, args): |
123 self.output_directory = '.' | 132 self.output_directory = '.' |
124 first_ids_file = None | 133 first_ids_file = None |
125 whitelist_filenames = [] | 134 whitelist_filenames = [] |
126 assert_output_files = [] | 135 assert_output_files = [] |
127 target_platform = None | 136 target_platform = None |
128 depfile = None | 137 depfile = None |
129 depdir = None | 138 depdir = None |
130 rc_header_format = None | 139 rc_header_format = None |
131 output_all_resource_defines = None | 140 output_all_resource_defines = None |
| 141 write_only_new = False |
132 (own_opts, args) = getopt.getopt(args, 'a:o:D:E:f:w:t:h:', | 142 (own_opts, args) = getopt.getopt(args, 'a:o:D:E:f:w:t:h:', |
133 ('depdir=','depfile=','assert-file-list=', | 143 ('depdir=','depfile=','assert-file-list=', |
134 'output-all-resource-defines', | 144 'output-all-resource-defines', |
135 'no-output-all-resource-defines',)) | 145 'no-output-all-resource-defines', |
| 146 'write-only-new=')) |
136 for (key, val) in own_opts: | 147 for (key, val) in own_opts: |
137 if key == '-a': | 148 if key == '-a': |
138 assert_output_files.append(val) | 149 assert_output_files.append(val) |
139 elif key == '--assert-file-list': | 150 elif key == '--assert-file-list': |
140 with open(val) as f: | 151 with open(val) as f: |
141 assert_output_files += f.read().splitlines() | 152 assert_output_files += f.read().splitlines() |
142 elif key == '-o': | 153 elif key == '-o': |
143 self.output_directory = val | 154 self.output_directory = val |
144 elif key == '-D': | 155 elif key == '-D': |
145 name, val = util.ParseDefine(val) | 156 name, val = util.ParseDefine(val) |
(...skipping 13 matching lines...) Expand all Loading... |
159 elif key == '--no-output-all-resource-defines': | 170 elif key == '--no-output-all-resource-defines': |
160 output_all_resource_defines = False | 171 output_all_resource_defines = False |
161 elif key == '-t': | 172 elif key == '-t': |
162 target_platform = val | 173 target_platform = val |
163 elif key == '-h': | 174 elif key == '-h': |
164 rc_header_format = val | 175 rc_header_format = val |
165 elif key == '--depdir': | 176 elif key == '--depdir': |
166 depdir = val | 177 depdir = val |
167 elif key == '--depfile': | 178 elif key == '--depfile': |
168 depfile = val | 179 depfile = val |
| 180 elif key == '--write-only-new': |
| 181 write_only_new = val != '0' |
169 | 182 |
170 if len(args): | 183 if len(args): |
171 print 'This tool takes no tool-specific arguments.' | 184 print 'This tool takes no tool-specific arguments.' |
172 return 2 | 185 return 2 |
173 self.SetOptions(opts) | 186 self.SetOptions(opts) |
174 if self.scons_targets: | 187 if self.scons_targets: |
175 self.VerboseOut('Using SCons targets to identify files to output.\n') | 188 self.VerboseOut('Using SCons targets to identify files to output.\n') |
176 else: | 189 else: |
177 self.VerboseOut('Output directory: %s (absolute path: %s)\n' % | 190 self.VerboseOut('Output directory: %s (absolute path: %s)\n' % |
178 (self.output_directory, | 191 (self.output_directory, |
179 os.path.abspath(self.output_directory))) | 192 os.path.abspath(self.output_directory))) |
180 | 193 |
181 if whitelist_filenames: | 194 if whitelist_filenames: |
182 self.whitelist_names = set() | 195 self.whitelist_names = set() |
183 for whitelist_filename in whitelist_filenames: | 196 for whitelist_filename in whitelist_filenames: |
184 self.VerboseOut('Using whitelist: %s\n' % whitelist_filename); | 197 self.VerboseOut('Using whitelist: %s\n' % whitelist_filename); |
185 whitelist_contents = util.ReadFile(whitelist_filename, util.RAW_TEXT) | 198 whitelist_contents = util.ReadFile(whitelist_filename, util.RAW_TEXT) |
186 self.whitelist_names.update(whitelist_contents.strip().split('\n')) | 199 self.whitelist_names.update(whitelist_contents.strip().split('\n')) |
187 | 200 |
| 201 self.write_only_new = write_only_new |
| 202 |
188 self.res = grd_reader.Parse(opts.input, | 203 self.res = grd_reader.Parse(opts.input, |
189 debug=opts.extra_verbose, | 204 debug=opts.extra_verbose, |
190 first_ids_file=first_ids_file, | 205 first_ids_file=first_ids_file, |
191 defines=self.defines, | 206 defines=self.defines, |
192 target_platform=target_platform) | 207 target_platform=target_platform) |
193 | 208 |
194 # If the output_all_resource_defines option is specified, override the value | 209 # If the output_all_resource_defines option is specified, override the value |
195 # found in the grd file. | 210 # found in the grd file. |
196 if output_all_resource_defines is not None: | 211 if output_all_resource_defines is not None: |
197 self.res.SetShouldOutputAllResourceDefines(output_all_resource_defines) | 212 self.res.SetShouldOutputAllResourceDefines(output_all_resource_defines) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 | 244 |
230 # Set to a list of filenames for the output nodes that are relative | 245 # Set to a list of filenames for the output nodes that are relative |
231 # to the current working directory. They are in the same order as the | 246 # to the current working directory. They are in the same order as the |
232 # output nodes in the file. | 247 # output nodes in the file. |
233 self.scons_targets = None | 248 self.scons_targets = None |
234 | 249 |
235 # The set of names that are whitelisted to actually be included in the | 250 # The set of names that are whitelisted to actually be included in the |
236 # output. | 251 # output. |
237 self.whitelist_names = None | 252 self.whitelist_names = None |
238 | 253 |
| 254 # Whether to compare outputs to their old contents before writing. |
| 255 self.write_only_new = False |
| 256 |
239 @staticmethod | 257 @staticmethod |
240 def AddWhitelistTags(start_node, whitelist_names): | 258 def AddWhitelistTags(start_node, whitelist_names): |
241 # Walk the tree of nodes added attributes for the nodes that shouldn't | 259 # Walk the tree of nodes added attributes for the nodes that shouldn't |
242 # be written into the target files (skip markers). | 260 # be written into the target files (skip markers). |
243 from grit.node import include | 261 from grit.node import include |
244 from grit.node import message | 262 from grit.node import message |
245 from grit.node import structure | 263 from grit.node import structure |
246 for node in start_node: | 264 for node in start_node: |
247 # Same trick data_pack.py uses to see what nodes actually result in | 265 # Same trick data_pack.py uses to see what nodes actually result in |
248 # real items. | 266 # real items. |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
334 # Now copy from the temp file back to the real output, but on Windows, | 352 # Now copy from the temp file back to the real output, but on Windows, |
335 # only if the real output doesn't exist or the contents of the file | 353 # only if the real output doesn't exist or the contents of the file |
336 # changed. This prevents identical headers from being written and .cc | 354 # changed. This prevents identical headers from being written and .cc |
337 # files from recompiling (which is painful on Windows). | 355 # files from recompiling (which is painful on Windows). |
338 if not os.path.exists(output.GetOutputFilename()): | 356 if not os.path.exists(output.GetOutputFilename()): |
339 os.rename(output.GetOutputFilename() + '.tmp', | 357 os.rename(output.GetOutputFilename() + '.tmp', |
340 output.GetOutputFilename()) | 358 output.GetOutputFilename()) |
341 else: | 359 else: |
342 # CHROMIUM SPECIFIC CHANGE. | 360 # CHROMIUM SPECIFIC CHANGE. |
343 # This clashes with gyp + vstudio, which expect the output timestamp | 361 # This clashes with gyp + vstudio, which expect the output timestamp |
344 # to change on a rebuild, even if nothing has changed. | 362 # to change on a rebuild, even if nothing has changed, so only do |
345 #files_match = filecmp.cmp(output.GetOutputFilename(), | 363 # it when opted in. |
346 # output.GetOutputFilename() + '.tmp') | 364 if not self.write_only_new: |
347 #if (output.GetType() != 'rc_header' or not files_match | 365 write_file = True |
348 # or sys.platform != 'win32'): | 366 else: |
349 shutil.copy2(output.GetOutputFilename() + '.tmp', | 367 files_match = filecmp.cmp(output.GetOutputFilename(), |
350 output.GetOutputFilename()) | 368 output.GetOutputFilename() + '.tmp') |
| 369 write_file = not files_match |
| 370 if write_file: |
| 371 shutil.copy2(output.GetOutputFilename() + '.tmp', |
| 372 output.GetOutputFilename()) |
351 os.remove(output.GetOutputFilename() + '.tmp') | 373 os.remove(output.GetOutputFilename() + '.tmp') |
352 | 374 |
353 self.VerboseOut(' done.\n') | 375 self.VerboseOut(' done.\n') |
354 | 376 |
355 # Print warnings if there are any duplicate shortcuts. | 377 # Print warnings if there are any duplicate shortcuts. |
356 warnings = shortcuts.GenerateDuplicateShortcutsWarnings( | 378 warnings = shortcuts.GenerateDuplicateShortcutsWarnings( |
357 self.res.UberClique(), self.res.GetTcProject()) | 379 self.res.UberClique(), self.res.GetTcProject()) |
358 if warnings: | 380 if warnings: |
359 print '\n'.join(warnings) | 381 print '\n'.join(warnings) |
360 | 382 |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
445 self.MakeDirectoriesTo(depfile) | 467 self.MakeDirectoriesTo(depfile) |
446 outfile = self.fo_create(depfile, 'wb') | 468 outfile = self.fo_create(depfile, 'wb') |
447 outfile.writelines(depfile_contents) | 469 outfile.writelines(depfile_contents) |
448 | 470 |
449 @staticmethod | 471 @staticmethod |
450 def MakeDirectoriesTo(file): | 472 def MakeDirectoriesTo(file): |
451 '''Creates directories necessary to contain |file|.''' | 473 '''Creates directories necessary to contain |file|.''' |
452 dir = os.path.split(file)[0] | 474 dir = os.path.split(file)[0] |
453 if not os.path.exists(dir): | 475 if not os.path.exists(dir): |
454 os.makedirs(dir) | 476 os.makedirs(dir) |
OLD | NEW |