Chromium Code Reviews| 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 |