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