diff --git a/pyopencl/cffi_cl.py b/pyopencl/cffi_cl.py
index 59ae52b588774f11e7365aa32fe720e0253cb50c..832ede696f92b054c1b3d15a5218cffef7fcc6fc 100644
--- a/pyopencl/cffi_cl.py
+++ b/pyopencl/cffi_cl.py
@@ -1,5 +1,5 @@
 
-from pyopencl._cl import device_info, context_info, command_queue_info, Event, event_info, mem_info, Image, image_info, program_info, Kernel, ImageFormat, GLBuffer, kernel_info, sampler_info, Sampler, have_gl, _enqueue_read_image, _enqueue_write_image, GLTexture, channel_type, _enqueue_copy_image, _enqueue_copy_image_to_buffer, _enqueue_copy_buffer_to_image, _enqueue_write_buffer, _enqueue_copy_buffer, get_cl_header_version, _enqueue_read_buffer_rect, _enqueue_write_buffer_rect, _enqueue_copy_buffer_rect, RuntimeError, program_kind, mem_object_type, Error, platform_info, device_type, mem_flags, LogicError
+from pyopencl._cl import context_info, command_queue_info, Event, event_info, Image, image_info, Kernel, ImageFormat, GLBuffer, kernel_info, sampler_info, Sampler, have_gl, _enqueue_read_image, _enqueue_write_image, GLTexture, channel_type, _enqueue_copy_image, _enqueue_copy_image_to_buffer, _enqueue_copy_buffer_to_image, _enqueue_write_buffer, _enqueue_copy_buffer, _enqueue_read_buffer_rect, _enqueue_write_buffer_rect, _enqueue_copy_buffer_rect, RuntimeError, program_kind, Error, LogicError
 
 import warnings
 
@@ -90,7 +90,7 @@ typedef cl_uint             cl_profiling_info;
 #define CL_MEM_COPY_HOST_PTR  ...
 #define CL_MEM_HOST_WRITE_ONLY  ...
 #define CL_MEM_HOST_READ_ONLY  ...
-#define CL_MEM_HOST_NO_ACCESS  ...
+#define CL_MEM_HOST_NO_ACCESS ...
 
 
 """
@@ -99,7 +99,7 @@ with open(os.path.join(current_directory, 'wrap_cl_core.h')) as _f:
     _wrap_cl_header = _f.read()
 
 _ffi.cdef('%s\n%s' % (_cl_header, _wrap_cl_header))
-print current_directory
+
 _lib = _ffi.verify(
     """
     #include <wrap_cl.h>
@@ -129,59 +129,33 @@ class CLRuntimeError(RuntimeError):
         self.routine = routine
         self.code = code
 
