Cleanup and fix debug ifdef
[ocl-icd] / icd_generator.rb
1 =begin
2 Copyright (c) 2012, Brice Videau <brice.videau@imag.fr>
3 Copyright (c) 2012, Vincent Danjean <Vincent.Danjean@ens-lyon.org>
4 All rights reserved.
5       
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8     
9 1. Redistributions of source code must retain the above copyright notice, this
10    list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright notice,
12    this list of conditions and the following disclaimer in the documentation
13    and/or other materials provided with the distribution.
14         
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 =end
26
27 require 'yaml'
28
29 module IcdGenerator
30   $api_entries = {}
31   $api_entries_array = []
32   $cl_objects = ["platform_id", "device_id", "context", "command_queue", "mem", "program", "kernel", "event", "sampler"]
33   $known_entries= { 1 => "clGetPlatformInfo", 0 => "clGetPlatformIDs" }
34   # do not call these functions when trying to discover the mapping
35   $forbidden_funcs = ["clGetExtensionFunctionAddress","clGetPlatformIDs",
36      "clGetPlatformInfo", "clGetGLContextInfoKHR", "clUnloadCompiler"]
37   # do not create weak functions for these ones in the discovering program
38   $noweak_funcs = ["clGetExtensionFunctionAddress", "clGetPlatformIDs",
39     "clGetPlatformInfo", "clGetGLContextInfoKHR", "clUnloadCompiler",
40     "clCreateContext", "clCreateContextFromType", "clWaitForEvents"]
41   # functions written specifically in the loader
42   $specific_loader_funcs = ["clGetExtensionFunctionAddress","clGetPlatformIDs",
43                          "clGetGLContextInfoKHR", "clUnloadCompiler",
44     "clCreateContext", "clCreateContextFromType", "clWaitForEvents"]
45   $header_files = ["/usr/include/CL/cl.h", "/usr/include/CL/cl_gl.h",
46     "/usr/include/CL/cl_ext.h", "/usr/include/CL/cl_gl_ext.h"]
47   $versions_entries = []
48   $buff=20
49   $license = <<EOF
50 Copyright (c) 2012, Brice Videau <brice.videau@imag.fr>
51 Copyright (c) 2012, Vincent Danjean <Vincent.Danjean@ens-lyon.org>
52 All rights reserved.
53       
54 Redistribution and use in source and binary forms, with or without
55 modification, are permitted provided that the following conditions are met:
56     
57 1. Redistributions of source code must retain the above copyright notice, this
58    list of conditions and the following disclaimer.
59 2. Redistributions in binary form must reproduce the above copyright notice,
60    this list of conditions and the following disclaimer in the documentation
61    and/or other materials provided with the distribution.
62         
63 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
64 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
67 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
72 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73
74 Do not edit this file. It is automatically generated.
75 EOF
76
77   def self.parse_headers
78     api_entries = []
79     $header_files.each{ |fname|
80       f = File::open(fname)
81       doc = f.read
82       api_entries += doc.scan(/CL_API_ENTRY.*?;/m)
83       f.close
84     }
85     api_entries.each{ |entry|
86 #      puts entry
87       begin 
88         entry_name = entry.match(/CL_API_CALL(.*?)\(/m)[1].strip
89         next if entry_name.match('\*')
90         next if entry_name.match("INTEL")
91         next if entry_name.match("APPLE")
92         $api_entries[entry_name] = entry
93        
94       rescue
95         entry_name = entry.match(/(\S*?)\(/m)[1].strip
96         next if entry_name.match('\*')
97         next if entry_name.match("INTEL")
98         next if entry_name.match("APPLE")
99         $api_entries[entry_name] = entry
100       end
101     }
102 #    $api_entries.each{ |key, value|
103 #      puts "#{key}: #{value}"
104 #    }
105   end
106
107   def self.include_headers
108     headers =""
109     $header_files.each { |h|
110       if h.match('^/usr/include/') then
111         headers += "#include <#{h[13..-1]}>\n"
112       else
113         headers += "#include \"#{h}\"\n"
114       end
115     }
116     return headers
117   end
118
119   def self.generate_ocl_icd_header
120     ocl_icd_header = "/**\n#{$license}\n*/\n\n"
121     ocl_icd_header += "#pragma GCC diagnostic push\n"
122     ocl_icd_header += "#  pragma GCC diagnostic ignored \"-Wcpp\"\n"
123     ocl_icd_header += "#  define CL_USE_DEPRECATED_OPENCL_1_0_APIS\n"
124     ocl_icd_header += "#  define CL_USE_DEPRECATED_OPENCL_1_1_APIS\n"
125     ocl_icd_header += "#  include <CL/opencl.h>\n"
126     ocl_icd_header += self.include_headers
127     ocl_icd_header += "#pragma GCC diagnostic pop\n"
128     ocl_icd_header += <<EOF
129
130 #define OCL_ICD_API_VERSION     1
131 #define OCL_ICD_IDENTIFIED_FUNCTIONS    #{$known_entries.count}
132
133 struct _cl_icd_dispatch {
134 EOF
135     $api_entries_array.each { |entry|
136       ocl_icd_header += entry.gsub("\r","").
137         sub(/CL_API_CALL\n?(.*?)\(/m,'(CL_API_CALL*\1)('+"\n  ").
138         gsub(/\) (CL_API_SUFFIX__VERSION)/m,"\n) \\1").gsub(/\s*$/,'').
139         gsub(/^[\t ]+/,"    ").gsub(/^([^\t ])/, '  \1') + "\n\n"
140     }
141     ocl_icd_header += "};\n\n"
142     return ocl_icd_header
143   end
144
145   def self.generate_ocl_icd_loader_header
146     ocl_icd_header = "/**\n#{$license}\n*/\n\n"
147     ocl_icd_header += "#include \"ocl_icd.h\"\n\n"
148     ocl_icd_header += <<EOF
149
150 struct func_desc {
151   const char* name;
152   void(*const addr)(void);
153 };
154
155 extern const struct func_desc function_description[];
156
157 EOF
158     ocl_icd_header += "extern struct _cl_icd_dispatch master_dispatch;\n"
159     $cl_objects.each { |o|
160       ocl_icd_header += "struct _cl_#{o} { struct _cl_icd_dispatch *dispatch; };\n"
161     }
162     return ocl_icd_header
163   end
164
165   def self.generate_ocl_icd_bindings_source
166     ocl_icd_bindings_source = "/**\n#{$license}\n*/\n"
167     ocl_icd_bindings_source += "#include \"ocl_icd.h\"\n"
168     ocl_icd_bindings_source += "struct _cl_icd_dispatch master_dispatch = {\n"
169     ($api_entries.length+$buff-1).times { |i|
170       if( $known_entries[i] ) then 
171         ocl_icd_bindings_source += "  #{$known_entries[i]},\n"
172       else
173         ocl_icd_bindings_source += "  (void *) NULL,\n"
174       end
175     }
176     if( $known_entries[$api_entries.length+$buff-1] ) then
177       ocl_icd_bindings_source += "  #{$known_entries[i]}\n"
178     else
179       ocl_icd_bindings_source += "  (void *) NULL\n"
180     end
181     ocl_icd_bindings_source += "};\n"
182     ocl_icd_bindings_source += <<EOF
183
184 CL_API_ENTRY cl_int CL_API_CALL clIcdGetPlatformIDsKHR(  
185              cl_uint num_entries, 
186              cl_platform_id *platforms,
187              cl_uint *num_platforms) {
188   if( platforms == NULL && num_platforms == NULL )
189     return CL_INVALID_VALUE;
190   if( num_entries == 0 && platforms != NULL )
191     return CL_INVALID_VALUE;
192 #error You have to fill the commented lines with corresponding variables from your library
193 //  if( your_number_of_platforms == 0)
194 //    return CL_PLATFORM_NOT_FOUND_KHR;
195 //  if( num_platforms != NULL )
196 //    *num_platforms = your_number_of_platforms;
197   if( platforms != NULL ) {
198     cl_uint i;
199 //    for( i=0; i<(your_number_of_platforms<num_entries?your_number_of_platforms:num_entries); i++)
200 //      platforms[i] = &your_platforms[i];
201   }
202   return CL_SUCCESS;
203 }
204
205 CL_API_ENTRY void * CL_API_CALL clGetExtensionFunctionAddress(
206              const char *   func_name) CL_API_SUFFIX__VERSION_1_0 {
207 #error You have to fill this function with your extensions of incorporate these lines in your version
208   if( func_name != NULL &&  strcmp("clIcdGetPlatformIDsKHR", func_name) == 0 )
209     return (void *)clIcdGetPlatformIDsKHR;
210   return NULL;
211 }
212 CL_API_ENTRY cl_int CL_API_CALL clGetPlatformInfo(
213              cl_platform_id   platform, 
214              cl_platform_info param_name,
215              size_t           param_value_size, 
216              void *           param_value,
217              size_t *         param_value_size_ret) CL_API_SUFFIX__VERSION_1_0 {
218 #error You ahve to fill this function with your information or assert that your version responds to CL_PLATFORM_ICD_SUFFIX_KHR
219 //  char cl_platform_profile[] = "FULL_PROFILE";
220 //  char cl_platform_version[] = "OpenCL 1.1";
221 //  char cl_platform_name[] = "DummyCL";
222 //  char cl_platform_vendor[] = "LIG";
223 //  char cl_platform_extensions[] = "cl_khr_icd";
224 //  char cl_platform_icd_suffix_khr[] = "DUMMY";
225   size_t size_string;
226   char * string_p;
227   if( platform != NULL ) {
228     int found = 0;
229     int i;
230     for(i=0; i<num_master_platforms; i++) {
231       if( platform == &master_platforms[i] )
232         found = 1;
233     }
234     if(!found)
235       return CL_INVALID_PLATFORM;
236   }
237   switch ( param_name ) {
238     case CL_PLATFORM_PROFILE:
239       string_p = cl_platform_profile;
240       size_string = sizeof(cl_platform_profile);
241       break;
242     case CL_PLATFORM_VERSION:
243       string_p = cl_platform_version;
244       size_string = sizeof(cl_platform_version);
245       break;
246     case CL_PLATFORM_NAME:
247       string_p = cl_platform_name;
248       size_string = sizeof(cl_platform_name);
249       break;
250     case CL_PLATFORM_VENDOR:
251       string_p = cl_platform_vendor;
252       size_string = sizeof(cl_platform_vendor);
253       break;
254     case CL_PLATFORM_EXTENSIONS:
255       string_p = cl_platform_extensions;
256       size_string = sizeof(cl_platform_extensions);
257       break;
258     case CL_PLATFORM_ICD_SUFFIX_KHR:
259       string_p = cl_platform_icd_suffix_khr;
260       size_string = sizeof(cl_platform_icd_suffix_khr);
261       break;
262     default:
263       return CL_INVALID_VALUE;
264       break;
265   }
266   if( param_value != NULL ) {
267     if( size_string > param_value_size )
268       return CL_INVALID_VALUE;
269     memcpy(param_value, string_p, size_string);
270   }
271   if( param_value_size_ret != NULL )
272     *param_value_size_ret = size_string;
273   return CL_SUCCESS;
274 }
275 EOF
276     return ocl_icd_bindings_source
277   end
278  
279   def self.generate_ocl_icd_loader_gen_source
280     skip_funcs = $specific_loader_funcs
281     ocl_icd_loader_gen_source = "/**\n#{$license}\n*/\n"
282     ocl_icd_loader_gen_source += "#include \"ocl_icd_loader.h\"\n"
283     ocl_icd_loader_gen_source += "#define DEBUG_OCL_ICD_PROVIDE_DUMP_FIELD\n"
284     ocl_icd_loader_gen_source += "#include \"ocl_icd_debug.h\"\n"
285     ocl_icd_loader_gen_source += ""
286     $api_entries.each { |func_name, entry|
287       next if skip_funcs.include?(func_name)
288       clean_entry = entry.sub(/(.*\)).*/m,'\1').gsub("/*","").gsub("*/","").gsub("\r","") + "{\n"
289       parameters = clean_entry.match(/\(.*\)/m)[0][1..-2]
290       parameters.gsub!(/\[.*?\]/,"")
291       parameters.sub!(/\(.*?\*\s*(.*?)\)\s*\(.*?\)/,'\1')
292       ocl_icd_loader_gen_source += clean_entry.gsub(/\[.*?\]/,"")
293       first_parameter = parameters.match(/.*?\,/m)
294       if not first_parameter then
295         first_parameter =  parameters.match(/.*/m)[0]
296       else
297         first_parameter = first_parameter[0][0..-2]
298       end
299       fps = first_parameter.split
300       ocl_icd_loader_gen_source += "  debug_trace();\n"
301       ocl_icd_loader_gen_source += "  RETURN(((struct _#{fps[0]} *)#{fps[1]})->dispatch->#{func_name}("
302       ps = parameters.split(",")
303       ps = ps.collect { |p|
304         p = p.split
305         p = p[-1].gsub("*","")
306       }
307       ocl_icd_loader_gen_source += ps.join(", ")
308       ocl_icd_loader_gen_source += "));\n"
309       ocl_icd_loader_gen_source += "}\n\n"
310     }
311     ocl_icd_loader_gen_source += "#pragma GCC visibility push(hidden)\n\n"
312     skip_funcs = $specific_loader_funcs
313     $api_entries.each { |func_name, entry|
314       #next if func_name.match(/EXT$/)
315       #next if func_name.match(/KHR$/)
316       if (skip_funcs.include?(func_name)) then
317         ocl_icd_loader_gen_source += "extern typeof(#{func_name}) #{func_name}_hid;\n"
318       else
319         ocl_icd_loader_gen_source += "typeof(#{func_name}) #{func_name}_hid __attribute__ ((alias (\"#{func_name}\"), visibility(\"hidden\")));\n"
320       end
321     }
322     ocl_icd_loader_gen_source += "\n\nstruct func_desc const function_description[]= {\n"
323     $api_entries.each { |func_name, entry|
324       #next if func_name.match(/EXT$/)
325       #next if func_name.match(/KHR$/)
326       ocl_icd_loader_gen_source += "  {\"#{func_name}\", (void(* const)(void))&#{func_name}_hid },\n"
327     }
328     ocl_icd_loader_gen_source += <<EOF
329   {NULL, NULL}
330 };
331
332 #ifdef DEBUG_OCL_ICD
333 void dump_platform(clGEFA_t f, cl_platform_id pid) {
334   debug(D_ALWAYS, "platform @%p:  name=field_in_struct [clGetExtensionFunctionAddress(name)/clGetExtensionFunctionAddressForPlatform(name)]", pid);
335 EOF
336     $api_entries_array.each { |entry|
337       e = entry.gsub("\r"," ").gsub("\n"," ").gsub("\t"," ").
338         sub(/.*CL_API_CALL *([^ ()]*)[ ()].*$/m, '\1')
339       ocl_icd_loader_gen_source += "  dump_field(pid, f, #{e});\n"
340     }
341
342     ocl_icd_loader_gen_source += <<EOF
343 }
344 #endif
345
346 #pragma GCC visibility pop
347
348 EOF
349     return ocl_icd_loader_gen_source;
350   end
351   
352   def self.generate_libdummy_icd_header
353     libdummy_icd_structures = "/**\n#{$license}\n*/\n"
354     libdummy_icd_structures +=  "#include <CL/opencl.h>\n"
355     libdummy_icd_structures += self.include_headers
356     libdummy_icd_structures += "\n\nstruct _cl_icd_dispatch;\n"
357     libdummy_icd_structures += "struct _cl_platform_id { struct _cl_icd_dispatch *dispatch; };\n\n"
358     libdummy_icd_structures += "struct _cl_icd_dispatch {\n"
359     ($api_entries.length+$buff).times { |i|
360       if( $known_entries[i] ) then
361         libdummy_icd_structures += "  void(*known#{i})(void);\n"
362       else
363         libdummy_icd_structures += "  void(*unknown#{i})(void);\n"
364       end
365     }
366     libdummy_icd_structures += "};\n\n"
367     libdummy_icd_structures += "#pragma GCC visibility push(hidden)\n\n"
368     libdummy_icd_structures += "struct _cl_icd_dispatch master_dispatch; \n\n"
369     $known_entries.each { |k, f|
370       libdummy_icd_structures += "typeof(#{f}) INT#{f};\n"
371     }
372     libdummy_icd_structures += "#pragma GCC visibility pop\n\n"
373     return libdummy_icd_structures
374   end
375
376   def self.generate_libdummy_icd_source
377     libdummy_icd_source = "/**\n#{$license}\n*/\n\n"
378     libdummy_icd_source += "#include <stdio.h>\n\n"
379     libdummy_icd_source += "#include \"libdummy_icd_gen.h\"\n\n"
380     libdummy_icd_source += "#include \"libdummy_icd.h\"\n\n"
381     (0...$api_entries.length+$buff).each { |i|
382       libdummy_icd_source += "void dummyFunc#{i}(void){ printf(\"#{i}  : \"); fflush(NULL); }\n"
383     }
384     libdummy_icd_source += "\nstruct _cl_icd_dispatch master_dispatch = {\n"
385     comma=","
386     ($api_entries.length+$buff).times { |i|
387       comma="" if (i == $api_entries.length+$buff-1)
388       if( $known_entries[i] ) then 
389         libdummy_icd_source += "  (void(*)(void))& INT#{$known_entries[i]}#{comma}\n"
390       else
391         libdummy_icd_source += "  (void(*)(void))& dummyFunc#{i}#{comma}\n"
392       end
393     }
394     libdummy_icd_source += "};\n"
395     return libdummy_icd_source
396   end
397   
398   def self.generate_run_dummy_icd_weak_source
399     run_dummy_icd_weak = "/**\n#{$license}\n*/\n"
400     run_dummy_icd_weak += <<EOF
401 #define _GNU_SOURCE 1
402 #include <stdio.h>
403 #include <dlfcn.h>
404
405 #define F(f) \\
406 __attribute__((weak)) int f (void* arg, void* arg2) { \\
407   void (* p)(void*, void*)=NULL; \\
408   p=dlsym(RTLD_NEXT, #f); \\
409   if (p) { \\
410     (*p)(arg, arg2); \\
411   } else { \\
412     printf("-1 : "); \\
413   } \\
414   return 0; \\
415
416
417 EOF
418     $api_entries.each_key { |func_name|
419        next if $noweak_funcs.include?(func_name)
420        run_dummy_icd_weak += "F(#{func_name})\n"
421     }
422     return run_dummy_icd_weak
423   end
424   def self.generate_run_dummy_icd_source
425     run_dummy_icd = "/**\n#{$license}\n*/\n"
426     run_dummy_icd += "#include <stdlib.h>\n"
427     run_dummy_icd += "#include <stdio.h>\n"
428     run_dummy_icd += "#pragma GCC diagnostic push\n"
429     run_dummy_icd += "#  pragma GCC diagnostic ignored \"-Wcpp\"\n"
430     run_dummy_icd += "#  define CL_USE_DEPRECATED_OPENCL_1_0_APIS\n"
431     run_dummy_icd += "#  define CL_USE_DEPRECATED_OPENCL_1_1_APIS\n"
432     run_dummy_icd += "#  include <CL/opencl.h>\n"
433     run_dummy_icd += self.include_headers
434     run_dummy_icd += "#pragma GCC diagnostic pop\n"
435     run_dummy_icd += "\n\n"
436     run_dummy_icd += "typedef CL_API_ENTRY cl_int (CL_API_CALL* oclFuncPtr_fn)(cl_platform_id platform);\n\n"
437     run_dummy_icd += "void call_all_OpenCL_functions(cl_platform_id chosen_platform) {\n"
438     run_dummy_icd += "  oclFuncPtr_fn oclFuncPtr;\n"
439     run_dummy_icd += "  cl_context_properties properties[] = { CL_CONTEXT_PLATFORM, (cl_context_properties)chosen_platform, 0 };\n"
440     $api_entries.each_key { |func_name|
441        next if $forbidden_funcs.include?(func_name)
442        if func_name == "clCreateContext" then
443          run_dummy_icd += "  #{func_name}(properties,1,(cl_device_id*)&chosen_platform,NULL,NULL,NULL);\n"
444        elsif func_name == "clGetGLContextInfoKHR" then
445          run_dummy_icd += "  #{func_name}(properties,CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR, 0, NULL, NULL);\n"
446        elsif func_name == "clCreateContextFromType" then
447          run_dummy_icd += "  #{func_name}(properties,CL_DEVICE_TYPE_CPU,NULL,NULL,NULL);\n"
448        elsif func_name == "clWaitForEvents" then
449          run_dummy_icd += "  #{func_name}(1,(cl_event*)&chosen_platform);\n"
450        elsif func_name == "clGetExtensionFunctionAddressForPlatform" then
451          run_dummy_icd += "  #{func_name}((cl_platform_id)chosen_platform, \"clIcdGetPlatformIDsKHR\");\n"
452        else
453          run_dummy_icd += "  oclFuncPtr = (oclFuncPtr_fn)" + func_name + ";\n"
454          run_dummy_icd += "  oclFuncPtr(chosen_platform);\n"
455        end
456        run_dummy_icd += "  printf(\"%s\\n\", \"#{func_name}\");"
457        run_dummy_icd += "  fflush(NULL);\n"
458     }
459     run_dummy_icd += "  return;\n}\n"
460     return run_dummy_icd
461   end
462
463   def self.generate_ocl_icd_loader_map
464     ocl_icd_loader_map = "/**\n#{$license}\n*/\n\n"
465     prev_version=""
466     $versions_entries.keys.sort.each { |version|
467       ocl_icd_loader_map += "OPENCL_#{version.sub('_','.')} {\n";
468       ocl_icd_loader_map += "  global:\n";
469       $versions_entries[version].each { |symb|
470         ocl_icd_loader_map += "    #{symb};\n"
471       }
472       if (prev_version == "") then
473         ocl_icd_loader_map += "  local:\n";
474         ocl_icd_loader_map += "    *;\n";
475       end
476       ocl_icd_loader_map += "} #{prev_version};\n\n";
477       prev_version="OPENCL_#{version.sub('_','.')}";
478     }
479     return ocl_icd_loader_map
480   end
481
482   def self.generate_sources
483     parse_headers
484     File.open('libdummy_icd_gen.h','w') { |f|
485       f.puts generate_libdummy_icd_header
486     }
487     File.open('libdummy_icd_gen.c','w') { |f|
488       f.puts generate_libdummy_icd_source
489     }
490     File.open('run_dummy_icd_gen.c','w') { |f|
491       f.puts generate_run_dummy_icd_source
492     }
493     File.open('run_dummy_icd_weak.c','w') { |f|
494       f.puts generate_run_dummy_icd_weak_source
495     }
496   end
497
498   def self.savedb(yamlfile)
499     api_db = {}
500     begin
501       File::open(yamlfile,"r") { |f|
502         api_db = YAML::load(f.read)
503 #        puts api_db.inspect
504       }
505     rescue
506       api_db = {}
507     end
508     $known_entries.each_key {|i|
509       next if api_db[i]
510       api_db[i] = $api_entries[$known_entries[i]].gsub("\r","")
511     }
512     File::open(yamlfile,"w") { |f|
513       f.write($license.gsub(/^/,"# "))
514       f.write( <<EOF
515
516 # In Intel (OpenCL 1.1):
517 # * clSetCommandQueueProperty(13): nil (deprecated in 1.1)
518 # * clGetGLContextInfoKHR(74): function present with its symbol
519 # * 75-80: nil
520 # * 92: correspond to symbol clGetKernelArgInfo (first abandonned version?)
521 # * 93-: garbage
522 # In nvidia (OpenCL 1.1):
523 # * clGetGLContextInfoKHR(74): function present but no symbol
524 # * 75-80: nil
525 # * 89-: nil
526 # * only two OpenCL symbols: clGetPlatformInfo(1) and clGetExtensionFunctionAddress(65)
527 # In AMD (OpenCL 1.2):
528 # * clGetPlatformIDs(0): nil (symbol present)
529 # * clGetGLContextInfoKHR(74): function present but no symbol
530 # * 75-80: nil
531 # * 92: nil
532 # * 109-118: nil
533 # * 119-: garbage
534
535 EOF
536 )
537       # Not using YAML::dump as:
538       # * keys are not ordered
539       # * strings are badly formatted in new YAML ruby implementation (psych)
540       # * it is very easy to do it ourself
541       #f.write(YAML::dump(api_db))
542       f.write("--- ")
543       api_db.keys.sort.each { |k|
544         f.write("\n#{k}: |-\n  ")
545         f.write(api_db[k].gsub("\n","\n  "))
546       }
547       f.write("\n")
548     }
549   end
550
551   def self.finalize(yamlfile)
552     parse_headers
553     doc = YAML::load(`./run_dummy_icd`)
554     doc.delete(-1)
555     $known_entries.merge!(doc)
556     self.savedb(yamlfile)
557     unknown=0
558     $api_entries_array = []
559     ($known_entries.length+$buff).times { |i|
560       #puts $known_entries[i]
561       if $known_entries[i] then
562         $api_entries_array.push( $api_entries[$known_entries[i]] )
563       else
564         $api_entries_array.push( "CL_API_ENTRY cl_int CL_API_CALL clUnknown#{i}(void);" )
565         unknown += 1
566       end
567     }
568   end
569   
570   def self.generate_from_database(yamlfile)
571     doc={}
572     File::open(yamlfile) { |f|
573       doc = YAML:: load(f.read)
574     }
575     $known_entries = {}
576     $api_entries = {}
577     $versions_entries = Hash::new { |hash,key| hash[key]=[] }
578     entry_name = ""
579     version = ""
580     doc.each { |key, value|
581       begin
582         entry_name = value.match(/CL_API_CALL(.*?)\(/m)[1].strip
583       rescue
584         entry_name = value.match(/(\S*?)\(/m)[1].strip
585       end
586       version = value.match(/SUFFIX__VERSION_(\d_\d)/m)[1]
587       $versions_entries[version].push(entry_name)
588       $known_entries[key] = entry_name
589       $api_entries[entry_name] = value
590     }
591     $api_entries_array = []
592     unknown=0
593     ($known_entries.length+$buff).times { |i|
594       #puts $known_entries[i]
595       if $known_entries[i] then
596         $api_entries_array.push( $api_entries[$known_entries[i]] )
597       else
598         $api_entries_array.push( "CL_API_ENTRY cl_int CL_API_CALL clUnknown#{i}(void);" )
599         unknown += 1
600       end
601     }
602     File.open('ocl_icd.h','w') { |f|
603       f.puts generate_ocl_icd_header
604     }
605     File.open('ocl_icd_loader.h','w') { |f|
606       f.puts generate_ocl_icd_loader_header
607     }
608     File.open('ocl_icd_loader.map','w') { |f|
609       f.puts generate_ocl_icd_loader_map
610     }
611     File.open('ocl_icd_bindings.c','w') { |f|
612       f.puts generate_ocl_icd_bindings_source
613     }
614     File.open('ocl_icd_loader_gen.c','w') { |f|
615       f.puts generate_ocl_icd_loader_gen_source
616     }
617   end
618 end
619
620 require 'optparse'
621
622 options = {}
623 OptionParser.new do |opts|
624   opts.banner = "Usage: cd_generator.rb [options] mode"
625
626   opts.on("-f", "--file FILE", String, "YAML file (default ocl_interface.yaml)") do |v|
627     options[:file] = v
628   end
629   opts.on("-m", "--mode [MODE]", [:database, :generate, :finalize],
630           "Select mode (database, generate, finalize)") do |m|
631     options[:mode] = m
632   end
633 end.parse!
634
635 if !options[:file] then
636   options[:file] = "ocl_interface.yaml"
637 end
638
639 if !options[:mode] then
640   raise "--mode option required"
641 end
642 if options[:mode] == :generate then
643   IcdGenerator.generate_sources
644 elsif options[:mode] == :finalize then
645   IcdGenerator.finalize(options[:file])
646 elsif options[:mode] == :database then
647   IcdGenerator.generate_from_database(options[:file])
648 else
649   raise "Mode must be one of generate, database or finalize not #{options[:mode]}" 
650 end
651