[email protected] | 4a41db5 | 2012-01-13 00:02:56 | [diff] [blame] | 1 | #!/usr/bin/env python |
[email protected] | dbf21cc | 2012-01-04 21:57:04 | [diff] [blame] | 2 | # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | f0dd202f | 2011-06-07 01:36:01 | [diff] [blame] | 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | """ Generator for C style prototypes and definitions """ |
| 7 | |
| 8 | import glob |
| 9 | import os |
[email protected] | 532d461a | 2012-05-11 18:21:20 | [diff] [blame] | 10 | import re |
[email protected] | f0dd202f | 2011-06-07 01:36:01 | [diff] [blame] | 11 | import sys |
| 12 | |
| 13 | from idl_log import ErrOut, InfoOut, WarnOut |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 14 | from idl_node import IDLAttribute, IDLNode |
| 15 | from idl_ast import IDLAst |
[email protected] | f0dd202f | 2011-06-07 01:36:01 | [diff] [blame] | 16 | from idl_option import GetOption, Option, ParseOptions |
| 17 | from idl_outfile import IDLOutFile |
| 18 | from idl_parser import ParseFiles |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 19 | from idl_c_proto import CGen, GetNodeComments, CommentLines, Comment |
| 20 | from idl_generator import Generator, GeneratorByFile |
[email protected] | f0dd202f | 2011-06-07 01:36:01 | [diff] [blame] | 21 | |
[email protected] | f93616a | 2011-10-04 22:54:22 | [diff] [blame] | 22 | Option('dstroot', 'Base directory of output', default=os.path.join('..', 'c')) |
| 23 | Option('guard', 'Include guard prefix', default=os.path.join('ppapi', 'c')) |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 24 | |
[email protected] | 406793d | 2011-11-14 22:26:54 | [diff] [blame] | 25 | |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 26 | def GetPathFromNode(filenode, relpath=None, ext=None): |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 27 | path, name = os.path.split(filenode.GetProperty('NAME')) |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 28 | if ext: name = os.path.splitext(name)[0] + ext |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 29 | if path: name = os.path.join(path, name) |
| 30 | if relpath: name = os.path.join(relpath, name) |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 31 | name = os.path.normpath(name) |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 32 | return name |
| 33 | |
[email protected] | 406793d | 2011-11-14 22:26:54 | [diff] [blame] | 34 | |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 35 | def GetHeaderFromNode(filenode, relpath=None): |
| 36 | return GetPathFromNode(filenode, relpath, ext='.h') |
| 37 | |
| 38 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 39 | def WriteGroupMarker(out, node, last_group): |
| 40 | # If we are part of a group comment marker... |
| 41 | if last_group and last_group != node.cls: |
| 42 | pre = CommentLines(['*',' @}', '']) + '\n' |
| 43 | else: |
| 44 | pre = '\n' |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 45 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 46 | if node.cls in ['Typedef', 'Interface', 'Struct', 'Enum']: |
| 47 | if last_group != node.cls: |
| 48 | pre += CommentLines(['*',' @addtogroup %ss' % node.cls, ' @{', '']) |
| 49 | last_group = node.cls |
| 50 | else: |
| 51 | last_group = None |
| 52 | out.Write(pre) |
| 53 | return last_group |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 54 | |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 55 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 56 | def GenerateHeader(out, filenode, releases): |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 57 | cgen = CGen() |
| 58 | pref = '' |
| 59 | do_comments = True |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 60 | |
| 61 | # Generate definitions. |
| 62 | last_group = None |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 63 | top_types = ['Typedef', 'Interface', 'Struct', 'Enum', 'Inline'] |
| 64 | for node in filenode.GetListOf(*top_types): |
| 65 | # Skip if this node is not in this release |
| 66 | if not node.InReleases(releases): |
| 67 | print "Skiping %s" % node |
| 68 | continue |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 69 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 70 | # End/Start group marker |
| 71 | if do_comments: |
| 72 | last_group = WriteGroupMarker(out, node, last_group) |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 73 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 74 | if node.IsA('Inline'): |
| 75 | item = node.GetProperty('VALUE') |
| 76 | # If 'C++' use __cplusplus wrapper |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 77 | if node.GetName() == 'cc': |
[email protected] | 8450e43 | 2012-11-06 03:33:46 | [diff] [blame] | 78 | item = '#ifdef __cplusplus\n%s\n#endif /* __cplusplus */\n\n' % item |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 79 | # If not C++ or C, then skip it |
| 80 | elif not node.GetName() == 'c': |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 81 | continue |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 82 | if item: out.Write(item) |
| 83 | continue |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 84 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 85 | # |
| 86 | # Otherwise we are defining a file level object, so generate the |
| 87 | # correct document notation. |
| 88 | # |
| 89 | item = cgen.Define(node, releases, prefix=pref, comment=True) |
| 90 | if not item: continue |
| 91 | asize = node.GetProperty('assert_size()') |
| 92 | if asize: |
| 93 | name = '%s%s' % (pref, node.GetName()) |
| 94 | if node.IsA('Struct'): |
| 95 | form = 'PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(%s, %s);\n' |
[email protected] | 03f41ec | 2011-11-18 22:53:04 | [diff] [blame] | 96 | elif node.IsA('Enum'): |
| 97 | if node.GetProperty('notypedef'): |
| 98 | form = 'PP_COMPILE_ASSERT_ENUM_SIZE_IN_BYTES(%s, %s);\n' |
| 99 | else: |
| 100 | form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n' |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 101 | else: |
| 102 | form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n' |
| 103 | item += form % (name, asize[0]) |
| 104 | |
| 105 | if item: out.Write(item) |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 106 | if last_group: |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 107 | out.Write(CommentLines(['*',' @}', '']) + '\n') |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 108 | |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 109 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 110 | class HGen(GeneratorByFile): |
[email protected] | acc3d8e | 2011-08-22 22:17:40 | [diff] [blame] | 111 | def __init__(self): |
| 112 | Generator.__init__(self, 'C Header', 'cgen', 'Generate the C headers.') |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 113 | |
[email protected] | 406793d | 2011-11-14 22:26:54 | [diff] [blame] | 114 | def GenerateFile(self, filenode, releases, options): |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 115 | savename = GetHeaderFromNode(filenode, GetOption('dstroot')) |
[email protected] | 98cfdfc | 2012-10-23 18:10:02 | [diff] [blame] | 116 | my_min, my_max = filenode.GetMinMax(releases) |
| 117 | if my_min > releases[-1] or my_max < releases[0]: |
[email protected] | 55e1a70 | 2012-01-10 17:55:17 | [diff] [blame] | 118 | if os.path.isfile(savename): |
| 119 | print "Removing stale %s for this range." % filenode.GetName() |
| 120 | os.remove(os.path.realpath(savename)) |
| 121 | return False |
| 122 | |
[email protected] | 406793d | 2011-11-14 22:26:54 | [diff] [blame] | 123 | out = IDLOutFile(savename) |
| 124 | self.GenerateHead(out, filenode, releases, options) |
| 125 | self.GenerateBody(out, filenode, releases, options) |
| 126 | self.GenerateTail(out, filenode, releases, options) |
| 127 | return out.Close() |
[email protected] | f0dd202f | 2011-06-07 01:36:01 | [diff] [blame] | 128 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 129 | def GenerateHead(self, out, filenode, releases, options): |
[email protected] | 406793d | 2011-11-14 22:26:54 | [diff] [blame] | 130 | __pychecker__ = 'unusednames=options' |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 131 | cgen = CGen() |
| 132 | gpath = GetOption('guard') |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 133 | def_guard = GetHeaderFromNode(filenode, relpath=gpath) |
[email protected] | f93616a | 2011-10-04 22:54:22 | [diff] [blame] | 134 | def_guard = def_guard.replace(os.sep,'_').replace('.','_').upper() + '_' |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 135 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 136 | cright_node = filenode.GetChildren()[0] |
| 137 | assert(cright_node.IsA('Copyright')) |
| 138 | fileinfo = filenode.GetChildren()[1] |
| 139 | assert(fileinfo.IsA('Comment')) |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 140 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 141 | out.Write('%s\n' % cgen.Copyright(cright_node)) |
[email protected] | dbf21cc | 2012-01-04 21:57:04 | [diff] [blame] | 142 | |
| 143 | # Wrap the From ... modified ... comment if it would be >80 characters. |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 144 | from_text = 'From %s' % GetPathFromNode(filenode) |
[email protected] | dbf21cc | 2012-01-04 21:57:04 | [diff] [blame] | 145 | modified_text = 'modified %s.' % ( |
| 146 | filenode.GetProperty('DATETIME')) |
| 147 | if len(from_text) + len(modified_text) < 74: |
| 148 | out.Write('/* %s %s */\n\n' % (from_text, modified_text)) |
| 149 | else: |
| 150 | out.Write('/* %s,\n * %s\n */\n\n' % (from_text, modified_text)) |
| 151 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 152 | out.Write('#ifndef %s\n#define %s\n\n' % (def_guard, def_guard)) |
| 153 | # Generate set of includes |
| 154 | |
| 155 | deps = set() |
| 156 | for release in releases: |
| 157 | deps |= filenode.GetDeps(release) |
| 158 | |
| 159 | includes = set([]) |
| 160 | for dep in deps: |
| 161 | depfile = dep.GetProperty('FILE') |
| 162 | if depfile: |
| 163 | includes.add(depfile) |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 164 | includes = [GetHeaderFromNode( |
[email protected] | f93616a | 2011-10-04 22:54:22 | [diff] [blame] | 165 | include, relpath=gpath).replace(os.sep, '/') for include in includes] |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 166 | includes.append('ppapi/c/pp_macros.h') |
| 167 | |
| 168 | # Assume we need stdint if we "include" C or C++ code |
| 169 | if filenode.GetListOf('Include'): |
| 170 | includes.append('ppapi/c/pp_stdint.h') |
| 171 | |
| 172 | includes = sorted(set(includes)) |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 173 | cur_include = GetHeaderFromNode(filenode, |
| 174 | relpath=gpath).replace(os.sep, '/') |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 175 | for include in includes: |
| 176 | if include == cur_include: continue |
| 177 | out.Write('#include "%s"\n' % include) |
| 178 | |
[email protected] | 532d461a | 2012-05-11 18:21:20 | [diff] [blame] | 179 | # If we are generating a single release, then create a macro for the highest |
| 180 | # available release number. |
| 181 | if filenode.GetProperty('NAME').endswith('pp_macros.idl'): |
| 182 | releasestr = GetOption('release') |
| 183 | if releasestr: |
| 184 | release_numbers = re.findall('\d+', releasestr) |
| 185 | if release_numbers: |
| 186 | out.Write('\n#define PPAPI_RELEASE %s\n' % release_numbers[0]) |
| 187 | |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 188 | # Generate all interface defines |
| 189 | out.Write('\n') |
| 190 | for node in filenode.GetListOf('Interface'): |
| 191 | idefs = '' |
[email protected] | 406793d | 2011-11-14 22:26:54 | [diff] [blame] | 192 | macro = cgen.GetInterfaceMacro(node) |
[email protected] | 55e1a70 | 2012-01-10 17:55:17 | [diff] [blame] | 193 | unique = node.GetUniqueReleases(releases) |
| 194 | |
| 195 | # Skip this interface if there are no matching versions |
| 196 | if not unique: continue |
| 197 | |
| 198 | for rel in unique: |
[email protected] | e8a83feb | 2011-08-25 21:04:26 | [diff] [blame] | 199 | version = node.GetVersion(rel) |
[email protected] | 406793d | 2011-11-14 22:26:54 | [diff] [blame] | 200 | name = cgen.GetInterfaceString(node, version) |
[email protected] | e8a83feb | 2011-08-25 21:04:26 | [diff] [blame] | 201 | strver = str(version).replace('.', '_') |
[email protected] | 406793d | 2011-11-14 22:26:54 | [diff] [blame] | 202 | idefs += cgen.GetDefine('%s_%s' % (macro, strver), '"%s"' % name) |
| 203 | idefs += cgen.GetDefine(macro, '%s_%s' % (macro, strver)) + '\n' |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 204 | out.Write(idefs) |
| 205 | |
| 206 | # Generate the @file comment |
| 207 | out.Write('%s\n' % Comment(fileinfo, prefix='*\n @file')) |
| 208 | |
| 209 | def GenerateBody(self, out, filenode, releases, options): |
[email protected] | 406793d | 2011-11-14 22:26:54 | [diff] [blame] | 210 | __pychecker__ = 'unusednames=options' |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 211 | GenerateHeader(out, filenode, releases) |
| 212 | |
| 213 | def GenerateTail(self, out, filenode, releases, options): |
[email protected] | 406793d | 2011-11-14 22:26:54 | [diff] [blame] | 214 | __pychecker__ = 'unusednames=options,releases' |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 215 | gpath = GetOption('guard') |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 216 | def_guard = GetPathFromNode(filenode, relpath=gpath, ext='.h') |
[email protected] | f93616a | 2011-10-04 22:54:22 | [diff] [blame] | 217 | def_guard = def_guard.replace(os.sep,'_').replace('.','_').upper() + '_' |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 218 | out.Write('#endif /* %s */\n\n' % def_guard) |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 219 | |
[email protected] | 5eef288 | 2011-07-19 00:08:54 | [diff] [blame] | 220 | |
[email protected] | acc3d8e | 2011-08-22 22:17:40 | [diff] [blame] | 221 | hgen = HGen() |
| 222 | |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 223 | def main(args): |
[email protected] | acc3d8e | 2011-08-22 22:17:40 | [diff] [blame] | 224 | # Default invocation will verify the golden files are unchanged. |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 225 | failed = 0 |
[email protected] | acc3d8e | 2011-08-22 22:17:40 | [diff] [blame] | 226 | if not args: |
| 227 | args = ['--wnone', '--diff', '--test', '--dstroot=.'] |
| 228 | |
| 229 | ParseOptions(args) |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 230 | |
[email protected] | acc3d8e | 2011-08-22 22:17:40 | [diff] [blame] | 231 | idldir = os.path.split(sys.argv[0])[0] |
| 232 | idldir = os.path.join(idldir, 'test_cgen', '*.idl') |
| 233 | filenames = glob.glob(idldir) |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 234 | ast = ParseFiles(filenames) |
| 235 | if hgen.GenerateRelease(ast, 'M14', {}): |
| 236 | print "Golden file for M14 failed." |
| 237 | failed = 1 |
| 238 | else: |
| 239 | print "Golden file for M14 passed." |
| 240 | |
| 241 | |
| 242 | idldir = os.path.split(sys.argv[0])[0] |
| 243 | idldir = os.path.join(idldir, 'test_cgen_range', '*.idl') |
| 244 | filenames = glob.glob(idldir) |
[email protected] | acc3d8e | 2011-08-22 22:17:40 | [diff] [blame] | 245 | |
| 246 | ast = ParseFiles(filenames) |
[email protected] | f731473 | 2011-08-24 23:03:06 | [diff] [blame] | 247 | if hgen.GenerateRange(ast, ['M13', 'M14', 'M15'], {}): |
| 248 | print "Golden file for M13-M15 failed." |
| 249 | failed =1 |
| 250 | else: |
| 251 | print "Golden file for M13-M15 passed." |
| 252 | |
| 253 | return failed |
[email protected] | f0dd202f | 2011-06-07 01:36:01 | [diff] [blame] | 254 | |
| 255 | if __name__ == '__main__': |
[email protected] | 6faeb20 | 2012-12-06 15:43:05 | [diff] [blame] | 256 | sys.exit(main(sys.argv[1:])) |
[email protected] | 55e1a70 | 2012-01-10 17:55:17 | [diff] [blame] | 257 | |