-        
-# plats = _ffi.new("void**")
-# print _lib.get_platforms(plats)
-# print _ffi.cast('int**', plats)[0][1]
-# exit()
-
-
-
-# _platform_info_constants = {
-#     'PROFILE': _lib.CL_PLATFORM_PROFILE,
-#     'VERSION': _lib.CL_PLATFORM_VERSION,
-#     'NAME': _lib.CL_PLATFORM_NAME,
-#     'VENDOR': _lib.CL_PLATFORM_VENDOR,
-# }
-
-# # re-implementation
-# platform_info = type("platform_info", (NOINIT,), _platform_info_constants)
-
-# _device_type_constants = {
-#     'DEFAULT': _lib.CL_DEVICE_TYPE_DEFAULT,
-#     'CPU': _lib.CL_DEVICE_TYPE_CPU,
-#     'GPU': _lib.CL_DEVICE_TYPE_GPU,
-#     'ACCELERATOR': _lib.CL_DEVICE_TYPE_ACCELERATOR,
-#     'ALL': _lib.CL_DEVICE_TYPE_ALL,
-#     }
-# if _CL_VERSION >= (1, 2):
-#     _device_type_constants['CUSTOM'] = _lib.CL_DEVICE_TYPE_CUSTOM
-
-# # re-implementation
-# device_type = type("device_type", (NOINIT,), _device_type_constants)
-
-# _mem_flags_constants = {
-#     'READ_WRITE': _lib.CL_MEM_READ_WRITE, 
-#     'WRITE_ONLY': _lib.CL_MEM_WRITE_ONLY, 
-#     'READ_ONLY': _lib.CL_MEM_READ_ONLY, 
-#     'USE_HOST_PTR': _lib.CL_MEM_USE_HOST_PTR, 
-#     'ALLOC_HOST_PTR': _lib.CL_MEM_ALLOC_HOST_PTR, 
-#     'COPY_HOST_PTR': _lib.CL_MEM_COPY_HOST_PTR,
-#     # TODO_PLAT
-#     # #ifdef cl_amd_device_memory_flags
-#     #     'USE_PERSISTENT_MEM_AMD': _lib.CL_MEM_USE_PERSISTENT_MEM_AMD, 
-#     # #endif
-#     }
-# if _CL_VERSION >= (1, 2):
-#     _mem_flags_constants.update({
-#         'HOST_WRITE_ONLY': _lib.CL_MEM_HOST_WRITE_ONLY, 
-#         'HOST_READ_ONLY': _lib.CL_MEM_HOST_READ_ONLY, 
-#         'HOST_NO_ACCESS': _lib.CL_MEM_HOST_NO_ACCESS,
-#     })
-
-# # re-implementation
-# mem_flags = type("mem_flags", (NOINIT,), _mem_flags_constants)
+class NoInit(object):
+    def __init__(self):
+        raise CLRuntimeError("This class cannot be instantiated.")
 
+def get_cl_header_version():
+    v = _lib.get_cl_version()
+    return (v >> (3*4),
+            (v >> (1*4)) & 0xff)
+        
+_CL_VERSION = get_cl_header_version()
+
+_constants = PP(_ffi.new('constant**'))
+_lib.get_constants(_constants.ptr, _constants.size)
+
+def _create_constants_class(name):
+    return type(name, (NoInit,), dict((_ffi.string(c.name), c.value) for c in _constants if _ffi.string(c.type) == name))
+
+platform_info = _create_constants_class("platform_info")
+device_type = _create_constants_class("device_type")
+device_info = _create_constants_class("device_info")
+mem_flags = _create_constants_class("mem_flags")
+mem_info = _create_constants_class("mem_info")
+mem_object_type = _create_constants_class("mem_object_type")
+program_info = _create_constants_class("program_info")
+program_build_info = _create_constants_class("program_build_info")
+program_binary_type = _create_constants_class("program_binary_type")
+kernel_info = _create_constants_class("kernel_info")
 class EQUALITY_TESTS(object):
     def __eq__(self, other):
         return hash(self) == hash(other)
diff --git a/src/c_wrapper/wrap_cl.c b/src/c_wrapper/wrap_cl.c
index e473f21cd853879274f38296a83ceb82b0e53fe2..9e43458f3e5aabbe2c59b661886710b7a3be84ba 100644
--- a/src/c_wrapper/wrap_cl.c
+++ b/src/c_wrapper/wrap_cl.c
@@ -2148,7 +2148,268 @@ inline event *enqueue_nd_range_kernel(
     return 0;
   }
 
