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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
56 '''A tool that builds RC files and resource header files for compilation. | 56 '''A tool that builds RC files and resource header files for compilation. |
57 | 57 |
58 Usage: grit build [-o OUTPUTDIR] [-D NAME[=VAL]]* | 58 Usage: grit build [-o OUTPUTDIR] [-D NAME[=VAL]]* |
59 | 59 |
60 All output options for this tool are specified in the input file (see | 60 All output options for this tool are specified in the input file (see |
61 'grit help' for details on how to specify the input file - it is a global | 61 'grit help' for details on how to specify the input file - it is a global |
62 option). | 62 option). |
63 | 63 |
64 Options: | 64 Options: |
65 | 65 |
66 -a FILE Assert that the given file is an output. There can be | |
67 multiple "-a" flags listed for multiple outputs. If a "-a" | |
68 or "--assert-file-list" argument is present, then the list | |
69 of asserted files must match the output files or the tool | |
70 will fail. The use-case is for the build system to maintain | |
71 separate lists of output files and to catch errors if the | |
72 build system's list and the grit list are out-of-sync. | |
73 | |
74 --assert-file-list Provide a file listing multiple asserted output files. | |
75 There is one file name per line. This acts like specifying | |
76 each file with "-a" on the command line, but without the | |
77 possibility of running into OS line-length limits for very | |
78 long lists. | |
79 | |
66 -o OUTPUTDIR Specify what directory output paths are relative to. | 80 -o OUTPUTDIR Specify what directory output paths are relative to. |
67 Defaults to the current directory. | 81 Defaults to the current directory. |
68 | 82 |
69 -D NAME[=VAL] Specify a C-preprocessor-like define NAME with optional | 83 -D NAME[=VAL] Specify a C-preprocessor-like define NAME with optional |
70 value VAL (defaults to 1) which will be used to control | 84 value VAL (defaults to 1) which will be used to control |
71 conditional inclusion of resources. | 85 conditional inclusion of resources. |
72 | 86 |
73 -E NAME=VALUE Set environment variable NAME to VALUE (within grit). | 87 -E NAME=VALUE Set environment variable NAME to VALUE (within grit). |
74 | 88 |
75 -f FIRSTIDSFILE Path to a python file that specifies the first id of | 89 -f FIRSTIDSFILE Path to a python file that specifies the first id of |
(...skipping 21 matching lines...) Expand all Loading... | |
97 are exported to translation interchange files (e.g. XMB files), etc. | 111 are exported to translation interchange files (e.g. XMB files), etc. |
98 ''' | 112 ''' |
99 | 113 |
100 def ShortDescription(self): | 114 def ShortDescription(self): |
101 return 'A tool that builds RC files for compilation.' | 115 return 'A tool that builds RC files for compilation.' |
102 | 116 |
103 def Run(self, opts, args): | 117 def Run(self, opts, args): |
104 self.output_directory = '.' | 118 self.output_directory = '.' |
105 first_ids_file = None | 119 first_ids_file = None |
106 whitelist_filenames = [] | 120 whitelist_filenames = [] |
121 assert_output_files = [] | |
107 target_platform = None | 122 target_platform = None |
108 depfile = None | 123 depfile = None |
109 depdir = None | 124 depdir = None |
110 rc_header_format = None | 125 rc_header_format = None |
111 (own_opts, args) = getopt.getopt(args, 'o:D:E:f:w:t:h:', ('depdir=','depfile =')) | 126 (own_opts, args) = getopt.getopt(args, 'a:o:D:E:f:w:t:h:', |
127 ('depdir=','depfile=','assert-file-list=')) | |
112 for (key, val) in own_opts: | 128 for (key, val) in own_opts: |
113 if key == '-o': | 129 if key == '-a': |
130 assert_output_files.append(val) | |
131 elif key == '--assert-file-list': | |
132 with open(val) as f: | |
133 assert_output_files += f.read().splitlines() | |
134 elif key == '-o': | |
114 self.output_directory = val | 135 self.output_directory = val |
115 elif key == '-D': | 136 elif key == '-D': |
116 name, val = util.ParseDefine(val) | 137 name, val = util.ParseDefine(val) |
117 self.defines[name] = val | 138 self.defines[name] = val |
118 elif key == '-E': | 139 elif key == '-E': |
119 (env_name, env_value) = val.split('=', 1) | 140 (env_name, env_value) = val.split('=', 1) |
120 os.environ[env_name] = env_value | 141 os.environ[env_name] = env_value |
121 elif key == '-f': | 142 elif key == '-f': |
122 # TODO(joi@chromium.org): Remove this override once change | 143 # TODO(joi@chromium.org): Remove this override once change |
123 # lands in WebKit.grd to specify the first_ids_file in the | 144 # lands in WebKit.grd to specify the first_ids_file in the |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
159 target_platform=target_platform) | 180 target_platform=target_platform) |
160 # Set an output context so that conditionals can use defines during the | 181 # Set an output context so that conditionals can use defines during the |
161 # gathering stage; we use a dummy language here since we are not outputting | 182 # gathering stage; we use a dummy language here since we are not outputting |
162 # a specific language. | 183 # a specific language. |
163 self.res.SetOutputLanguage('en') | 184 self.res.SetOutputLanguage('en') |
164 if rc_header_format: | 185 if rc_header_format: |
165 self.res.AssignRcHeaderFormat(rc_header_format) | 186 self.res.AssignRcHeaderFormat(rc_header_format) |
166 self.res.RunGatherers() | 187 self.res.RunGatherers() |
167 self.Process() | 188 self.Process() |
168 | 189 |
190 if assert_output_files: | |
191 if not self.CheckAssertedOutputFiles(assert_output_files): | |
192 return 2 | |
193 | |
169 if depfile and depdir: | 194 if depfile and depdir: |
170 self.GenerateDepfile(opts.input, depfile, depdir) | 195 self.GenerateDepfile(depfile, depdir) |
171 | 196 |
172 return 0 | 197 return 0 |
173 | 198 |
174 def __init__(self, defines=None): | 199 def __init__(self, defines=None): |
175 # Default file-creation function is built-in open(). Only done to allow | 200 # Default file-creation function is built-in open(). Only done to allow |
176 # overriding by unit test. | 201 # overriding by unit test. |
177 self.fo_create = open | 202 self.fo_create = open |
178 | 203 |
179 # key/value pairs of C-preprocessor like defines that are used for | 204 # key/value pairs of C-preprocessor like defines that are used for |
180 # conditional output of resources | 205 # conditional output of resources |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
317 # exit with an error code if there are missing translations in a non-pseudo | 342 # exit with an error code if there are missing translations in a non-pseudo |
318 # and non-official build. | 343 # and non-official build. |
319 warnings = (self.res.UberClique().MissingTranslationsReport(). | 344 warnings = (self.res.UberClique().MissingTranslationsReport(). |
320 encode('ascii', 'replace')) | 345 encode('ascii', 'replace')) |
321 if warnings: | 346 if warnings: |
322 self.VerboseOut(warnings) | 347 self.VerboseOut(warnings) |
323 if self.res.UberClique().HasMissingTranslations(): | 348 if self.res.UberClique().HasMissingTranslations(): |
324 print self.res.UberClique().missing_translations_ | 349 print self.res.UberClique().missing_translations_ |
325 sys.exit(-1) | 350 sys.exit(-1) |
326 | 351 |
327 def GenerateDepfile(self, input_filename, depfile, depdir): | 352 |
353 def CheckAssertedOutputFiles(self, assert_output_files): | |
354 '''Checks that the asserted output files are specified in the given list. | |
355 | |
356 Returns true if the asserted files are present. If they are not, returns | |
357 False and prints the failure. | |
358 ''' | |
359 # Compare the absolute path names, sorted. | |
360 asserted = sorted([os.path.abspath(i) for i in assert_output_files]) | |
Nico
2014/07/21 18:09:25
so asserted_output_files is relative to the cwd, b
brettw
2014/07/21 19:51:53
Yes, like all other inputs, they're relative to th
| |
361 actual = sorted([ | |
362 os.path.abspath(os.path.join(self.output_directory, i.GetFilename())) | |
363 for i in self.res.GetOutputFiles()]) | |
364 | |
365 if asserted != actual: | |
366 print '''Asserted file list does not match. | |
367 | |
368 Expected output files: %s | |
369 | |
370 Actual output files: %s | |
371 ''' % (asserted, actual) | |
372 return False | |
373 return True | |
374 | |
375 | |
376 def GenerateDepfile(self, depfile, depdir): | |
328 '''Generate a depfile that contains the imlicit dependencies of the input | 377 '''Generate a depfile that contains the imlicit dependencies of the input |
329 grd. The depfile will be in the same format as a makefile, and will contain | 378 grd. The depfile will be in the same format as a makefile, and will contain |
330 references to files relative to |depdir|. It will be put in |depfile|. | 379 references to files relative to |depdir|. It will be put in |depfile|. |
331 | 380 |
332 For example, supposing we have three files in a directory src/ | 381 For example, supposing we have three files in a directory src/ |
333 | 382 |
334 src/ | 383 src/ |
335 blah.grd <- depends on input{1,2}.xtb | 384 blah.grd <- depends on input{1,2}.xtb |
336 input1.xtb | 385 input1.xtb |
337 input2.xtb | 386 input2.xtb |
338 | 387 |
339 and we run | 388 and we run |
340 | 389 |
341 grit -i blah.grd -o ../out/gen --depdir ../out --depfile ../out/gen/blah.r d.d | 390 grit -i blah.grd -o ../out/gen --depdir ../out --depfile ../out/gen/blah.r d.d |
342 | 391 |
343 from the directory src/ we will generate a depfile ../out/gen/blah.grd.d | 392 from the directory src/ we will generate a depfile ../out/gen/blah.grd.d |
344 that has the contents | 393 that has the contents |
345 | 394 |
346 gen/blah.grd.d: ../src/input1.xtb ../src/input2.xtb | 395 gen/blah.h: ../src/input1.xtb ../src/input2.xtb |
396 | |
397 Where "gen/blah.h" is the first output (Ninja expects the .d file to list | |
398 the first output in cases where there is more than one). | |
347 | 399 |
348 Note that all paths in the depfile are relative to ../out, the depdir. | 400 Note that all paths in the depfile are relative to ../out, the depdir. |
349 ''' | 401 ''' |
350 depfile = os.path.abspath(depfile) | 402 depfile = os.path.abspath(depfile) |
351 depdir = os.path.abspath(depdir) | 403 depdir = os.path.abspath(depdir) |
404 infiles = self.res.GetInputFiles() | |
405 | |
406 # Get the first output file relative to the depdir. | |
407 outputs = self.res.GetOutputFiles() | |
408 output_file = os.path.relpath(os.path.join( | |
409 self.output_directory, outputs[0].GetFilename()), depdir) | |
410 | |
352 # The path prefix to prepend to dependencies in the depfile. | 411 # The path prefix to prepend to dependencies in the depfile. |
353 prefix = os.path.relpath(os.getcwd(), depdir) | 412 prefix = os.path.relpath(os.getcwd(), depdir) |
354 # The path that the depfile refers to itself by. | |
355 self_ref_depfile = os.path.relpath(depfile, depdir) | |
356 infiles = self.res.GetInputFiles() | |
357 deps_text = ' '.join([os.path.join(prefix, i) for i in infiles]) | 413 deps_text = ' '.join([os.path.join(prefix, i) for i in infiles]) |
358 depfile_contents = self_ref_depfile + ': ' + deps_text | 414 |
415 depfile_contents = output_file + ': ' + deps_text | |
359 self.MakeDirectoriesTo(depfile) | 416 self.MakeDirectoriesTo(depfile) |
360 outfile = self.fo_create(depfile, 'wb') | 417 outfile = self.fo_create(depfile, 'wb') |
361 outfile.writelines(depfile_contents) | 418 outfile.writelines(depfile_contents) |
362 | 419 |
363 @staticmethod | 420 @staticmethod |
364 def MakeDirectoriesTo(file): | 421 def MakeDirectoriesTo(file): |
365 '''Creates directories necessary to contain |file|.''' | 422 '''Creates directories necessary to contain |file|.''' |
366 dir = os.path.split(file)[0] | 423 dir = os.path.split(file)[0] |
367 if not os.path.exists(dir): | 424 if not os.path.exists(dir): |
368 os.makedirs(dir) | 425 os.makedirs(dir) |
OLD | NEW |