Skip to content

Commit

Permalink
Convert wrapper to ahead-of-time, verified build (some extensions mis…
Browse files Browse the repository at this point in the history
…sing so far)
  • Loading branch information
inducer committed Jun 29, 2015
1 parent 67735ea commit e3802ba
Show file tree
Hide file tree
Showing 48 changed files with 222 additions and 419 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -60,3 +60,5 @@ virtualenv-[0-9]*
pytest.xml
setuptools*tar.gz
build-and-test-py-project.sh

cffi_build.py
2 changes: 2 additions & 0 deletions MANIFEST.in
Expand Up @@ -4,6 +4,7 @@ include pyopencl/cl/*.cl
include src/c_wrapper/*.hpp
include src/c_wrapper/*.h
include src/c_wrapper/*.cpp
include *.h
include test/*.py
include test/*.h
include examples/*.py
Expand All @@ -16,6 +17,7 @@ include doc/source/conf.py
include doc/source/_static/*.css
include doc/source/_templates/*.html

include *.py.in
include configure.py
include Makefile.in
include aksetup_helper.py
Expand Down
93 changes: 93 additions & 0 deletions cffi_build.py.in
@@ -0,0 +1,93 @@
from __future__ import absolute_import, print_function

__copyright__ = """
Copyright (C) 2009-15 Andreas Kloeckner
Copyright (C) 2013 Marko Bencun
Copyright (C) 2014 Yuyi Chao
"""

__license__ = """
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""


from cffi import FFI

ffi = FFI()


with open("cl_types.h", "rt") as f:
ffi.cdef(f.read())

if {CL_ENABLE_GL}:
with open("cl_gl_types.h") as f:
ffi.cdef(f.read())

with open("src/c_wrapper/wrap_cl_core.h", "rt") as f:
ffi.cdef(f.read())

if {CL_ENABLE_GL}:
with open("wrap_cl_gl_core.h") as f:
ffi.cdef(f.read())

ffi.set_source("pyopencl._cffi",
"""
#include <CL/cl.h>

extern "C" {{
#include <wrap_cl_core.h>
#ifdef HAVE_GL
#include <wrap_cl_gl_core.h>
#endif
}}
""",
define_macros=list({EXTRA_DEFINES}.items()),
include_dirs=(
{CL_INC_DIR} + ["src/c_wrapper/"]),
library_dirs={CL_LIB_DIR},
libraries={CL_LIBNAME},
extra_compile_args=(
['-std=c++0x'] + {CXXFLAGS}),
extra_link_args={LDFLAGS},
source_extension=".cpp",
sources=[
"src/c_wrapper/wrap_cl.cpp",
"src/c_wrapper/wrap_constants.cpp",
"src/c_wrapper/bitlog.cpp",
"src/c_wrapper/pyhelper.cpp",
"src/c_wrapper/platform.cpp",
"src/c_wrapper/device.cpp",
"src/c_wrapper/context.cpp",
"src/c_wrapper/command_queue.cpp",
"src/c_wrapper/event.cpp",
"src/c_wrapper/memory_object.cpp",
"src/c_wrapper/image.cpp",
"src/c_wrapper/gl_obj.cpp",
"src/c_wrapper/memory_map.cpp",
"src/c_wrapper/buffer.cpp",
"src/c_wrapper/sampler.cpp",
"src/c_wrapper/program.cpp",
"src/c_wrapper/kernel.cpp",
"src/c_wrapper/debug.cpp",
]
)


if __name__ == "__main__":
ffi.compile()
12 changes: 12 additions & 0 deletions cl_gl_types.h
@@ -0,0 +1,12 @@
/* cl_gl.h */
typedef cl_uint cl_gl_object_type;
typedef cl_uint cl_gl_texture_info;
typedef cl_uint cl_gl_platform_info;
typedef struct __GLsync *cl_GLsync;
typedef cl_uint cl_gl_context_info;

/* cl_egl.h */
typedef void* CLeglImageKHR;
typedef void* CLeglDisplayKHR;
typedef void* CLeglSyncKHR;
typedef intptr_t cl_egl_image_properties_khr;
127 changes: 3 additions & 124 deletions pyopencl/_cffi.py → cl_types.h
@@ -1,9 +1,3 @@
from __future__ import absolute_import
from cffi import FFI

_ffi = FFI()
_cl_header = """
/* gl.h */
typedef unsigned int GLenum;
typedef int GLint; /* 4-byte signed */
Expand Down Expand Up @@ -110,6 +104,8 @@
} cl_buffer_region;

/* cl_ext.h */

/*
typedef cl_ulong cl_device_partition_property_ext;
typedef cl_uint cl_image_pitch_info_qcom;
typedef struct _cl_mem_ext_host_ptr {
Expand All @@ -123,121 +119,4 @@
} cl_mem_ion_host_ptr;
typedef cl_bitfield cl_mem_migration_flags_ext;
/* cl_gl.h */
typedef cl_uint cl_gl_object_type;
typedef cl_uint cl_gl_texture_info;
typedef cl_uint cl_gl_platform_info;
typedef struct __GLsync *cl_GLsync;
typedef cl_uint cl_gl_context_info;
/* cl_egl.h */
typedef void* CLeglImageKHR;
typedef void* CLeglDisplayKHR;
typedef void* CLeglSyncKHR;
typedef intptr_t cl_egl_image_properties_khr;
/* c++ class pointer */
typedef struct clbase *clobj_t;
"""


