| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # | 2 # |
| 3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 """ Generator for C style prototypes and definitions """ | 7 """ Generator for C style prototypes and definitions """ |
| 8 | 8 |
| 9 import glob | 9 import glob |
| 10 import os | 10 import os |
| 11 import sys | 11 import sys |
| 12 import subprocess | 12 import subprocess |
| 13 | 13 |
| 14 from idl_log import ErrOut, InfoOut, WarnOut | 14 from idl_log import ErrOut, InfoOut, WarnOut |
| 15 from idl_node import IDLAttribute, IDLNode | 15 from idl_node import IDLAttribute, IDLNode |
| 16 from idl_ast import IDLAst | 16 from idl_ast import IDLAst |
| 17 from idl_option import GetOption, Option, ParseOptions | 17 from idl_option import GetOption, Option, ParseOptions |
| 18 from idl_outfile import IDLOutFile | 18 from idl_outfile import IDLOutFile |
| 19 from idl_parser import ParseFiles | 19 from idl_parser import ParseFiles |
| 20 from idl_c_proto import CGen | 20 from idl_c_proto import CGen, GetNodeComments, CommentLines, Comment |
| 21 from idl_generator import Generator | 21 from idl_generator import Generator, GeneratorByFile |
| 22 | 22 |
| 23 Option('dstroot', 'Base directory of output', default='../c') | 23 Option('dstroot', 'Base directory of output', default='../c') |
| 24 Option('guard', 'Include guard prefix', default='ppapi/c') | 24 Option('guard', 'Include guard prefix', default='ppapi/c') |
| 25 Option('out', 'List of output files', default='') | 25 Option('out', 'List of output files', default='') |
| 26 | 26 |
| 27 cgen = CGen() | 27 def GetOutFileName(filenode, relpath=None, prefix=None): |
| 28 | |
| 29 def IDLToHeader(filenode, relpath=None, prefix=None): | |
| 30 path, name = os.path.split(filenode.GetProperty('NAME')) | 28 path, name = os.path.split(filenode.GetProperty('NAME')) |
| 31 name = os.path.splitext(name)[0] + '.h' | 29 name = os.path.splitext(name)[0] + '.h' |
| 32 if prefix: name = '%s%s' % (prefix, name) | 30 if prefix: name = '%s%s' % (prefix, name) |
| 33 if path: name = os.path.join(path, name) | 31 if path: name = os.path.join(path, name) |
| 34 if relpath: name = os.path.join(relpath, name) | 32 if relpath: name = os.path.join(relpath, name) |
| 35 return name | 33 return name |
| 36 | 34 |
| 37 | 35 def WriteGroupMarker(out, node, last_group): |
| 38 def GenerateHeader(filenode, release, pref, inline=True): | 36 # If we are part of a group comment marker... |
| 39 name = filenode.GetProperty('NAME') | 37 if last_group and last_group != node.cls: |
| 40 # if name == 'pp_stdint.idl': return | 38 pre = CommentLines(['*',' @}', '']) + '\n' |
| 41 | 39 else: |
| 42 # If we have an 'out' filter list, then check if we should output this file. | 40 pre = '\n' |
| 43 outlist = GetOption('out') | 41 |
| 44 if outlist: | 42 if node.cls in ['Typedef', 'Interface', 'Struct', 'Enum']: |
| 45 outlist = outlist.split(',') | 43 if last_group != node.cls: |
| 46 if name not in outlist: | 44 pre += CommentLines(['*',' @addtogroup %ss' % node.cls, ' @{', '']) |
| 47 return | 45 last_group = node.cls |
| 48 | 46 else: |
| 49 savename = IDLToHeader(filenode, relpath=GetOption('dstroot'), prefix=pref) | 47 last_group = None |
| 50 out = IDLOutFile(savename) | 48 out.Write(pre) |
| 51 | 49 return last_group |
| 50 |
| 51 |
| 52 def GenerateHeader(out, filenode, releases): |
| 52 gpath = GetOption('guard') | 53 gpath = GetOption('guard') |
| 53 def_guard = IDLToHeader(filenode, relpath=gpath, prefix=pref) | 54 cgen = CGen() |
| 54 def_guard = def_guard.replace('/','_').replace('.','_').upper() + '_' | 55 pref = '' |
| 55 cright_node = filenode.GetChildren()[0] | 56 do_comments = True |
| 56 assert(cright_node.IsA('Copyright')) | |
| 57 | |
| 58 fileinfo = filenode.GetChildren()[1] | |
| 59 assert(fileinfo.IsA('Comment')) | |
| 60 | |
| 61 out.Write('%s\n' % cgen.Copyright(cright_node)) | |
| 62 out.Write('/* From %s modified %s. */\n\n'% ( | |
| 63 filenode.GetProperty('NAME'), filenode.GetProperty('DATETIME'))) | |
| 64 out.Write('#ifndef %s\n#define %s\n\n' % (def_guard, def_guard)) | |
| 65 | 57 |
| 66 for label in filenode.GetListOf('Label'): | 58 for label in filenode.GetListOf('Label'): |
| 67 if label.GetName() == GetOption('label'): | 59 if label.GetName() == GetOption('label'): |
| 68 cgen.SetVersionMap(label) | 60 cgen.SetVersionMap(label) |
| 69 | 61 |
| 70 deps = filenode.GetDeps(release) | |
| 71 # Generate set of includes | |
| 72 includes = set([]) | |
| 73 for dep in deps: | |
| 74 depfile = dep.GetProperty('FILE') | |
| 75 if depfile: | |
| 76 includes.add(depfile) | |
| 77 includes = [IDLToHeader(include, relpath=gpath) for include in includes] | |
| 78 includes.append('ppapi/c/pp_macros.h') | |
| 79 | |
| 80 # Assume we need stdint if we "include" C or C++ code | |
| 81 if filenode.GetListOf('Include'): | |
| 82 includes.append('ppapi/c/pp_stdint.h') | |
| 83 | |
| 84 includes = sorted(set(includes)) | |
| 85 cur_include = IDLToHeader(filenode, relpath=gpath) | |
| 86 for include in includes: | |
| 87 if include == cur_include: continue | |
| 88 out.Write('#include "%s"\n' % include) | |
| 89 | |
| 90 # Generate all interface defines | |
| 91 out.Write('\n') | |
| 92 for node in filenode.GetListOf('Interface'): | |
| 93 out.Write( cgen.InterfaceDefs(node) ) | |
| 94 | |
| 95 # Generate the @file comment | |
| 96 out.Write('%s\n' % cgen.Comment(fileinfo, prefix='*\n @file')) | |
| 97 | |
| 98 # Generate definitions. | 62 # Generate definitions. |
| 99 last_group = None | 63 last_group = None |
| 100 for node in filenode.GetChildren()[2:]: | 64 top_types = ['Typedef', 'Interface', 'Struct', 'Enum', 'Inline'] |
| 101 # If we are part of a group comment marker... | 65 for node in filenode.GetListOf(*top_types): |
| 102 if last_group and last_group != node.cls: | 66 # Skip if this node is not in this release |
| 103 pre = cgen.CommentLines(['*',' @}', '']) + '\n' | 67 if not node.InReleases(releases): |
| 104 else: | 68 print "Skiping %s" % node |
| 105 pre = '\n' | 69 continue |
| 106 | 70 |
| 107 if node.cls in ['Typedef', 'Interface', 'Struct', 'Enum']: | 71 # End/Start group marker |
| 108 if last_group != node.cls: | 72 if do_comments: |
| 109 pre += cgen.CommentLines(['*',' @addtogroup %ss' % node.cls, ' @{', '']) | 73 last_group = WriteGroupMarker(out, node, last_group) |
| 110 last_group = node.cls | 74 |
| 111 else: | 75 if node.IsA('Inline'): |
| 112 last_group = None | 76 item = node.GetProperty('VALUE') |
| 113 | 77 # If 'C++' use __cplusplus wrapper |
| 114 if node.IsA('Comment'): | |
| 115 item = '%s\n\n' % cgen.Comment(node) | |
| 116 elif node.IsA('Inline'): | |
| 117 if not inline: continue | |
| 118 if node.GetName() == 'cc': | 78 if node.GetName() == 'cc': |
| 119 item = cgen.Define(node, prefix=pref, comment=True) | |
| 120 item = '#ifdef __cplusplus\n%s\n#endif // __cplusplus\n\n' % item | 79 item = '#ifdef __cplusplus\n%s\n#endif // __cplusplus\n\n' % item |
| 121 elif node.GetName() == 'c': | 80 # If not C++ or C, then skip it |
| 122 item = cgen.Define(node, prefix=pref, comment=True) | 81 elif not node.GetName() == 'c': |
| 82 continue |
| 83 if item: out.Write(item) |
| 84 continue |
| 85 |
| 86 # |
| 87 # Otherwise we are defining a file level object, so generate the |
| 88 # correct document notation. |
| 89 # |
| 90 item = cgen.Define(node, releases, prefix=pref, comment=True) |
| 91 if not item: continue |
| 92 asize = node.GetProperty('assert_size()') |
| 93 if asize: |
| 94 name = '%s%s' % (pref, node.GetName()) |
| 95 if node.IsA('Struct'): |
| 96 form = 'PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(%s, %s);\n' |
| 123 else: | 97 else: |
| 124 continue | 98 form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n' |
| 125 if not item: continue | 99 item += form % (name, asize[0]) |
| 126 else: | 100 |
| 127 # | 101 if item: out.Write(item) |
| 128 # Otherwise we are defining a file level object, so generate the | |
| 129 # correct document notation. | |
| 130 # | |
| 131 item = cgen.Define(node, prefix=pref, comment=True) | |
| 132 if not item: continue | |
| 133 asize = node.GetProperty('assert_size()') | |
| 134 if asize: | |
| 135 name = '%s%s' % (pref, node.GetName()) | |
| 136 if node.IsA('Struct'): | |
| 137 form = 'PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(%s, %s);\n' | |
| 138 else: | |
| 139 form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n' | |
| 140 item += form % (name, asize[0]) | |
| 141 | |
| 142 if item: out.Write('%s%s' % (pre, item)) | |
| 143 if last_group: | 102 if last_group: |
| 144 out.Write(cgen.CommentLines(['*',' @}', '']) + '\n') | 103 out.Write(CommentLines(['*',' @}', '']) + '\n') |
| 145 | 104 |
| 146 out.Write('#endif /* %s */\n\n' % def_guard) | 105 |
| 147 return out.Close() | 106 class HGen(GeneratorByFile): |
| 148 | |
| 149 class HGen(Generator): | |
| 150 def __init__(self): | 107 def __init__(self): |
| 151 Generator.__init__(self, 'C Header', 'cgen', 'Generate the C headers.') | 108 Generator.__init__(self, 'C Header', 'cgen', 'Generate the C headers.') |
| 152 | 109 |
| 153 def GenerateVersion(self, ast, release, options): | 110 def GetMacro(self, node): |
| 154 outdir = GetOption('dstroot') | 111 name = node.GetName() |
| 155 skipList= [] | 112 name = name.upper() |
| 156 prefix = '' | 113 return "%s_INTERFACE" % name |
| 157 cfile = None | 114 |
| 158 cnt = 0 | 115 def GetDefine(self, name, value): |
| 159 | 116 out = '#define %s %s' % (name, value) |
| 160 for filenode in ast.GetListOf('File'): | 117 if len(out) > 80: |
| 161 if GetOption('verbose'): | 118 out = '#define %s \\\n %s' % (name, value) |
| 162 print "Working on %s" % filenode | 119 return '%s\n' % out |
| 163 | 120 |
| 164 # If this file has errors, skip it | 121 |
| 165 if filenode.GetProperty('ERRORS') > 0: | 122 def GetOutFile(self, filenode, options): |
| 166 skipList.append(filenode) | 123 savename = GetOutFileName(filenode, GetOption('dstroot')) |
| 167 continue | 124 return IDLOutFile(savename) |
| 168 | 125 |
| 169 if GenerateHeader(filenode, release, prefix): | 126 def GenerateHead(self, out, filenode, releases, options): |
| 170 cnt = cnt + 1 | 127 cgen = CGen() |
| 171 | 128 gpath = GetOption('guard') |
| 172 for filenode in skipList: | 129 release = releases[0] |
| 173 errcnt = filenode.GetProperty('ERRORS') | 130 def_guard = GetOutFileName(filenode, relpath=gpath) |
| 174 ErrOut.Log('%s : Skipped because of %d errors.' % ( | 131 def_guard = def_guard.replace('/','_').replace('.','_').upper() + '_' |
| 175 filenode.GetName(), errcnt)) | 132 |
| 176 | 133 cright_node = filenode.GetChildren()[0] |
| 177 if skipList: | 134 assert(cright_node.IsA('Copyright')) |
| 178 return -len(skipList) | 135 fileinfo = filenode.GetChildren()[1] |
| 179 | 136 assert(fileinfo.IsA('Comment')) |
| 180 if GetOption('diff'): | 137 |
| 181 return -cnt | 138 out.Write('%s\n' % cgen.Copyright(cright_node)) |
| 182 return cnt | 139 out.Write('/* From %s modified %s. */\n\n'% ( |
| 140 filenode.GetProperty('NAME'), filenode.GetProperty('DATETIME'))) |
| 141 out.Write('#ifndef %s\n#define %s\n\n' % (def_guard, def_guard)) |
| 142 # Generate set of includes |
| 143 |
| 144 deps = set() |
| 145 for release in releases: |
| 146 deps |= filenode.GetDeps(release) |
| 147 |
| 148 includes = set([]) |
| 149 for dep in deps: |
| 150 depfile = dep.GetProperty('FILE') |
| 151 if depfile: |
| 152 includes.add(depfile) |
| 153 includes = [GetOutFileName(include, relpath=gpath) for include in includes] |
| 154 includes.append('ppapi/c/pp_macros.h') |
| 155 |
| 156 # Assume we need stdint if we "include" C or C++ code |
| 157 if filenode.GetListOf('Include'): |
| 158 includes.append('ppapi/c/pp_stdint.h') |
| 159 |
| 160 includes = sorted(set(includes)) |
| 161 cur_include = GetOutFileName(filenode, relpath=gpath) |
| 162 for include in includes: |
| 163 if include == cur_include: continue |
| 164 out.Write('#include "%s"\n' % include) |
| 165 |
| 166 # Generate all interface defines |
| 167 out.Write('\n') |
| 168 for node in filenode.GetListOf('Interface'): |
| 169 idefs = '' |
| 170 name = node.GetName() |
| 171 macro = node.GetProperty('macro') |
| 172 if not macro: |
| 173 macro = self.GetMacro(node) |
| 174 label = node.GetLabel() |
| 175 if label: |
| 176 for vers in label.versions: |
| 177 strver = str(vers).replace('.', '_') |
| 178 idefs += self.GetDefine('%s_%s' % (macro, strver), |
| 179 '"%s;%s"' % (name, vers)) |
| 180 if label.GetRelease(vers) == releases[-1]: |
| 181 idefs += self.GetDefine(macro, '%s_%s' % (macro, strver)) |
| 182 idefs += '\n' |
| 183 out.Write(idefs) |
| 184 |
| 185 # Generate the @file comment |
| 186 out.Write('%s\n' % Comment(fileinfo, prefix='*\n @file')) |
| 187 |
| 188 def GenerateBody(self, out, filenode, releases, options): |
| 189 GenerateHeader(out, filenode, releases) |
| 190 |
| 191 def GenerateTail(self, out, filenode, releases, options): |
| 192 gpath = GetOption('guard') |
| 193 def_guard = GetOutFileName(filenode, relpath=gpath) |
| 194 def_guard = def_guard.replace('/','_').replace('.','_').upper() + '_' |
| 195 out.Write('#endif /* %s */\n\n' % def_guard) |
| 183 | 196 |
| 184 | 197 |
| 185 hgen = HGen() | 198 hgen = HGen() |
| 186 | 199 |
| 187 def Main(args): | 200 def Main(args): |
| 188 # Default invocation will verify the golden files are unchanged. | 201 # Default invocation will verify the golden files are unchanged. |
| 202 failed = 0 |
| 189 if not args: | 203 if not args: |
| 190 args = ['--wnone', '--diff', '--test', '--dstroot=.'] | 204 args = ['--wnone', '--diff', '--test', '--dstroot=.'] |
| 191 | 205 |
| 192 ParseOptions(args) | 206 ParseOptions(args) |
| 207 |
| 193 idldir = os.path.split(sys.argv[0])[0] | 208 idldir = os.path.split(sys.argv[0])[0] |
| 194 idldir = os.path.join(idldir, 'test_cgen', '*.idl') | 209 idldir = os.path.join(idldir, 'test_cgen', '*.idl') |
| 195 filenames = glob.glob(idldir) | 210 filenames = glob.glob(idldir) |
| 196 | |
| 197 ast = ParseFiles(filenames) | 211 ast = ParseFiles(filenames) |
| 198 return hgen.GenerateVersion(ast, 'M14', {}) | 212 if hgen.GenerateRelease(ast, 'M14', {}): |
| 213 print "Golden file for M14 failed." |
| 214 failed = 1 |
| 215 else: |
| 216 print "Golden file for M14 passed." |
| 217 |
| 218 |
| 219 idldir = os.path.split(sys.argv[0])[0] |
| 220 idldir = os.path.join(idldir, 'test_cgen_range', '*.idl') |
| 221 filenames = glob.glob(idldir) |
| 222 |
| 223 ast = ParseFiles(filenames) |
| 224 if hgen.GenerateRange(ast, ['M13', 'M14', 'M15'], {}): |
| 225 print "Golden file for M13-M15 failed." |
| 226 failed =1 |
| 227 else: |
| 228 print "Golden file for M13-M15 passed." |
| 229 |
| 230 return failed |
| 199 | 231 |
| 200 if __name__ == '__main__': | 232 if __name__ == '__main__': |
| 201 retval = Main(sys.argv[1:]) | 233 retval = Main(sys.argv[1:]) |
| 202 sys.exit(retval) | 234 sys.exit(retval) |
| 203 | 235 |
| OLD | NEW |