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# action_derivedsourceslist.py generates a single cpp file that includes
36# all v8 bindings cpp files generated from idls. Files can be assigned into
37# multiple output files, to reduce maximum compilation unit size and allow
38# parallel compilation.
39#
40# usage: action_derivedsourceslist.py IDL_FILES_LIST -- OUTPUT_FILE1 OUTPUT_FILE2 ...
41#
42# Note that IDL_FILES_LIST is a text file containing the IDL file paths.
43
44import errno
45import os
46import os.path
47import re
48import subprocess
49import sys
50
51# A regexp for finding Conditional attributes in interface definitions.
52conditionalPattern = re.compile('interface[\s]*\[[^\]]*Conditional=([\_0-9a-zA-Z&|]*)')
53
54copyrightTemplate = """/*
55 * THIS FILE WAS AUTOMATICALLY GENERATED, DO NOT EDIT.
56 *
57 * This file was generated by the make_jni_lists.py script.
58 *
59 * Copyright (C) 2009 Google Inc.  All rights reserved.
60 *
61 * Redistribution and use in source and binary forms, with or without
62 * modification, are permitted provided that the following conditions
63 * are met:
64 * 1. Redistributions of source code must retain the above copyright
65 *    notice, this list of conditions and the following disclaimer.
66 * 2. Redistributions in binary form must reproduce the above copyright
67 *    notice, this list of conditions and the following disclaimer in the
68 *    documentation and/or other materials provided with the distribution.
69 *
70 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
71 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
72 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
73 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
74 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
75 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
76 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
77 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
78 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
79 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
80 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
81 */
82"""
83
84
85# Wraps conditional with ENABLE() and replace '&','|' with '&&','||' if more than one conditional is specified.
86def formatConditional(conditional):
87    def wrapWithEnable(s):
88        if re.match('[|&]$', s):
89            return s * 2
90        return 'ENABLE(' + s + ')'
91    return ' '.join(map(wrapWithEnable, conditional))
92
93
94# Find the conditional interface attribute.
95def extractConditional(idlFilePath):
96    conditional = None
97
98    # Read file and look for "interface [ Conditional=XXX ]".
99    idlFile = open(idlFilePath)
100    idlContents = idlFile.read().replace('\n', '')
101    idlFile.close()
102
103    match = conditionalPattern.search(idlContents)
104    if match:
105        conditional = match.group(1)
106        conditional = re.split('([|&])', conditional)
107
108    return conditional
109
110# Extracts conditional and interface name from each IDL file.
111def extractMetaData(filePaths):
112    metaDataList = []
113
114    for f in filePaths:
115        metaData = {}
116        if len(f) == 0:
117            continue
118        if not os.path.exists(f):
119            print 'WARNING: file not found: "%s"' % f
120            continue
121
122        # Extract type name from file name
123        (parentPath, fileName) = os.path.split(f)
124        (interfaceName, ext) = os.path.splitext(fileName)
125
126        if not ext == '.idl':
127            continue
128
129        metaData = {
130            'conditional': extractConditional(f),
131            'name': interfaceName,
132        }
133
134        metaDataList.append(metaData)
135
136    return metaDataList
137
138
139def generateContent(filesMetaData, partition, totalPartitions):
140    # Sort files by conditionals.
141    filesMetaData.sort()
142
143    output = []
144
145    # Add fixed content.
146    output.append(copyrightTemplate)
147    output.append('#define NO_IMPLICIT_ATOMICSTRING\n\n')
148
149    # List all includes segmented by if and endif.
150    prevConditional = None
151    for metaData in filesMetaData:
152        name = metaData['name']
153        if (hash(name) % totalPartitions) != partition:
154            continue
155        conditional = metaData['conditional']
156
157        if prevConditional and prevConditional != conditional:
158            output.append('#endif\n')
159        if conditional and prevConditional != conditional:
160            output.append('\n#if %s\n' % formatConditional(conditional))
161
162        output.append('#include "bindings/V8%s.cpp"\n' % name)
163
164        prevConditional = conditional
165
166    if prevConditional:
167        output.append('#endif\n')
168
169    return ''.join(output)
170
171
172def writeContent(content, outputFileName):
173    (parentPath, fileName) = os.path.split(outputFileName)
174    if not os.path.exists(parentPath):
175        print parentPath
176        os.mkdir(parentPath)
177    f = open(outputFileName, 'w')
178    f.write(content)
179    f.close()
180
181
182def main(args):
183    assert(len(args) > 3)
184    inOutBreakIndex = args.index('--')
185    inputFileName = args[1]
186    outputFileNames = args[inOutBreakIndex+1:]
187
188    inputFile = open(inputFileName, 'r')
189    idlFileNames = inputFile.read().split('\n')
190    inputFile.close()
191
192    filesMetaData = extractMetaData(idlFileNames)
193    for fileName in outputFileNames:
194        print 'Generating derived sources list into %s...' % fileName
195        partition = outputFileNames.index(fileName)
196        fileContents = generateContent(filesMetaData, partition, len(outputFileNames))
197        writeContent(fileContents, fileName)
198
199    return 0
200
201
202if __name__ == '__main__':
203    sys.exit(main(sys.argv))
204