195640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org#!/usr/bin/env python 295640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org# Copyright (c) 2012 The Chromium Authors. All rights reserved. 301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# Use of this source code is governed by a BSD-style license that can be 401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# found in the LICENSE file. 501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org'''The 'grit build' tool along with integration for this tool with the 701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgSCons build system. 801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org''' 901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport filecmp 1101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport getopt 1201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport os 1301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport shutil 1401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport sys 1501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit import grd_reader 1701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit import util 1801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit.tool import interface 1901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit import shortcuts 2001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 2101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 22ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org# It would be cleaner to have each module register itself, but that would 23ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org# require importing all of them on every run of GRIT. 24ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org'''Map from <output> node types to modules under grit.format.''' 25ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org_format_modules = { 26ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'android': 'android_xml', 27ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'c_format': 'c_format', 28ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'chrome_messages_json': 'chrome_messages_json', 29ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'data_package': 'data_pack', 30ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'js_map_format': 'js_map_format', 31ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'rc_all': 'rc', 32ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'rc_translateable': 'rc', 33ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'rc_nontranslateable': 'rc', 34ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'rc_header': 'rc_header', 35ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'resource_map_header': 'resource_map', 36ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'resource_map_source': 'resource_map', 37ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'resource_file_map_source': 'resource_map', 38ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org} 39ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org_format_modules.update((type, 'policy_templates.template_formatter') 40ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for type in 'adm plist plist_strings admx adml doc json reg'.split()) 41ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 42ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 43ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.orgdef GetFormatter(type): 44ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org modulename = 'grit.format.' + _format_modules[type] 45ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org __import__(modulename) 46ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org module = sys.modules[modulename] 47ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org try: 48ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org return module.Format 49ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org except AttributeError: 50ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org return module.GetFormatter(type) 51ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 52ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 5301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass RcBuilder(interface.Tool): 5401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''A tool that builds RC files and resource header files for compilation. 5501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 5601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgUsage: grit build [-o OUTPUTDIR] [-D NAME[=VAL]]* 5701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 5801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgAll output options for this tool are specified in the input file (see 5901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org'grit help' for details on how to specify the input file - it is a global 6001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgoption). 6101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 6201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgOptions: 6301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 6401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org -o OUTPUTDIR Specify what directory output paths are relative to. 6501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org Defaults to the current directory. 6601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 6701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org -D NAME[=VAL] Specify a C-preprocessor-like define NAME with optional 6801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org value VAL (defaults to 1) which will be used to control 6901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org conditional inclusion of resources. 7001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 7101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org -E NAME=VALUE Set environment variable NAME to VALUE (within grit). 7201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 730dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org -f FIRSTIDSFILE Path to a python file that specifies the first id of 740dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org value to use for resources. A non-empty value here will 750dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org override the value specified in the <grit> node's 760dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org first_ids_file. 7701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 7801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org -w WHITELISTFILE Path to a file containing the string names of the 7901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org resources to include. Anything not listed is dropped. 8001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 81abf28c9e0d607e293a9d790300090e557be6b41ejoi@chromium.org -t PLATFORM Specifies the platform the build is targeting; defaults 82abf28c9e0d607e293a9d790300090e557be6b41ejoi@chromium.org to the value of sys.platform. The value provided via this 83abf28c9e0d607e293a9d790300090e557be6b41ejoi@chromium.org flag should match what sys.platform would report for your 84abf28c9e0d607e293a9d790300090e557be6b41ejoi@chromium.org target platform; see grit.node.base.EvaluateCondition. 8501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 8601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgConditional inclusion of resources only affects the output of files which 8701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgcontrol which resources get linked into a binary, e.g. it affects .rc files 8801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgmeant for compilation but it does not affect resource header files (that define 8901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgIDs). This helps ensure that values of IDs stay the same, that all messages 9001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgare exported to translation interchange files (e.g. XMB files), etc. 9101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org''' 9201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 9301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def ShortDescription(self): 9401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 'A tool that builds RC files for compilation.' 9501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 9601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Run(self, opts, args): 9701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.output_directory = '.' 980dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org first_ids_file = None 9901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org whitelist_filenames = [] 100abf28c9e0d607e293a9d790300090e557be6b41ejoi@chromium.org target_platform = None 101247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org dep_dir = None 102247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org (own_opts, args) = getopt.getopt(args, 'o:D:E:f:w:t:', ('dep-dir=',)) 10301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for (key, val) in own_opts: 10401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if key == '-o': 10501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.output_directory = val 10601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org elif key == '-D': 10777cbaa8b1f1af05d8ba2c2a951c74e7909318830joi@chromium.org name, val = util.ParseDefine(val) 10801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.defines[name] = val 10901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org elif key == '-E': 110ef7918f5c87325d97a94438b3adf18e1bc799b7cjoi@chromium.org (env_name, env_value) = val.split('=', 1) 11101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org os.environ[env_name] = env_value 11201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org elif key == '-f': 1130dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org # TODO(joi@chromium.org): Remove this override once change 1140dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org # lands in WebKit.grd to specify the first_ids_file in the 1150dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org # .grd itself. 1160dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org first_ids_file = val 11701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org elif key == '-w': 11801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org whitelist_filenames.append(val) 119abf28c9e0d607e293a9d790300090e557be6b41ejoi@chromium.org elif key == '-t': 120abf28c9e0d607e293a9d790300090e557be6b41ejoi@chromium.org target_platform = val 121247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org elif key == '--dep-dir': 122247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org dep_dir = val 12301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 12401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if len(args): 12577cbaa8b1f1af05d8ba2c2a951c74e7909318830joi@chromium.org print 'This tool takes no tool-specific arguments.' 12601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 2 12701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.SetOptions(opts) 12801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.scons_targets: 12901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.VerboseOut('Using SCons targets to identify files to output.\n') 13001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 13101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.VerboseOut('Output directory: %s (absolute path: %s)\n' % 13201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org (self.output_directory, 13301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org os.path.abspath(self.output_directory))) 13401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 13501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if whitelist_filenames: 13601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.whitelist_names = set() 13701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for whitelist_filename in whitelist_filenames: 13801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.VerboseOut('Using whitelist: %s\n' % whitelist_filename); 139b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org whitelist_contents = util.ReadFile(whitelist_filename, util.RAW_TEXT) 140b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org self.whitelist_names.update(whitelist_contents.strip().split('\n')) 14101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1420dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org self.res = grd_reader.Parse(opts.input, 1430dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org debug=opts.extra_verbose, 1440dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org first_ids_file=first_ids_file, 145abf28c9e0d607e293a9d790300090e557be6b41ejoi@chromium.org defines=self.defines, 146abf28c9e0d607e293a9d790300090e557be6b41ejoi@chromium.org target_platform=target_platform) 147b012d530d2c6c921727e1136d0939e2649e4f77ejoi@chromium.org # Set an output context so that conditionals can use defines during the 148b012d530d2c6c921727e1136d0939e2649e4f77ejoi@chromium.org # gathering stage; we use a dummy language here since we are not outputting 149b012d530d2c6c921727e1136d0939e2649e4f77ejoi@chromium.org # a specific language. 150783385ad40d453977d8b9d537e204f851e21591abenrg@chromium.org self.res.SetOutputLanguage('en') 151ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org self.res.RunGatherers() 15201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.Process() 153247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 154247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org if dep_dir: 155247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org self.GenerateDepfile(opts.input, dep_dir) 156247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 15701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 15801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 159705a118ab4a1f2fe348fccdcd4786a0b5bf426ecjoi@chromium.org def __init__(self, defines=None): 160b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org # Default file-creation function is built-in open(). Only done to allow 16101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # overriding by unit test. 162b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org self.fo_create = open 16301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 16401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # key/value pairs of C-preprocessor like defines that are used for 16501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # conditional output of resources 16677cbaa8b1f1af05d8ba2c2a951c74e7909318830joi@chromium.org self.defines = defines or {} 16701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 16801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # self.res is a fully-populated resource tree if Run() 16901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # has been called, otherwise None. 17001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.res = None 17101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 17201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Set to a list of filenames for the output nodes that are relative 17301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # to the current working directory. They are in the same order as the 17401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # output nodes in the file. 17501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.scons_targets = None 17601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 17701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # The set of names that are whitelisted to actually be included in the 17801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # output. 17901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.whitelist_names = None 18001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 18101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 182b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org @staticmethod 18301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def AddWhitelistTags(start_node, whitelist_names): 18401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Walk the tree of nodes added attributes for the nodes that shouldn't 18501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # be written into the target files (skip markers). 18601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org from grit.node import include 18701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org from grit.node import message 188ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for node in start_node: 18901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Same trick data_pack.py uses to see what nodes actually result in 19001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # real items. 19101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if (isinstance(node, include.IncludeNode) or 19201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org isinstance(node, message.MessageNode)): 19301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org text_ids = node.GetTextualIds() 19401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Mark the item to be skipped if it wasn't in the whitelist. 195ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if text_ids and text_ids[0] not in whitelist_names: 19601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org node.SetWhitelistMarkedAsSkip(True) 19701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 198b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org @staticmethod 19901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def ProcessNode(node, output_node, outfile): 20001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''Processes a node in-order, calling its formatter before and after 20101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org recursing to its children. 20201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 20301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org Args: 20401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org node: grit.node.base.Node subclass 205ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org output_node: grit.node.io.OutputNode 20601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org outfile: open filehandle 20701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ''' 20801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org base_dir = util.dirname(output_node.GetOutputFilename()) 20901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 210ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org formatter = GetFormatter(output_node.GetType()) 211ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org formatted = formatter(node, output_node.GetLanguage(), output_dir=base_dir) 212ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org outfile.writelines(formatted) 21301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 21401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 21501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Process(self): 21601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Update filenames with those provided by SCons if we're being invoked 21701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # from SCons. The list of SCons targets also includes all <structure> 21801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # node outputs, but it starts with our output files, in the order they 21901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # occur in the .grd 22001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.scons_targets: 22101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org assert len(self.scons_targets) >= len(self.res.GetOutputFiles()) 22201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org outfiles = self.res.GetOutputFiles() 22301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for ix in range(len(outfiles)): 22401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org outfiles[ix].output_filename = os.path.abspath( 22501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.scons_targets[ix]) 22601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 22701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for output in self.res.GetOutputFiles(): 22801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org output.output_filename = os.path.abspath(os.path.join( 22901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.output_directory, output.GetFilename())) 23001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 23101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # If there are whitelisted names, tag the tree once up front, this way 23201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # while looping through the actual output, it is just an attribute check. 23301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.whitelist_names: 23401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.AddWhitelistTags(self.res, self.whitelist_names) 23501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 23601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for output in self.res.GetOutputFiles(): 23701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.VerboseOut('Creating %s...' % output.GetFilename()) 23801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 23901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Microsoft's RC compiler can only deal with single-byte or double-byte 24001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # files (no UTF-8), so we make all RC files UTF-16 to support all 24101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # character sets. 24201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if output.GetType() in ('rc_header', 'resource_map_header', 24301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 'resource_map_source', 'resource_file_map_source'): 24401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org encoding = 'cp1252' 24539c335c3faa47701974a3ba3f7f8175947efc248newt@chromium.org elif output.GetType() in ('android', 'c_format', 'js_map_format', 'plist', 246140682b7c724552cbac145cbafaa6a88ce757123sergeyu@chromium.org 'plist_strings', 'doc', 'json'): 24701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org encoding = 'utf_8' 248140682b7c724552cbac145cbafaa6a88ce757123sergeyu@chromium.org elif output.GetType() in ('chrome_messages_json'): 249140682b7c724552cbac145cbafaa6a88ce757123sergeyu@chromium.org # Chrome Web Store currently expects BOM for UTF-8 files :-( 250140682b7c724552cbac145cbafaa6a88ce757123sergeyu@chromium.org encoding = 'utf-8-sig' 25101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 25201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # TODO(gfeher) modify here to set utf-8 encoding for admx/adml 25301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org encoding = 'utf_16' 25401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 255b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org # Set the context, for conditional inclusion of resources 256b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org self.res.SetOutputLanguage(output.GetLanguage()) 257b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org self.res.SetOutputContext(output.GetContext()) 258b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org self.res.SetDefines(self.defines) 259b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org 26001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Make the output directory if it doesn't exist. 261247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org self.MakeDirectoriesTo(output.GetOutputFilename()) 262b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org 26301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Write the results to a temporary file and only overwrite the original 26401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # if the file changed. This avoids unnecessary rebuilds. 26501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org outfile = self.fo_create(output.GetOutputFilename() + '.tmp', 'wb') 26601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 26701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if output.GetType() != 'data_package': 26801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org outfile = util.WrapOutputStream(outfile, encoding) 26901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 27001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Iterate in-order through entire resource tree, calling formatters on 27101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # the entry into a node and on exit out of it. 272b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org with outfile: 273b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org self.ProcessNode(self.res, output, outfile) 27401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 27501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Now copy from the temp file back to the real output, but on Windows, 27601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # only if the real output doesn't exist or the contents of the file 27701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # changed. This prevents identical headers from being written and .cc 27801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # files from recompiling (which is painful on Windows). 27901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not os.path.exists(output.GetOutputFilename()): 28001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org os.rename(output.GetOutputFilename() + '.tmp', 28101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org output.GetOutputFilename()) 28201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 28301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # CHROMIUM SPECIFIC CHANGE. 28401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # This clashes with gyp + vstudio, which expect the output timestamp 28501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # to change on a rebuild, even if nothing has changed. 28601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org #files_match = filecmp.cmp(output.GetOutputFilename(), 28701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # output.GetOutputFilename() + '.tmp') 28801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org #if (output.GetType() != 'rc_header' or not files_match 28901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # or sys.platform != 'win32'): 29001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org shutil.copy2(output.GetOutputFilename() + '.tmp', 29101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org output.GetOutputFilename()) 29201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org os.remove(output.GetOutputFilename() + '.tmp') 29301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 29401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.VerboseOut(' done.\n') 29501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 29601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Print warnings if there are any duplicate shortcuts. 29701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org warnings = shortcuts.GenerateDuplicateShortcutsWarnings( 29801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.res.UberClique(), self.res.GetTcProject()) 29901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if warnings: 30001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org print '\n'.join(warnings) 30101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 30201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Print out any fallback warnings, and missing translation errors, and 30301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # exit with an error code if there are missing translations in a non-pseudo 30401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # and non-official build. 30501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org warnings = (self.res.UberClique().MissingTranslationsReport(). 30601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org encode('ascii', 'replace')) 30799515cd09d78391b5ec3145ee6b7939220612e8dtony@chromium.org if warnings: 30899515cd09d78391b5ec3145ee6b7939220612e8dtony@chromium.org self.VerboseOut(warnings) 30901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.res.UberClique().HasMissingTranslations(): 3101eddb32f808ac5930f24b1954b5c949b273a3869joi@chromium.org print self.res.UberClique().missing_translations_ 31101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org sys.exit(-1) 312247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 313247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org def GenerateDepfile(self, input_filename, dep_dir): 314247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org '''Generate a depfile that contains the imlicit dependencies of the input 315247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org grd. The depfile will be in the same format as a makefile, and will contain 316247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org references to files relative to |dep_dir|. It will be put in the same 317247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org directory as the generated outputs. 318247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 319247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org For example, supposing we have three files in a directory src/ 320247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 321247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org src/ 322247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org blah.grd <- depends on input{1,2}.xtb 323247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org input1.xtb 324247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org input2.xtb 325247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 326247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org and we run 327247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 328247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org grit -i blah.grd -o ../out/gen --dep-dir ../out 329247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 330247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org from the directory src/ we will generate a depfile ../out/gen/blah.grd.d 331247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org that has the contents 332247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 333247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org gen/blah.grd.d: ../src/input1.xtb ../src/input2.xtb 334247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 335247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org Note that all paths in the depfile are relative to ../out, the dep-dir. 336247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org ''' 337247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org depsfile_basename = os.path.basename(input_filename + '.d') 338247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org depfile = os.path.abspath( 339247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org os.path.join(self.output_directory, depsfile_basename)) 340247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org dep_dir = os.path.abspath(dep_dir) 341247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org # The path prefix to prepend to dependencies in the depfile. 342247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org prefix = os.path.relpath(os.getcwd(), dep_dir) 343247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org # The path that the depfile refers to itself by. 344247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org self_ref_depfile = os.path.relpath(depfile, dep_dir) 345247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org infiles = self.res.GetInputFiles() 346247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org deps_text = ' '.join([os.path.join(prefix, i) for i in infiles]) 347247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org depfile_contents = self_ref_depfile + ': ' + deps_text 348247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org self.MakeDirectoriesTo(depfile) 349247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org outfile = self.fo_create(depfile, 'wb') 350247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org outfile.writelines(depfile_contents) 351247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org 352247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org @staticmethod 353247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org def MakeDirectoriesTo(file): 354247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org '''Creates directories necessary to contain |file|.''' 355247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org dir = os.path.split(file)[0] 356247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org if not os.path.exists(dir): 357247c890730ffcd4932c99117272aba944f347cc6joi@chromium.org os.makedirs(dir) 358