| 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 |
| 21 from idl_generator import Generator |
| 21 | 22 |
| 22 Option('dstroot', 'Base directory of output', default='../c') | 23 Option('dstroot', 'Base directory of output', default='../c') |
| 23 Option('guard', 'Include guard prefix', default='ppapi/c') | 24 Option('guard', 'Include guard prefix', default='ppapi/c') |
| 24 Option('out', 'List of output files', default='') | 25 Option('out', 'List of output files', default='') |
| 25 | 26 |
| 26 cgen = CGen() | 27 cgen = CGen() |
| 27 | 28 |
| 28 def IDLToHeader(filenode, relpath=None, prefix=None): | 29 def IDLToHeader(filenode, relpath=None, prefix=None): |
| 29 path, name = os.path.split(filenode.GetProperty('NAME')) | 30 path, name = os.path.split(filenode.GetProperty('NAME')) |
| 30 name = os.path.splitext(name)[0] + '.h' | 31 name = os.path.splitext(name)[0] + '.h' |
| 31 if prefix: name = '%s%s' % (prefix, name) | 32 if prefix: name = '%s%s' % (prefix, name) |
| 32 if path: name = os.path.join(path, name) | 33 if path: name = os.path.join(path, name) |
| 33 if relpath: name = os.path.join(relpath, name) | 34 if relpath: name = os.path.join(relpath, name) |
| 34 return name | 35 return name |
| 35 | 36 |
| 36 | 37 |
| 37 def GenerateHeader(filenode, pref, inline=True): | 38 def GenerateHeader(filenode, release, pref, inline=True): |
| 38 name = filenode.GetProperty('NAME') | 39 name = filenode.GetProperty('NAME') |
| 39 # if name == 'pp_stdint.idl': return | 40 # if name == 'pp_stdint.idl': return |
| 40 | 41 |
| 41 # If we have an 'out' filter list, then check if we should output this file. | 42 # If we have an 'out' filter list, then check if we should output this file. |
| 42 outlist = GetOption('out') | 43 outlist = GetOption('out') |
| 43 if outlist: | 44 if outlist: |
| 44 outlist = outlist.split(',') | 45 outlist = outlist.split(',') |
| 45 if name not in outlist: | 46 if name not in outlist: |
| 46 return | 47 return |
| 47 | 48 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 59 | 60 |
| 60 out.Write('%s\n' % cgen.Copyright(cright_node)) | 61 out.Write('%s\n' % cgen.Copyright(cright_node)) |
| 61 out.Write('/* From %s modified %s. */\n\n'% ( | 62 out.Write('/* From %s modified %s. */\n\n'% ( |
| 62 filenode.GetProperty('NAME'), filenode.GetProperty('DATETIME'))) | 63 filenode.GetProperty('NAME'), filenode.GetProperty('DATETIME'))) |
| 63 out.Write('#ifndef %s\n#define %s\n\n' % (def_guard, def_guard)) | 64 out.Write('#ifndef %s\n#define %s\n\n' % (def_guard, def_guard)) |
| 64 | 65 |
| 65 for label in filenode.GetListOf('Label'): | 66 for label in filenode.GetListOf('Label'): |
| 66 if label.GetName() == GetOption('label'): | 67 if label.GetName() == GetOption('label'): |
| 67 cgen.SetVersionMap(label) | 68 cgen.SetVersionMap(label) |
| 68 | 69 |
| 69 deps = filenode.GetDeps('M14') | 70 deps = filenode.GetDeps(release) |
| 70 # Generate set of includes | 71 # Generate set of includes |
| 71 includes = set([]) | 72 includes = set([]) |
| 72 for dep in deps: | 73 for dep in deps: |
| 73 depfile = dep.GetProperty('FILE') | 74 depfile = dep.GetProperty('FILE') |
| 74 if depfile: | 75 if depfile: |
| 75 includes.add(depfile) | 76 includes.add(depfile) |
| 76 includes = [IDLToHeader(include, relpath=gpath) for include in includes] | 77 includes = [IDLToHeader(include, relpath=gpath) for include in includes] |
| 77 includes.append('ppapi/c/pp_macros.h') | 78 includes.append('ppapi/c/pp_macros.h') |
| 78 | 79 |
| 79 # Assume we need stdint if we "include" C or C++ code | 80 # Assume we need stdint if we "include" C or C++ code |
| 80 if filenode.GetListOf('Include'): | 81 if filenode.GetListOf('Include'): |
| 81 includes.append('ppapi/c/pp_stdint.h') | 82 includes.append('ppapi/c/pp_stdint.h') |
| 82 | 83 |
| 83 includes = sorted(set(includes)) | 84 includes = sorted(set(includes)) |
| 84 cur_include = IDLToHeader(filenode, relpath=gpath) | 85 cur_include = IDLToHeader(filenode, relpath=gpath) |
| 85 for include in includes: | 86 for include in includes: |
| 86 if include == cur_include: continue | 87 if include == cur_include: continue |
| 87 out.Write('#include "%s"\n' % include) | 88 out.Write('#include "%s"\n' % include) |
| 88 | 89 |
| 89 # Generate all interface defines | 90 # Generate all interface defines |
| 90 release = 'M14' | |
| 91 out.Write('\n') | 91 out.Write('\n') |
| 92 for node in filenode.GetListOf('Interface'): | 92 for node in filenode.GetListOf('Interface'): |
| 93 out.Write( cgen.InterfaceDefs(node) ) | 93 out.Write( cgen.InterfaceDefs(node) ) |
| 94 | 94 |
| 95 # Generate the @file comment | 95 # Generate the @file comment |
| 96 out.Write('%s\n' % cgen.Comment(fileinfo, prefix='*\n @file')) | 96 out.Write('%s\n' % cgen.Comment(fileinfo, prefix='*\n @file')) |
| 97 | 97 |
| 98 # Generate definitions. | 98 # Generate definitions. |
| 99 last_group = None | 99 last_group = None |
| 100 for node in filenode.GetChildren()[2:]: | 100 for node in filenode.GetChildren()[2:]: |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 form = 'PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(%s, %s);\n' | 137 form = 'PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(%s, %s);\n' |
| 138 else: | 138 else: |
| 139 form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n' | 139 form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n' |
| 140 item += form % (name, asize[0]) | 140 item += form % (name, asize[0]) |
| 141 | 141 |
| 142 if item: out.Write('%s%s' % (pre, item)) | 142 if item: out.Write('%s%s' % (pre, item)) |
| 143 if last_group: | 143 if last_group: |
| 144 out.Write(cgen.CommentLines(['*',' @}', '']) + '\n') | 144 out.Write(cgen.CommentLines(['*',' @}', '']) + '\n') |
| 145 | 145 |
| 146 out.Write('#endif /* %s */\n\n' % def_guard) | 146 out.Write('#endif /* %s */\n\n' % def_guard) |
| 147 out.Close() | 147 return out.Close() |
| 148 |
| 149 class HGen(Generator): |
| 150 def __init__(self): |
| 151 Generator.__init__(self, 'C Header', 'cgen', 'Generate the C headers.') |
| 152 |
| 153 def GenerateVersion(self, ast, release, options): |
| 154 outdir = GetOption('dstroot') |
| 155 skipList= [] |
| 156 prefix = '' |
| 157 cfile = None |
| 158 cnt = 0 |
| 159 |
| 160 for filenode in ast.GetListOf('File'): |
| 161 if GetOption('verbose'): |
| 162 print "Working on %s" % filenode |
| 163 |
| 164 # If this file has errors, skip it |
| 165 if filenode.GetProperty('ERRORS') > 0: |
| 166 skipList.append(filenode) |
| 167 continue |
| 168 |
| 169 if GenerateHeader(filenode, release, prefix): |
| 170 cnt = cnt + 1 |
| 171 |
| 172 for filenode in skipList: |
| 173 errcnt = filenode.GetProperty('ERRORS') |
| 174 ErrOut.Log('%s : Skipped because of %d errors.' % ( |
| 175 filenode.GetName(), errcnt)) |
| 176 |
| 177 if skipList: |
| 178 return -len(skipList) |
| 179 |
| 180 if GetOption('diff'): |
| 181 return -cnt |
| 182 return cnt |
| 148 | 183 |
| 149 | 184 |
| 150 def GenerateFileTest(cfile, filenode, pref): | 185 hgen = HGen() |
| 151 tests = [] | |
| 152 original = IDLToHeader(filenode, relpath='') | |
| 153 savename = IDLToHeader(filenode, relpath='', prefix=pref) | |
| 154 cfile.Write('/* Test %s */\n' % filenode.GetProperty('NAME')) | |
| 155 cfile.Write('#include "%s"\n' % original) | |
| 156 cfile.Write('#include "%s"\n' % savename) | |
| 157 | |
| 158 # For all children (excluding copyright notice) | |
| 159 for node in filenode.children[1:]: | |
| 160 # Test enums by assigning all enum items to themselves. Unfortunately this | |
| 161 # will not catch cases where the '.h' has enums that the IDL does not. | |
| 162 if node.IsA('Enum'): | |
| 163 tests.append('test_%s' % node.GetProperty('NAME')) | |
| 164 cfile.Write('int test_%s() {\n' % node.GetProperty('NAME')) | |
| 165 cfile.Write(' int errors = 0;\n') | |
| 166 for enum in node.GetListOf('EnumItem'): | |
| 167 cfile.Write(' errors += VERIFY_ENUM(%s, %s%s);\n' % | |
| 168 (enum.GetProperty('NAME'), pref, enum.GetProperty('NAME'))) | |
| 169 cfile.Write(' if (errors) printf("Failure in %s:%s.\\n");\n' % | |
| 170 (filenode.GetName(), node.GetName())) | |
| 171 cfile.Write(' return errors;\n}\n\n') | |
| 172 continue | |
| 173 | |
| 174 # Use a structure asignment to verify equivilency | |
| 175 if node.IsA('Interface', 'Struct'): | |
| 176 tests.append('test_%s' % node.GetName()) | |
| 177 rtype1 = cgen.GetTypeName(node) | |
| 178 rtype2 = cgen.GetTypeName(node, prefix='tst_') | |
| 179 cfile.Write('int test_%s() {\n' % node.GetName()) | |
| 180 cfile.Write(' int errors = 0;\n'); | |
| 181 cmp_structs = ' %s A;\n %s B;\n' % (rtype1, rtype2) | |
| 182 cfile.Write(cmp_structs) | |
| 183 cfile.Write(' memset(&A, 0, sizeof(A));\n') | |
| 184 cfile.Write(' memset(&B, 1, sizeof(B));\n') | |
| 185 for member in node.GetListOf('Member', 'Function'): | |
| 186 if member.GetOneOf('Array'): | |
| 187 cfile.Write(' memcpy(A.%s, B.%s, sizeof(A.%s));\n' % | |
| 188 (member.GetName(), member.GetName(), member.GetName())) | |
| 189 else: | |
| 190 cfile.Write(' A.%s = B.%s;\n' % (member.GetName(), member.GetName())) | |
| 191 cfile.Write(' errors += (sizeof(A) != sizeof(B)) ? 1 : 0;\n') | |
| 192 cfile.Write(' errors += (memcmp(&A, &B, sizeof(A))) ? 1 : 0;\n') | |
| 193 cfile.Write(' return (sizeof(A) == sizeof(B));\n}\n') | |
| 194 continue | |
| 195 | |
| 196 cfile.Write('\n\n') | |
| 197 return tests | |
| 198 | |
| 199 def GenerateBaseTest(cfile): | |
| 200 for inc in ['<stdio.h>','<string.h>','"pp_stdint.h"']: | |
| 201 cfile.Write('#include %s\n' % inc) | |
| 202 cfile.Write('\n') | |
| 203 cfile.Write('#define VERIFY_ENUM(orig, idl) Check(#orig, orig, idl)\n\n') | |
| 204 cfile.Write('int Check(const char *name, int v1, int v2) {\n') | |
| 205 cfile.Write(' if (v1 == v2) return 0;\n') | |
| 206 cfile.Write(' printf("Mismatch enum %s : %d vs %d\\n", name, v1, v2);\n') | |
| 207 cfile.Write(' return 1;\n}\n\n') | |
| 208 | |
| 209 | 186 |
| 210 def Main(args): | 187 def Main(args): |
| 211 filenames = ParseOptions(args) | 188 # Default invocation will verify the golden files are unchanged. |
| 189 if not args: |
| 190 args = ['--wnone', '--diff', '--test', '--dstroot=.'] |
| 191 |
| 192 ParseOptions(args) |
| 193 idldir = os.path.split(sys.argv[0])[0] |
| 194 idldir = os.path.join(idldir, 'test_cgen', '*.idl') |
| 195 filenames = glob.glob(idldir) |
| 196 |
| 212 ast = ParseFiles(filenames) | 197 ast = ParseFiles(filenames) |
| 213 testFuncs = [] | 198 return hgen.GenerateVersion(ast, 'M14', {}) |
| 214 skipList = [] | |
| 215 | |
| 216 outdir = GetOption('dstroot') | |
| 217 | |
| 218 if GetOption('test'): | |
| 219 prefix = 'tst_' | |
| 220 cfile = IDLOutFile(os.path.join(outdir, 'test.c')) | |
| 221 GenerateBaseTest(cfile) | |
| 222 else: | |
| 223 prefix = '' | |
| 224 cfile = None | |
| 225 | |
| 226 for filenode in ast.GetListOf('File'): | |
| 227 if GetOption('verbose'): | |
| 228 print "Working on %s" % filenode | |
| 229 | |
| 230 # If this file has errors, skip it | |
| 231 if filenode.GetProperty('ERRORS') > 0: | |
| 232 skipList.append(filenode) | |
| 233 continue | |
| 234 | |
| 235 GenerateHeader(filenode, prefix, inline=not cfile) | |
| 236 if cfile: GenerateFileTest(cfile, filenode, prefix) | |
| 237 | |
| 238 if cfile: | |
| 239 cfile.Write('int main(int argc, const char *args[]) {\n') | |
| 240 cfile.Write(' int errors = 0;\n'); | |
| 241 for testname in testFuncs: | |
| 242 cfile.Write(' errors += %s();\n' % testname) | |
| 243 | |
| 244 cfile.Write(' printf("Found %d error(s) in the IDL.\\n", errors);\n') | |
| 245 cfile.Write(' return errors;\n}\n\n') | |
| 246 cfile.Close() | |
| 247 | |
| 248 # TODO(noelallen) Add a standard test | |
| 249 if not skipList: | |
| 250 args = ['gcc', '-o', 'tester', '%s/test.c' % outdir, '-I%s' % outdir, | |
| 251 '-I../c', '-I../..', '-DPPAPI_INSTANCE_REMOVE_SCRIPTING'] | |
| 252 InfoOut.Log('Running: %s' % ' '.join(args)) | |
| 253 ret = subprocess.call(args) | |
| 254 if ret: | |
| 255 ErrOut.Log('Failed to compile.') | |
| 256 return -1 | |
| 257 InfoOut.Log('Running: ./tester') | |
| 258 ret = subprocess.call('./tester') | |
| 259 if ret > 0: | |
| 260 ErrOut.Log('Found %d errors.' % ret) | |
| 261 return ret | |
| 262 InfoOut.Log('Success!') | |
| 263 return 0 | |
| 264 | |
| 265 for filenode in skipList: | |
| 266 errcnt = filenode.GetProperty('ERRORS') | |
| 267 ErrOut.Log('%s : Skipped because of %d errors.' % ( | |
| 268 filenode.GetName(), errcnt)) | |
| 269 | |
| 270 if not skipList: | |
| 271 InfoOut.Log('Processed %d files.' % len(ast.GetListOf('File'))) | |
| 272 return len(skipList) | |
| 273 | 199 |
| 274 if __name__ == '__main__': | 200 if __name__ == '__main__': |
| 275 sys.exit(Main(sys.argv[1:])) | 201 retval = Main(sys.argv[1:]) |
| 202 sys.exit(retval) |
| 276 | 203 |
| OLD | NEW |