1 #!/usr/bin/env python 2 # 3 # Copyright (c) 2013-2016 The Khronos Group Inc. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 import sys, time, pdb, string, cProfile 18 from reg import * 19 from generator import write, CGeneratorOptions, COutputGenerator, DocGeneratorOptions, DocOutputGenerator, PyOutputGenerator, ValidityOutputGenerator, HostSynchronizationOutputGenerator, ThreadGeneratorOptions, ThreadOutputGenerator 20 from generator import ParamCheckerGeneratorOptions, ParamCheckerOutputGenerator 21 22 # debug - start header generation in debugger 23 # dump - dump registry after loading 24 # profile - enable Python profiling 25 # protect - whether to use #ifndef protections 26 # registry <filename> - use specified XML registry instead of gl.xml 27 # target - string name of target header, or all targets if None 28 # timeit - time length of registry loading & header generation 29 # validate - validate return & parameter group tags against <group> 30 debug = False 31 dump = False 32 profile = False 33 protect = True 34 target = None 35 timeit = False 36 validate= False 37 # Default input / log files 38 errFilename = None 39 diagFilename = 'diag.txt' 40 regFilename = 'vk.xml' 41 outDir = '.' 42 43 if __name__ == '__main__': 44 i = 1 45 while (i < len(sys.argv)): 46 arg = sys.argv[i] 47 i = i + 1 48 if (arg == '-debug'): 49 write('Enabling debug (-debug)', file=sys.stderr) 50 debug = True 51 elif (arg == '-dump'): 52 write('Enabling dump (-dump)', file=sys.stderr) 53 dump = True 54 elif (arg == '-noprotect'): 55 write('Disabling inclusion protection in output headers', file=sys.stderr) 56 protect = False 57 elif (arg == '-profile'): 58 write('Enabling profiling (-profile)', file=sys.stderr) 59 profile = True 60 elif (arg == '-registry'): 61 regFilename = sys.argv[i] 62 i = i+1 63 write('Using registry ', regFilename, file=sys.stderr) 64 elif (arg == '-time'): 65 write('Enabling timing (-time)', file=sys.stderr) 66 timeit = True 67 elif (arg == '-validate'): 68 write('Enabling group validation (-validate)', file=sys.stderr) 69 validate = True 70 elif (arg == '-outdir'): 71 outDir = sys.argv[i] 72 i = i+1 73 write('Using output directory ', outDir, file=sys.stderr) 74 elif (arg[0:1] == '-'): 75 write('Unrecognized argument:', arg, file=sys.stderr) 76 exit(1) 77 else: 78 target = arg 79 write('Using target', target, file=sys.stderr) 80 81 # Simple timer functions 82 startTime = None 83 def startTimer(): 84 global startTime 85 startTime = time.clock() 86 def endTimer(msg): 87 global startTime 88 endTime = time.clock() 89 if (timeit): 90 write(msg, endTime - startTime) 91 startTime = None 92 93 # Load & parse registry 94 reg = Registry() 95 96 startTimer() 97 tree = etree.parse(regFilename) 98 endTimer('Time to make ElementTree =') 99 100 startTimer() 101 reg.loadElementTree(tree) 102 endTimer('Time to parse ElementTree =') 103 104 if (validate): 105 reg.validateGroups() 106 107 if (dump): 108 write('***************************************') 109 write('Performing Registry dump to regdump.txt') 110 write('***************************************') 111 reg.dumpReg(filehandle = open('regdump.txt','w')) 112 113 # Turn a list of strings into a regexp string matching exactly those strings 114 def makeREstring(list): 115 return '^(' + '|'.join(list) + ')$' 116 117 # Descriptive names for various regexp patterns used to select 118 # versions and extensions 119 allVersions = allExtensions = '.*' 120 noVersions = noExtensions = None 121 122 # Copyright text prefixing all headers (list of strings). 123 prefixStrings = [ 124 '/*', 125 '** Copyright (c) 2015-2016 The Khronos Group Inc.', 126 '**', 127 '** Licensed under the Apache License, Version 2.0 (the "License");', 128 '** you may not use this file except in compliance with the License.', 129 '** You may obtain a copy of the License at', 130 '**', 131 '** http://www.apache.org/licenses/LICENSE-2.0', 132 '**', 133 '** Unless required by applicable law or agreed to in writing, software', 134 '** distributed under the License is distributed on an "AS IS" BASIS,', 135 '** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.', 136 '** See the License for the specific language governing permissions and', 137 '** limitations under the License.', 138 '*/', 139 '' 140 ] 141 142 # Text specific to Vulkan headers 143 vkPrefixStrings = [ 144 '/*', 145 '** This header is generated from the Khronos Vulkan XML API Registry.', 146 '**', 147 '*/', 148 '' 149 ] 150 151 # Defaults for generating re-inclusion protection wrappers (or not) 152 protectFile = protect 153 protectFeature = protect 154 protectProto = protect 155 156 buildList = [ 157 # Vulkan 1.0 - header for core API + extensions. 158 # To generate just the core API, 159 # change to 'defaultExtensions = None' below. 160 [ COutputGenerator, 161 CGeneratorOptions( 162 filename = 'include/vulkan/vulkan.h', 163 apiname = 'vulkan', 164 profile = None, 165 versions = allVersions, 166 emitversions = allVersions, 167 defaultExtensions = 'vulkan', 168 addExtensions = None, 169 removeExtensions = None, 170 prefixText = prefixStrings + vkPrefixStrings, 171 genFuncPointers = True, 172 protectFile = protectFile, 173 protectFeature = False, 174 protectProto = '#ifndef', 175 protectProtoStr = 'VK_NO_PROTOTYPES', 176 apicall = 'VKAPI_ATTR ', 177 apientry = 'VKAPI_CALL ', 178 apientryp = 'VKAPI_PTR *', 179 alignFuncParam = 48) 180 ], 181 # Vulkan 1.0 draft - API include files for spec and ref pages 182 # Overwrites include subdirectories in spec source tree 183 # The generated include files do not include the calling convention 184 # macros (apientry etc.), unlike the header files. 185 # Because the 1.0 core branch includes ref pages for extensions, 186 # all the extension interfaces need to be generated, even though 187 # none are used by the core spec itself. 188 [ DocOutputGenerator, 189 DocGeneratorOptions( 190 filename = 'vulkan-docs', 191 apiname = 'vulkan', 192 profile = None, 193 versions = allVersions, 194 emitversions = allVersions, 195 defaultExtensions = None, 196 addExtensions = 197 makeREstring([ 198 'VK_KHR_sampler_mirror_clamp_to_edge', 199 ]), 200 removeExtensions = 201 makeREstring([ 202 ]), 203 prefixText = prefixStrings + vkPrefixStrings, 204 apicall = '', 205 apientry = '', 206 apientryp = '*', 207 genDirectory = '../../doc/specs/vulkan', 208 alignFuncParam = 48, 209 expandEnumerants = False) 210 ], 211 # Vulkan 1.0 draft - API names to validate man/api spec includes & links 212 [ PyOutputGenerator, 213 DocGeneratorOptions( 214 filename = '../../doc/specs/vulkan/vkapi.py', 215 apiname = 'vulkan', 216 profile = None, 217 versions = allVersions, 218 emitversions = allVersions, 219 defaultExtensions = None, 220 addExtensions = 221 makeREstring([ 222 'VK_KHR_sampler_mirror_clamp_to_edge', 223 ]), 224 removeExtensions = 225 makeREstring([ 226 ])) 227 ], 228 # Vulkan 1.0 draft - core API validity files for spec 229 # Overwrites validity subdirectories in spec source tree 230 [ ValidityOutputGenerator, 231 DocGeneratorOptions( 232 filename = 'validity', 233 apiname = 'vulkan', 234 profile = None, 235 versions = allVersions, 236 emitversions = allVersions, 237 defaultExtensions = None, 238 addExtensions = 239 makeREstring([ 240 'VK_KHR_sampler_mirror_clamp_to_edge', 241 ]), 242 removeExtensions = 243 makeREstring([ 244 ]), 245 genDirectory = '../../doc/specs/vulkan') 246 ], 247 # Vulkan 1.0 draft - core API host sync table files for spec 248 # Overwrites subdirectory in spec source tree 249 [ HostSynchronizationOutputGenerator, 250 DocGeneratorOptions( 251 filename = 'hostsynctable', 252 apiname = 'vulkan', 253 profile = None, 254 versions = allVersions, 255 emitversions = allVersions, 256 defaultExtensions = None, 257 addExtensions = 258 makeREstring([ 259 'VK_KHR_sampler_mirror_clamp_to_edge', 260 ]), 261 removeExtensions = 262 makeREstring([ 263 ]), 264 genDirectory = '../../doc/specs/vulkan') 265 ], 266 # Vulkan 1.0 draft - thread checking layer 267 [ ThreadOutputGenerator, 268 ThreadGeneratorOptions( 269 filename = 'thread_check.h', 270 apiname = 'vulkan', 271 profile = None, 272 versions = allVersions, 273 emitversions = allVersions, 274 defaultExtensions = 'vulkan', 275 addExtensions = None, 276 removeExtensions = None, 277 prefixText = prefixStrings + vkPrefixStrings, 278 genFuncPointers = True, 279 protectFile = protectFile, 280 protectFeature = False, 281 protectProto = True, 282 protectProtoStr = 'VK_PROTOTYPES', 283 apicall = 'VKAPI_ATTR ', 284 apientry = 'VKAPI_CALL ', 285 apientryp = 'VKAPI_PTR *', 286 alignFuncParam = 48, 287 genDirectory = outDir) 288 ], 289 [ ParamCheckerOutputGenerator, 290 ParamCheckerGeneratorOptions( 291 filename = 'parameter_validation.h', 292 apiname = 'vulkan', 293 profile = None, 294 versions = allVersions, 295 emitversions = allVersions, 296 defaultExtensions = 'vulkan', 297 addExtensions = None, 298 removeExtensions = None, 299 prefixText = prefixStrings + vkPrefixStrings, 300 genFuncPointers = True, 301 protectFile = protectFile, 302 protectFeature = False, 303 protectProto = None, 304 protectProtoStr = 'VK_NO_PROTOTYPES', 305 apicall = 'VKAPI_ATTR ', 306 apientry = 'VKAPI_CALL ', 307 apientryp = 'VKAPI_PTR *', 308 alignFuncParam = 48, 309 genDirectory = outDir) 310 ], 311 None 312 ] 313 314 # create error/warning & diagnostic files 315 if (errFilename): 316 errWarn = open(errFilename,'w') 317 else: 318 errWarn = sys.stderr 319 diag = open(diagFilename, 'w') 320 321 # check that output directory exists 322 if (not os.path.isdir(outDir)): 323 write('Output directory does not exist: ', outDir) 324 raise 325 326 def genHeaders(): 327 # Loop over targets, building each 328 generated = 0 329 for item in buildList: 330 if (item == None): 331 break 332 createGenerator = item[0] 333 genOpts = item[1] 334 if (target and target != genOpts.filename): 335 # write('*** Skipping', genOpts.filename) 336 continue 337 write('*** Building', genOpts.filename) 338 generated = generated + 1 339 startTimer() 340 gen = createGenerator(errFile=errWarn, 341 warnFile=errWarn, 342 diagFile=diag) 343 reg.setGenerator(gen) 344 reg.apiGen(genOpts) 345 write('** Generated', genOpts.filename) 346 endTimer('Time to generate ' + genOpts.filename + ' =') 347 if (target and generated == 0): 348 write('Failed to generate target:', target) 349 350 if (debug): 351 pdb.run('genHeaders()') 352 elif (profile): 353 import cProfile, pstats 354 cProfile.run('genHeaders()', 'profile.txt') 355 p = pstats.Stats('profile.txt') 356 p.strip_dirs().sort_stats('time').print_stats(50) 357 else: 358 genHeaders() 359