def _get_wrap_header(filename):
from pkg_resources import Requirement, resource_filename
header_name = resource_filename(
Requirement.parse("pyopencl"), "pyopencl/c_wrapper/"+filename)

with open(header_name, "rt") as f:
return f.read()

_ffi.cdef(_cl_header)
_ffi.cdef(_get_wrap_header("wrap_cl_core.h"))


# Copied from pypy distutils/commands/build_ext.py
def _get_c_extension_suffix():
import imp
for ext, mod, typ in imp.get_suffixes():
if typ == imp.C_EXTENSION:
return ext


def _get_wrapcl_so_names():
import os.path
current_directory = os.path.dirname(__file__)

# TODO: windows debug_mode?

# Copied from pypy's distutils that "should work for CPython too".
ext_suffix = _get_c_extension_suffix()
if ext_suffix is not None:
yield os.path.join(current_directory, "_wrapcl" + ext_suffix)

# Oh god. Chop hyphen-separated bits off the end, in the hope that
# something matches...

root, ext = os.path.splitext(ext_suffix)
while True:
last_hyphen = root.rfind("-")
if last_hyphen == -1:
break
root = root[:last_hyphen]
yield os.path.join(current_directory, "_wrapcl" + root + ext)

yield os.path.join(current_directory, "_wrapcl" + ext)

from distutils.sysconfig import get_config_var
# "SO" is apparently deprecated, but changing this to "EXT_SUFFIX"
# as recommended breaks Py2 and PyPy3, as reported by @yuyichao
# on 2014-07-20.
#
# You've been warned. Change "SO" with care.
yield os.path.join(current_directory, "_wrapcl" + get_config_var("SO"))


def _import_library():
names = list(_get_wrapcl_so_names())
for name in names:
try:
return _ffi.dlopen(name)
except OSError:
pass

raise RuntimeError("could not find PyOpenCL wrapper library. (tried: %s)"
% ", ".join(names))

_lib = _import_library()

if _lib.have_gl():
_ffi.cdef(_get_wrap_header("wrap_cl_gl_core.h"))

import gc
_py_gc = _ffi.callback('int(void)')(gc.collect)

_pyrefs = {}


@_ffi.callback('void(void*)')
def _py_deref(handle):
try:
del _pyrefs[handle]
except:
pass


# return a new reference of the object pointed to by the handle.
# The return value might be different with the input (on PyPy).
# _py_deref should be called (once) when the object is not needed anymore.
@_ffi.callback('void*(void*)')
def _py_ref(handle):
obj = _ffi.from_handle(handle)
handle = _ffi.new_handle(obj)
_pyrefs[handle] = handle
return handle


@_ffi.callback('void(void*, cl_int)')
def _py_call(handle, status):
_ffi.from_handle(handle)(status)

_lib.set_py_funcs(_py_gc, _py_ref, _py_deref, _py_call)
*/
50 changes: 43 additions & 7 deletions pyopencl/cffi_cl.py
@@ -1,8 +1,4 @@
from __future__ import division
from __future__ import absolute_import
from six.moves import map
from six.moves import range
from six.moves import zip
from __future__ import division, absolute_import

__copyright__ = """
Copyright (C) 2013 Marko Bencun
Expand Down Expand Up @@ -30,14 +26,54 @@
THE SOFTWARE.
"""

from six.moves import map, range, zip

import warnings
import numpy as np
import sys

from pyopencl._cffi import _ffi, _lib
from pyopencl._cffi import ffi as _ffi
from .compyte.array import f_contiguous_strides, c_contiguous_strides

_lib = _ffi.dlopen(None)

# {{{ hook up connections between the wrapper and the interperter

import gc
_py_gc = _ffi.callback('int(void)')(gc.collect)

_pyrefs = {}


@_ffi.callback('void(void*)')
def _py_deref(handle):
try:
del _pyrefs[handle]
except:
pass


# return a new reference of the object pointed to by the handle.
# The return value might be different with the input (on PyPy).
# _py_deref should be called (once) when the object is not needed anymore.
@_ffi.callback('void*(void*)')
def _py_ref(handle):
obj = _ffi.from_handle(handle)
handle = _ffi.new_handle(obj)
_pyrefs[handle] = handle
return handle


@_ffi.callback('void(void*, cl_int)')
def _py_call(handle, status):
_ffi.from_handle(handle)(status)


_lib.set_py_funcs(_py_gc, _py_ref, _py_deref, _py_call)

# }}}


# {{{ compatibility shims

# are we running on pypy?
Expand Down Expand Up @@ -406,7 +442,7 @@ class migrate_mem_object_flags_ext(_NoInit): # noqa
_locals = locals()


@_ffi.callback('void(const char*, const char* name, long value)')
@_ffi.callback('void (*)(const char*, const char* name, long value)')
def _constant_callback(type_, name, value):
setattr(_locals[_ffi_pystr(type_)], _ffi_pystr(name), value) # noqa

Expand Down
2 changes: 1 addition & 1 deletion pyopencl/tools.py
Expand Up @@ -35,7 +35,7 @@
from decorator import decorator
import pyopencl as cl
from pytools import memoize, memoize_method
from pyopencl._cffi import _lib
from pyopencl.cffi_cl import _lib

import re

Expand Down

0 comments on commit e3802ba

Please sign in to comment.