+  void get_constants(constant** out, uint32_t *num_constants) {
+#define ADD_ATTR(TYPE, PREFIX, NAME)					\
+    constants.push_back((constant){TYPE, #NAME, CL_##PREFIX##NAME});
+    
+    std::vector<constant> constants;
+    
+    // PLATFORM
+    ADD_ATTR("platform_info", PLATFORM_, PROFILE);
+    ADD_ATTR("platform_info", PLATFORM_, VERSION);
+    ADD_ATTR("platform_info", PLATFORM_, NAME);
+    ADD_ATTR("platform_info", PLATFORM_, VENDOR);
+#if !(defined(CL_PLATFORMNVIDIA) && CL_PLATFORMNVIDIA == 0x3001)
+    ADD_ATTR("platform_info", PLATFORM_, EXTENSIONS);
+#endif
+    
+    // DEVICE_TYPE
+    ADD_ATTR("device_type", DEVICE_TYPE_, DEFAULT);
+    ADD_ATTR("device_type", DEVICE_TYPE_, CPU);
+    ADD_ATTR("device_type", DEVICE_TYPE_, GPU);
+    ADD_ATTR("device_type", DEVICE_TYPE_, ACCELERATOR);
+#if PYOPENCL_CL_VERSION >= 0x1020
+    ADD_ATTR("device_type", DEVICE_TYPE_, CUSTOM);
+#endif
+    ADD_ATTR("device_type", DEVICE_TYPE_, ALL);
+    
+    // DEVICE
+    ADD_ATTR("device_type", DEVICE_, TYPE);
+    ADD_ATTR("device_type", DEVICE_, VENDOR_ID);
+    ADD_ATTR("device_type", DEVICE_, MAX_COMPUTE_UNITS);
+    ADD_ATTR("device_type", DEVICE_, MAX_WORK_ITEM_DIMENSIONS);
+    ADD_ATTR("device_type", DEVICE_, MAX_WORK_GROUP_SIZE);
+    ADD_ATTR("device_type", DEVICE_, MAX_WORK_ITEM_SIZES);
+    ADD_ATTR("device_type", DEVICE_, PREFERRED_VECTOR_WIDTH_CHAR);
+    ADD_ATTR("device_type", DEVICE_, PREFERRED_VECTOR_WIDTH_SHORT);
+    ADD_ATTR("device_type", DEVICE_, PREFERRED_VECTOR_WIDTH_INT);
+    ADD_ATTR("device_type", DEVICE_, PREFERRED_VECTOR_WIDTH_LONG);
+    ADD_ATTR("device_type", DEVICE_, PREFERRED_VECTOR_WIDTH_FLOAT);
+    ADD_ATTR("device_type", DEVICE_, PREFERRED_VECTOR_WIDTH_DOUBLE);
+    ADD_ATTR("device_type", DEVICE_, MAX_CLOCK_FREQUENCY);
+    ADD_ATTR("device_type", DEVICE_, ADDRESS_BITS);
+    ADD_ATTR("device_type", DEVICE_, MAX_READ_IMAGE_ARGS);
+    ADD_ATTR("device_type", DEVICE_, MAX_WRITE_IMAGE_ARGS);
+    ADD_ATTR("device_type", DEVICE_, MAX_MEM_ALLOC_SIZE);
+    ADD_ATTR("device_type", DEVICE_, IMAGE2D_MAX_WIDTH);
+    ADD_ATTR("device_type", DEVICE_, IMAGE2D_MAX_HEIGHT);
+    ADD_ATTR("device_type", DEVICE_, IMAGE3D_MAX_WIDTH);
+    ADD_ATTR("device_type", DEVICE_, IMAGE3D_MAX_HEIGHT);
+    ADD_ATTR("device_type", DEVICE_, IMAGE3D_MAX_DEPTH);
+    ADD_ATTR("device_type", DEVICE_, IMAGE_SUPPORT);
+    ADD_ATTR("device_type", DEVICE_, MAX_PARAMETER_SIZE);
+    ADD_ATTR("device_type", DEVICE_, MAX_SAMPLERS);
+    ADD_ATTR("device_type", DEVICE_, MEM_BASE_ADDR_ALIGN);
+    ADD_ATTR("device_type", DEVICE_, MIN_DATA_TYPE_ALIGN_SIZE);
+    ADD_ATTR("device_type", DEVICE_, SINGLE_FP_CONFIG);
+#ifdef CL_DEVICEDOUBLE_FP_CONFIG
+    ADD_ATTR("device_type", DEVICE_, DOUBLE_FP_CONFIG);
+#endif
+#ifdef CL_DEVICEHALF_FP_CONFIG
+    ADD_ATTR("device_type", DEVICE_, HALF_FP_CONFIG);
+#endif
+    ADD_ATTR("device_type", DEVICE_, GLOBAL_MEM_CACHE_TYPE);
+    ADD_ATTR("device_type", DEVICE_, GLOBAL_MEM_CACHELINE_SIZE);
+    ADD_ATTR("device_type", DEVICE_, GLOBAL_MEM_CACHE_SIZE);
+    ADD_ATTR("device_type", DEVICE_, GLOBAL_MEM_SIZE);
+    ADD_ATTR("device_type", DEVICE_, MAX_CONSTANT_BUFFER_SIZE);
+    ADD_ATTR("device_type", DEVICE_, MAX_CONSTANT_ARGS);
+    ADD_ATTR("device_type", DEVICE_, LOCAL_MEM_TYPE);
+    ADD_ATTR("device_type", DEVICE_, LOCAL_MEM_SIZE);
+    ADD_ATTR("device_type", DEVICE_, ERROR_CORRECTION_SUPPORT);
+    ADD_ATTR("device_type", DEVICE_, PROFILING_TIMER_RESOLUTION);
+    ADD_ATTR("device_type", DEVICE_, ENDIAN_LITTLE);
+    ADD_ATTR("device_type", DEVICE_, AVAILABLE);
+    ADD_ATTR("device_type", DEVICE_, COMPILER_AVAILABLE);
+    ADD_ATTR("device_type", DEVICE_, EXECUTION_CAPABILITIES);
+    ADD_ATTR("device_type", DEVICE_, QUEUE_PROPERTIES);
+    ADD_ATTR("device_type", DEVICE_, NAME);
+    ADD_ATTR("device_type", DEVICE_, VENDOR);
+    ADD_ATTR("device_type", , DRIVER_VERSION);
+    ADD_ATTR("device_type", DEVICE_, VERSION);
+    ADD_ATTR("device_type", DEVICE_, PROFILE);
+    ADD_ATTR("device_type", DEVICE_, VERSION);
+    ADD_ATTR("device_type", DEVICE_, EXTENSIONS);
+    ADD_ATTR("device_type", DEVICE_, PLATFORM);
+#if PYOPENCL_CL_VERSION >= 0x1010
+    ADD_ATTR("device_type", DEVICE_, PREFERRED_VECTOR_WIDTH_HALF);
+    ADD_ATTR("device_type", DEVICE_, HOST_UNIFIED_MEMORY);
+    ADD_ATTR("device_type", DEVICE_, NATIVE_VECTOR_WIDTH_CHAR);
+    ADD_ATTR("device_type", DEVICE_, NATIVE_VECTOR_WIDTH_SHORT);
+    ADD_ATTR("device_type", DEVICE_, NATIVE_VECTOR_WIDTH_INT);
+    ADD_ATTR("device_type", DEVICE_, NATIVE_VECTOR_WIDTH_LONG);
+    ADD_ATTR("device_type", DEVICE_, NATIVE_VECTOR_WIDTH_FLOAT);
+    ADD_ATTR("device_type", DEVICE_, NATIVE_VECTOR_WIDTH_DOUBLE);
+    ADD_ATTR("device_type", DEVICE_, NATIVE_VECTOR_WIDTH_HALF);
+    ADD_ATTR("device_type", DEVICE_, OPENCL_C_VERSION);
+#endif
+    // support for cl_nv_DEVICEattribute_query
+#ifdef CL_DEVICECOMPUTE_CAPABILITY_MAJOR_NV
+    ADD_ATTR("device_type", DEVICE_, COMPUTE_CAPABILITY_MAJOR_NV);
+    ADD_ATTR("device_type", DEVICE_, COMPUTE_CAPABILITY_MINOR_NV);
+    ADD_ATTR("device_type", DEVICE_, REGISTERS_PER_BLOCK_NV);
+    ADD_ATTR("device_type", DEVICE_, WARP_SIZE_NV);
+    ADD_ATTR("device_type", DEVICE_, GPU_OVERLAP_NV);
+    ADD_ATTR("device_type", DEVICE_, KERNEL_EXEC_TIMEOUT_NV);
+    ADD_ATTR("device_type", DEVICE_, INTEGRATED_MEMORY_NV);
+#endif
+    // {{{ cl_amd_DEVICEattribute_query
+#ifdef CL_DEVICEPROFILING_TIMER_OFFSET_AMD
+    ADD_ATTR("device_type", DEVICE_, PROFILING_TIMER_OFFSET_AMD);
+#endif
+#ifdef CL_DEVICETOPOLOGY_AMD
+    ADD_ATTR("device_type", DEVICE_, TOPOLOGY_AMD);
+#endif
+#ifdef CL_DEVICEBOARD_NAME_AMD
+    ADD_ATTR("device_type", DEVICE_, BOARD_NAME_AMD);
+#endif
+#ifdef CL_DEVICEGLOBAL_FREE_MEMORY_AMD
+    ADD_ATTR("device_type", DEVICE_, GLOBAL_FREE_MEMORY_AMD);
+#endif
+#ifdef CL_DEVICESIMD_PER_COMPUTE_UNIT_AMD
+    ADD_ATTR("device_type", DEVICE_, SIMD_PER_COMPUTE_UNIT_AMD);
+#endif
+#ifdef CL_DEVICESIMD_WIDTH_AMD
+    ADD_ATTR("device_type", DEVICE_, SIMD_WIDTH_AMD);
+#endif
+#ifdef CL_DEVICESIMD_INSTRUCTION_WIDTH_AMD
+    ADD_ATTR("device_type", DEVICE_, SIMD_INSTRUCTION_WIDTH_AMD);
+#endif
+#ifdef CL_DEVICEWAVEFRONT_WIDTH_AMD
+    ADD_ATTR("device_type", DEVICE_, WAVEFRONT_WIDTH_AMD);
+#endif
+#ifdef CL_DEVICEGLOBAL_MEM_CHANNELS_AMD
+    ADD_ATTR("device_type", DEVICE_, GLOBAL_MEM_CHANNELS_AMD);
+#endif
+#ifdef CL_DEVICEGLOBAL_MEM_CHANNEL_BANKS_AMD
+    ADD_ATTR("device_type", DEVICE_, GLOBAL_MEM_CHANNEL_BANKS_AMD);
+#endif
+#ifdef CL_DEVICEGLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD
+    ADD_ATTR("device_type", DEVICE_, GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD);
+#endif
+#ifdef CL_DEVICELOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD
+    ADD_ATTR("device_type", DEVICE_, LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD);
+#endif
+#ifdef CL_DEVICELOCAL_MEM_BANKS_AMD
+    ADD_ATTR("device_type", DEVICE_, LOCAL_MEM_BANKS_AMD);
+#endif
+    // }}}
+#ifdef CL_DEVICEMAX_ATOMIC_COUNTERS_EXT
+    ADD_ATTR("device_type", DEVICE_, MAX_ATOMIC_COUNTERS_EXT);
+#endif
+#if defined(cl_ext_DEVICEfission) && defined(PYOPENCL_USE_DEVICEFISSION)
+    ADD_ATTR("device_type", DEVICE_, PARENT_DEVICEEXT);
+    ADD_ATTR("device_type", DEVICE_, PARTITION_TYPES_EXT);
+    ADD_ATTR("device_type", DEVICE_, AFFINITY_DOMAINS_EXT);
+    ADD_ATTR("device_type", DEVICE_, REFERENCE_COUNT_EXT);
+    ADD_ATTR("device_type", DEVICE_, PARTITION_STYLE_EXT);
+#endif
+#if PYOPENCL_CL_VERSION >= 0x1020
+    ADD_ATTR("device_type", DEVICE_, LINKER_AVAILABLE);
+    ADD_ATTR("device_type", DEVICE_, BUILT_IN_KERNELS);
+    ADD_ATTR("device_type", DEVICE_, IMAGE_MAX_BUFFER_SIZE);
+    ADD_ATTR("device_type", DEVICE_, IMAGE_MAX_ARRAY_SIZE);
+    ADD_ATTR("device_type", DEVICE_, PARENT_DEVICE);
+    ADD_ATTR("device_type", DEVICE_, PARTITION_MAX_SUB_DEVICES);
+    ADD_ATTR("device_type", DEVICE_, PARTITION_PROPERTIES);
+    ADD_ATTR("device_type", DEVICE_, PARTITION_AFFINITY_DOMAIN);
+    ADD_ATTR("device_type", DEVICE_, PARTITION_TYPE);
+    ADD_ATTR("device_type", DEVICE_, REFERENCE_COUNT);
+    ADD_ATTR("device_type", DEVICE_, PREFERRED_INTEROP_USER_SYNC);
+    ADD_ATTR("device_type", DEVICE_, PRINTF_BUFFER_SIZE);
+#endif
+#ifdef cl_khr_image2d_from_buffer
+    ADD_ATTR("device_type", DEVICE_, IMAGE_PITCH_ALIGNMENT);
+    ADD_ATTR("device_type", DEVICE_, IMAGE_BASE_ADDRESS_ALIGNMENT);
+#endif
+
+    // mem_flags
+    ADD_ATTR("mem_flags", MEM_, READ_WRITE);
+    ADD_ATTR("mem_flags", MEM_, WRITE_ONLY);
+    ADD_ATTR("mem_flags", MEM_, READ_ONLY);
+    ADD_ATTR("mem_flags", MEM_, USE_HOST_PTR);
+    ADD_ATTR("mem_flags", MEM_, ALLOC_HOST_PTR);
+    ADD_ATTR("mem_flags", MEM_, COPY_HOST_PTR);
+#ifdef cl_amd_device_memory_flags
+    ADD_ATTR("mem_flags", MEM_, USE_PERSISTENT_MEM_AMD);
+#endif
+#if PYOPENCL_CL_VERSION >= 0x1020
+    ADD_ATTR("mem_flags", MEM_, HOST_WRITE_ONLY);
+    ADD_ATTR("mem_flags", MEM_, HOST_READ_ONLY);
+    ADD_ATTR("mem_flags", MEM_, HOST_NO_ACCESS);
+#endif
+
+    // mem_info
+    ADD_ATTR("mem_info", MEM_, TYPE);
+    ADD_ATTR("mem_info", MEM_, FLAGS);
+    ADD_ATTR("mem_info", MEM_, SIZE);
+    ADD_ATTR("mem_info", MEM_, HOST_PTR);
+    ADD_ATTR("mem_info", MEM_, MAP_COUNT);
+    ADD_ATTR("mem_info", MEM_, REFERENCE_COUNT);
+    ADD_ATTR("mem_info", MEM_, CONTEXT);
+#if PYOPENCL_CL_VERSION >= 0x1010
+    ADD_ATTR("mem_info", MEM_, ASSOCIATED_MEMOBJECT);
+    ADD_ATTR("mem_info", MEM_, OFFSET);
+#endif
+
+    // mem_object_type
+    ADD_ATTR("mem_object_type", MEM_OBJECT_, BUFFER);
+    ADD_ATTR("mem_object_type", MEM_OBJECT_, IMAGE2D);
+    ADD_ATTR("mem_object_type", MEM_OBJECT_, IMAGE3D);
+#if PYOPENCL_CL_VERSION >= 0x1020
+    ADD_ATTR("mem_object_type", MEM_OBJECT_, IMAGE2D_ARRAY);
+    ADD_ATTR("mem_object_type", MEM_OBJECT_, IMAGE1D);
+    ADD_ATTR("mem_object_type", MEM_OBJECT_, IMAGE1D_ARRAY);
+    ADD_ATTR("mem_object_type", MEM_OBJECT_, IMAGE1D_BUFFER);
+#endif
+
+    // program_info
+    ADD_ATTR("program_info", PROGRAM_, REFERENCE_COUNT);
+    ADD_ATTR("program_info", PROGRAM_, CONTEXT);
+    ADD_ATTR("program_info", PROGRAM_, NUM_DEVICES);
+    ADD_ATTR("program_info", PROGRAM_, DEVICES);
+    ADD_ATTR("program_info", PROGRAM_, SOURCE);
+    ADD_ATTR("program_info", PROGRAM_, BINARY_SIZES);
+    ADD_ATTR("program_info", PROGRAM_, BINARIES);
+#if PYOPENCL_CL_VERSION >= 0x1020
+    ADD_ATTR("program_info", PROGRAM_, NUM_KERNELS);
+    ADD_ATTR("program_info", PROGRAM_, KERNEL_NAMES);
+#endif
+
+    // program_build_info
+    ADD_ATTR("program_build_info", PROGRAM_BUILD_, STATUS);
+    ADD_ATTR("program_build_info", PROGRAM_BUILD_, OPTIONS);
+    ADD_ATTR("program_build_info", PROGRAM_BUILD_, LOG);
+#if PYOPENCL_CL_VERSION >= 0x1020
+    ADD_ATTR("program_build_info", PROGRAM_, BINARY_TYPE);
+#endif
+    
+    // program_binary_type    
+#if PYOPENCL_CL_VERSION >= 0x1020
+    ADD_ATTR("program_binary_type", PROGRAM_BINARY_TYPE_, NONE);
+    ADD_ATTR("program_binary_type", PROGRAM_BINARY_TYPE_, COMPILED_OBJECT);
+    ADD_ATTR("program_binary_type", PROGRAM_BINARY_TYPE_, LIBRARY);
+    ADD_ATTR("program_binary_type", PROGRAM_BINARY_TYPE_, EXECUTABLE);
+#endif
 
+    // kernel_info
+    ADD_ATTR("kernel_info", KERNEL_, FUNCTION_NAME);
+    ADD_ATTR("kernel_info", KERNEL_, NUM_ARGS);
+    ADD_ATTR("kernel_info", KERNEL_, REFERENCE_COUNT);
+    ADD_ATTR("kernel_info", KERNEL_, CONTEXT);
+    ADD_ATTR("kernel_info", KERNEL_, PROGRAM);
+#if PYOPENCL_CL_VERSION >= 0x1020
+    ADD_ATTR("kernel_info", KERNEL_, ATTRIBUTES);
+#endif
+    
+    MALLOC(constant, c, constants.size());
+    for(std::vector<constant>::size_type i = 0; i < constants.size(); ++i) {
+      c[i] = constants[i];
+    }
+    *out = c;
+    *num_constants = constants.size();
+  }
+  
 }
 
 
diff --git a/src/c_wrapper/wrap_cl_core.h b/src/c_wrapper/wrap_cl_core.h
index f25b2b4b2e82beef46c14e0ae9bbe346a59df8c2..30b42de52e4eb9c40f0954f3bf89fad6639967d0 100644
--- a/src/c_wrapper/wrap_cl_core.h
+++ b/src/c_wrapper/wrap_cl_core.h
@@ -1,34 +1,41 @@
-  typedef enum {
-    generic_info_type_cl_uint,
-    generic_info_type_cl_mem_object_type,
-  } generic_info_type_t;
-  typedef struct {
-    generic_info_type_t type;
-    union value_t {
-      cl_uint _cl_uint;
-      cl_mem_object_type _cl_mem_object_type;
-    } value;
-  } generic_info;
+typedef enum {
+  generic_info_type_cl_uint,
+  generic_info_type_cl_mem_object_type,
+} generic_info_type_t;
+typedef struct {
+  generic_info_type_t type;
+  union value_t {
+    cl_uint _cl_uint;
+    cl_mem_object_type _cl_mem_object_type;
+  } value;
+} generic_info;
 
-  int get_cl_version(void);
-  void* get_platforms(void** ptr_platforms, uint32_t* num_platforms);
-  void* platform__get_info(void* ptr_platform, cl_platform_info param_name, char** out);
-  void* platform__get_devices(void* ptr_platform, void** ptr_devices, uint32_t* num_devices, cl_device_type devtype);
-  void* device__get_info(void* ptr_device, cl_device_info param_name, char** out);
-  long device__hash(void *ptr_device);
-  void* _create_context(void** ptr_ctx, cl_context_properties* properties, cl_uint num_devices, void** ptr_devices);
-  void* _create_command_queue(void** ptr_command_queue, void* ptr_context, void* ptr_device, cl_command_queue_properties properties);
-  void* _create_buffer(void** ptr_buffer, void* ptr_context, cl_mem_flags flags, size_t size, void* hostbuf);
-  void* _create_program_with_source(void **ptr_program, void *ptr_context, char* src);
-  void* _create_program_with_binary(void **ptr_program, void *ptr_context, cl_uint num_devices, void** ptr_devices, cl_uint num_binaries, char** binaries);
-  void* program__build(void* ptr_program, char* options, cl_uint num_devices, void** ptr_devices);
-  void* program__kind(void* ptr_program, int *kind);
-  void* program__get_info__devices(void* ptr_program, void** ptr_devices, uint32_t* num_devices);
-  void* program__get_info__binaries(void* ptr_program, char*** ptr_binaries, uint32_t* num_binaries);
-  void* _create_kernel(void** ptr_kernel, void* ptr_program, char* name);
-  void* kernel__get_info(void *ptr_kernel, cl_kernel_info param, generic_info* out);
-  void* kernel__set_arg_mem_buffer(void* ptr_kernel, cl_uint arg_index, void* ptr_buffer);
-  void* _enqueue_nd_range_kernel(void **ptr_event, void* ptr_command_queue, void* ptr_kernel, cl_uint work_dim, const size_t* global_work_offset, const size_t* global_work_size, const size_t* local_work_size);
-  void* _enqueue_read_buffer(void **ptr_event, void* ptr_command_queue, void* ptr_memory_object_holder, void* buffer, size_t size, size_t device_offset, int is_blocking);
-  void* memory_object_holder__get_info(void* ptr_memory_object_holder, cl_mem_info param, generic_info* out);
-  void freem(void*);
+typedef struct {
+  const char* type;
+  const char* name;
+  unsigned int value;
+} constant;
+
+int get_cl_version(void);
+void* get_platforms(void** ptr_platforms, uint32_t* num_platforms);
+void* platform__get_info(void* ptr_platform, cl_platform_info param_name, char** out);
+void* platform__get_devices(void* ptr_platform, void** ptr_devices, uint32_t* num_devices, cl_device_type devtype);
+void* device__get_info(void* ptr_device, cl_device_info param_name, char** out);
+long device__hash(void *ptr_device);
+void* _create_context(void** ptr_ctx, cl_context_properties* properties, cl_uint num_devices, void** ptr_devices);
+void* _create_command_queue(void** ptr_command_queue, void* ptr_context, void* ptr_device, cl_command_queue_properties properties);
+void* _create_buffer(void** ptr_buffer, void* ptr_context, cl_mem_flags flags, size_t size, void* hostbuf);
+void* _create_program_with_source(void **ptr_program, void *ptr_context, char* src);
+void* _create_program_with_binary(void **ptr_program, void *ptr_context, cl_uint num_devices, void** ptr_devices, cl_uint num_binaries, char** binaries);
+void* program__build(void* ptr_program, char* options, cl_uint num_devices, void** ptr_devices);
+void* program__kind(void* ptr_program, int *kind);
+void* program__get_info__devices(void* ptr_program, void** ptr_devices, uint32_t* num_devices);
+void* program__get_info__binaries(void* ptr_program, char*** ptr_binaries, uint32_t* num_binaries);
+void* _create_kernel(void** ptr_kernel, void* ptr_program, char* name);
+void* kernel__get_info(void *ptr_kernel, cl_kernel_info param, generic_info* out);
+void* kernel__set_arg_mem_buffer(void* ptr_kernel, cl_uint arg_index, void* ptr_buffer);
+void* _enqueue_nd_range_kernel(void **ptr_event, void* ptr_command_queue, void* ptr_kernel, cl_uint work_dim, const size_t* global_work_offset, const size_t* global_work_size, const size_t* local_work_size);
+void* _enqueue_read_buffer(void **ptr_event, void* ptr_command_queue, void* ptr_memory_object_holder, void* buffer, size_t size, size_t device_offset, int is_blocking);
+void* memory_object_holder__get_info(void* ptr_memory_object_holder, cl_mem_info param, generic_info* out);
+void get_constants(constant** out, uint32_t *num_constants);
+void freem(void*);