1#!/usr/bin/python 2# 3# Copyright (C) 2009 Google Inc. All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: 8# 9# * Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# * Redistributions in binary form must reproduce the above 12# copyright notice, this list of conditions and the following disclaimer 13# in the documentation and/or other materials provided with the 14# distribution. 15# * Neither the name of Google Inc. nor the names of its 16# contributors may be used to endorse or promote products derived from 17# this software without specific prior written permission. 18# 19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30# 31# Copyright (c) 2009 The Chromium Authors. All rights reserved. 32# Use of this source code is governed by a BSD-style license that can be 33# found in the LICENSE file. 34 35"""Generate aggregate .cpp files that include multiple V8 binding .cpp files. 36 37This can be a single output file, to preserve symbol space; or multiple output 38files, to reduce maximum compilation unit size and allow parallel compilation. 39 40Usage: 41aggregate_generated_bindings.py COMPONENT_DIR IDL_FILES_LIST -- OUTPUT_FILE1 OUTPUT_FILE2 ... 42 43COMPONENT_DIR is the relative directory of a component, e.g., 'core', 'modules'. 44IDL_FILES_LIST is a text file containing the IDL file paths, so the command 45line doesn't exceed OS length limits. 46OUTPUT_FILE1 etc. are filenames of output files. 47 48Design doc: http://www.chromium.org/developers/design-documents/idl-build 49""" 50 51import errno 52import os 53import re 54import subprocess 55import sys 56 57from utilities import idl_filename_to_interface_name 58 59# A regexp for finding Conditional attributes in interface definitions. 60CONDITIONAL_PATTERN = re.compile( 61 r'\[' 62 r'[^\]]*' 63 r'Conditional=([\_0-9a-zA-Z&|]*)' 64 r'[^\]]*' 65 r'\]\s*' 66 r'((callback|partial)\s+)?' 67 r'interface\s+' 68 r'\w+\s*' 69 r'(:\s*\w+\s*)?' 70 r'{', 71 re.MULTILINE) 72 73COPYRIGHT_TEMPLATE = """/* 74 * THIS FILE WAS AUTOMATICALLY GENERATED, DO NOT EDIT. 75 * 76 * This file was generated by the action_derivedsourcesallinone.py script. 77 * 78 * Copyright (C) 2009 Google Inc. All rights reserved. 79 * 80 * Redistribution and use in source and binary forms, with or without 81 * modification, are permitted provided that the following conditions 82 * are met: 83 * 1. Redistributions of source code must retain the above copyright 84 * notice, this list of conditions and the following disclaimer. 85 * 2. Redistributions in binary form must reproduce the above copyright 86 * notice, this list of conditions and the following disclaimer in the 87 * documentation and/or other materials provided with the distribution. 88 * 89 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 90 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 91 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 92 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 93 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 94 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 95 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 96 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 97 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 98 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 99 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 100 */ 101""" 102 103 104def format_conditional(conditional): 105 """Wraps conditional with ENABLE() and replace '&','|' with '&&','||' if 106 more than one conditional is specified.""" 107 def wrap_with_enable(s): 108 if s in ['|', '&']: 109 return s * 2 110 return 'ENABLE(' + s + ')' 111 return ' '.join(map(wrap_with_enable, conditional)) 112 113 114def extract_conditional(idl_file_path): 115 """Find [Conditional] interface extended attribute.""" 116 with open(idl_file_path) as idl_file: 117 idl_contents = idl_file.read() 118 119 match = CONDITIONAL_PATTERN.search(idl_contents) 120 if not match: 121 return None 122 conditional = match.group(1) 123 return re.split('([|&])', conditional) 124 125 126def extract_meta_data(file_paths): 127 """Extracts conditional and interface name from each IDL file.""" 128 meta_data_list = [] 129 130 for file_path in file_paths: 131 if not file_path.endswith('.idl'): 132 print 'WARNING: non-IDL file passed: "%s"' % file_path 133 continue 134 if not os.path.exists(file_path): 135 print 'WARNING: file not found: "%s"' % file_path 136 continue 137 138 # Extract interface name from file name 139 interface_name = idl_filename_to_interface_name(file_path) 140 141 meta_data = { 142 'conditional': extract_conditional(file_path), 143 'name': interface_name, 144 } 145 meta_data_list.append(meta_data) 146 147 return meta_data_list 148 149 150def generate_content(component_dir, files_meta_data_this_partition): 151 # Add fixed content. 152 output = [COPYRIGHT_TEMPLATE, 153 '#define NO_IMPLICIT_ATOMICSTRING\n\n'] 154 155 # List all includes segmented by if and endif. 156 prev_conditional = None 157 files_meta_data_this_partition.sort(key=lambda e: e['conditional']) 158 for meta_data in files_meta_data_this_partition: 159 conditional = meta_data['conditional'] 160 if prev_conditional != conditional: 161 if prev_conditional: 162 output.append('#endif\n') 163 if conditional: 164 output.append('\n#if %s\n' % format_conditional(conditional)) 165 prev_conditional = conditional 166 167 output.append('#include "bindings/%s/v8/V8%s.cpp"\n' % 168 (component_dir, meta_data['name'])) 169 170 if prev_conditional: 171 output.append('#endif\n') 172 173 return ''.join(output) 174 175 176def write_content(content, output_file_name): 177 parent_path, file_name = os.path.split(output_file_name) 178 if not os.path.exists(parent_path): 179 print 'Creating directory: %s' % parent_path 180 os.makedirs(parent_path) 181 with open(output_file_name, 'w') as f: 182 f.write(content) 183 184 185def resolve_cygpath(cygdrive_names): 186 if not cygdrive_names: 187 return [] 188 cmd = ['cygpath', '-f', '-', '-wa'] 189 process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 190 idl_file_names = [] 191 for file_name in cygdrive_names: 192 process.stdin.write('%s\n' % file_name) 193 process.stdin.flush() 194 idl_file_names.append(process.stdout.readline().rstrip()) 195 process.stdin.close() 196 process.wait() 197 return idl_file_names 198 199 200def main(args): 201 if len(args) <= 4: 202 raise Exception('Expected at least 5 arguments.') 203 component_dir = args[1] 204 input_file_name = args[2] 205 in_out_break_index = args.index('--') 206 output_file_names = args[in_out_break_index + 1:] 207 208 with open(input_file_name) as input_file: 209 file_names = sorted([os.path.realpath(line.rstrip('\n')) 210 for line in input_file]) 211 idl_file_names = [file_name for file_name in file_names 212 if not file_name.startswith('/cygdrive')] 213 cygdrive_names = [file_name for file_name in file_names 214 if file_name.startswith('/cygdrive')] 215 idl_file_names.extend(resolve_cygpath(cygdrive_names)) 216 217 files_meta_data = extract_meta_data(idl_file_names) 218 total_partitions = len(output_file_names) 219 for partition, file_name in enumerate(output_file_names): 220 files_meta_data_this_partition = [ 221 meta_data for meta_data in files_meta_data 222 if hash(meta_data['name']) % total_partitions == partition] 223 file_contents = generate_content(component_dir, 224 files_meta_data_this_partition) 225 write_content(file_contents, file_name) 226 227 228if __name__ == '__main__': 229 sys.exit(main(sys.argv)) 230