Example #1
0
from cffi import FFI

ffibuilder = FFI()

definitions = ["-DACCOUNT_API=", "-DACCOUNT_NOINCLUDE"]
header = Path(__file__).resolve().parent / "account.h"
command = ["cc", "-E"] + definitions + [str(header)]
interface = check_output(command).decode("utf-8")

# remove possible \r characters on windows which
# would confuse cdef
_interface = [l.strip("\r") for l in interface.split("\n")]

# cdef() expects a single string declaring the C types, functions and
# globals needed to use the shared object. It must be in valid C syntax.
ffibuilder.cdef("\n".join(_interface))

# set_source() gives the name of the python extension module to
# produce, and some C source code as a string.  This C code needs
# to make the declared functions, types and globals available,
# so it is often just the "#include".
ffibuilder.set_source(
    "_pyaccount",
    """
     #include "account.h"
""",
)

ffibuilder.emit_c_code("_pyaccount.c")
Example #2
0
ffi = FFI()

ffi.set_source(
    "_flux._security",
    """
#include <flux/security/sign.h>


// TODO: remove this when we can use cffi 1.10
#ifdef __GNUC__
#pragma GCC visibility push(default)
#endif
            """,
)

cdefs = """
typedef int... ptrdiff_t;
typedef int... pid_t;
typedef ... va_list;
void free(void *ptr);

    """

with open("_security_preproc.h") as h:
    cdefs = cdefs + h.read()

ffi.cdef(cdefs)
if __name__ == "__main__":
    ffi.emit_c_code("_security.c")
Example #3
0
ffibuilder = FFI()

path = os.path.dirname(os.path.abspath(__file__))

cnt = []
with open(os.path.join(path, '..', 'libclingo-dl', 'clingo-dl.h')) as f:
    for line in f:
        if not re.match(r' *(#|//|extern *"C" *{|}$|$)', line):
            cnt.append(
                re.sub(r'[A-Z_]+_VISIBILITY_DEFAULT ', '', line).strip())
cnt.append(
    'extern "Python" bool pyclingodl_rewrite(clingo_ast_t *ast, void *data);')
code = '\n'.join(cnt)

ffibuilder.cdef(f'''\
typedef uint64_t clingo_symbol_t;
typedef struct clingo_ast_statement clingo_ast_statement_t;
typedef struct clingo_ast clingo_ast_t;
typedef struct clingo_control clingo_control_t;
typedef struct clingo_options clingo_options_t;
typedef struct clingo_model clingo_model_t;
typedef struct clingo_statistics clingo_statistics_t;
{code}
''')

ffibuilder.set_source("_clingodl", """\
#include "clingo-dl.h"
""")

ffibuilder.emit_c_code('_clingodl.c')
Example #4
0
#include <czmq.h>
#include "src/common/librlist/rlist.h"


// TODO: remove this when we can use cffi 1.10
#ifdef __GNUC__
#pragma GCC visibility push(default)
#endif
            """,
)

cdefs = """
typedef struct _zlistx_t zlistx_t;
typedef struct _zhashx_t zhashx_t;
typedef int... json_type;
typedef struct json_t json_t;
typedef struct json_error_t json_error_t;

void free (void *);

"""

with open("_rlist_preproc.h") as h:
    cdefs = cdefs + h.read()

ffi.cdef(cdefs)
if __name__ == "__main__":
    ffi.emit_c_code("_rlist.c")
    # Ensure target mtime is updated
    Path("_rlist.c").touch()
Example #5
0
def prepare(space, cdef, module_name, source, w_includes=None,
            w_extra_source=None):
    try:
        import cffi
        from cffi import FFI            # <== the system one, which
        from cffi import recompiler     # needs to be at least cffi 1.0.4
        from cffi import ffiplatform
    except ImportError:
        py.test.skip("system cffi module not found or older than 1.0.0")
    if cffi.__version_info__ < (1, 2, 0):
        py.test.skip("system cffi module needs to be at least 1.2.0")
    space.appexec([], """():
        import _cffi_backend     # force it to be initialized
    """)
    includes = []
    if w_includes:
        includes += space.unpackiterable(w_includes)
    assert module_name.startswith('test_')
    module_name = '_CFFI_' + module_name
    rdir = udir.ensure('recompiler', dir=1)
    rdir.join('Python.h').write(
        '#define PYPY_VERSION XX\n'
        '#define PyMODINIT_FUNC /*exported*/ void\n'
        )
    path = module_name.replace('.', os.sep)
    if '.' in module_name:
        subrdir = rdir.join(module_name[:module_name.index('.')])
        os.mkdir(str(subrdir))
    else:
        subrdir = rdir
    c_file  = str(rdir.join('%s.c'  % path))
    ffi = FFI()
    for include_ffi_object in includes:
        ffi.include(include_ffi_object._test_recompiler_source_ffi)
    ffi.cdef(cdef)
    ffi.set_source(module_name, source)
    ffi.emit_c_code(c_file)

    base_module_name = module_name.split('.')[-1]
    sources = []
    if w_extra_source is not None:
        sources.append(space.str_w(w_extra_source))
    ext = ffiplatform.get_extension(c_file, module_name,
            include_dirs=[str(rdir)],
            export_symbols=['_cffi_pypyinit_' + base_module_name],
            sources=sources)
    ffiplatform.compile(str(rdir), ext)

    for extension in ['so', 'pyd', 'dylib']:
        so_file = str(rdir.join('%s.%s' % (path, extension)))
        if os.path.exists(so_file):
            break
    else:
        raise Exception("could not find the compiled extension module?")

    args_w = [space.wrap(module_name), space.wrap(so_file)]
    w_res = space.appexec(args_w, """(modulename, filename):
        import imp
        mod = imp.load_dynamic(modulename, filename)
        assert mod.__name__ == modulename
        return (mod.ffi, mod.lib)
    """)
    ffiobject = space.getitem(w_res, space.wrap(0))
    ffiobject._test_recompiler_source_ffi = ffi
    if not hasattr(space, '_cleanup_ffi'):
        space._cleanup_ffi = []
    space._cleanup_ffi.append(ffiobject)
    return w_res
Example #6
0
# Remove function-like macros
declarations = re.sub(r"^#define \w+\(.*$",
                      "",
                      declarations,
                      flags=re.MULTILINE)
# Make macro value always be "..."
declarations = re.sub(r"^(#define \w+).*$",
                      lambda m: m.group(1) + " ...",
                      declarations,
                      flags=re.MULTILINE)
# Mark callbacks with special CFFI syntax
if args.callbacks_file:
    declarations = re.sub(r"^(.*\b" + callbacks_regex + r"\b.*)$",
                          lambda m: 'extern "Python+C" ' + m.group(1),
                          declarations,
                          flags=re.MULTILINE)
# Remove empty lines
declarations = re.sub(r"^\s*$\n", "", declarations, flags=re.MULTILINE)

try:
    builder = FFI()
    builder.cdef(declarations)
    builder.set_source(args.module_name, f'#include "{args.header_file}"')
    builder.emit_c_code(args.output_file)

except Exception as e:
    for lineno, line in enumerate(declarations.split("\n"), start=1):
        print(f"{lineno:3d}: {line}")
    print(e)
    sys.exit(1)
Example #7
0
from cffi import FFI

ffi = FFI()

ffi.set_source(
    "_flux._idset",
    """
#include <flux/idset.h>


// TODO: remove this when we can use cffi 1.10
#ifdef __GNUC__
#pragma GCC visibility push(default)
#endif
            """,
)

cdefs = """
static const unsigned int IDSET_INVALID_ID;
void free (void *);
"""

with open("_idset_preproc.h") as h:
    cdefs = cdefs + h.read()

ffi.cdef(cdefs)
if __name__ == "__main__":
    ffi.emit_c_code("_idset.c")
    # Ensure target mtime is updated
    Path("_idset.c").touch()
Example #8
0

void * unpack_long(ptrdiff_t num){
  return (void*)num;
}
// TODO: remove this when we can use cffi 1.10
#ifdef __GNUC__
#pragma GCC visibility push(default)
#endif
            """,
    libraries=["flux-core"],
)

cdefs = """
typedef int... ptrdiff_t;
typedef int... pid_t;
typedef ... va_list;
void * unpack_long(ptrdiff_t num);
void free(void *ptr);

    """

with open("_core_preproc.h") as h:
    cdefs = cdefs + h.read()

ffi.cdef(cdefs)
if __name__ == "__main__":
    ffi.emit_c_code("_core.c")
    # ensure mtime of target is updated
    Path("_core.c").touch()
Example #9
0
def generate_c(action):
    clingo_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))

    ffi = FFI()

    cnt = []
    with open(f'{clingo_dir}/libclingo/clingo.h') as f:
        for line in f:
            if not re.match(r' *(#|//|extern *"C" *{|}$|$)', line):
                cnt.append(
                    line.replace('CLINGO_VISIBILITY_DEFAULT ', '').strip())

    # callbacks
    cnt.append(
        'extern "Python" bool pyclingo_solve_event_callback(clingo_solve_event_type_t type, void *event, void *data, bool *goon);'
    )
    cnt.append(
        'extern "Python" void pyclingo_logger_callback(clingo_warning_t code, char const *message, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_ground_callback(clingo_location_t const *location, char const *name, clingo_symbol_t const *arguments, size_t arguments_size, void *data, clingo_symbol_callback_t symbol_callback, void *symbol_callback_data);'
    )
    # propagator callbacks
    cnt.append(
        'extern "Python" bool pyclingo_propagator_init(clingo_propagate_init_t *init, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_propagator_propagate(clingo_propagate_control_t *control, clingo_literal_t const *changes, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" void pyclingo_propagator_undo(clingo_propagate_control_t const *control, clingo_literal_t const *changes, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_propagator_check(clingo_propagate_control_t *control, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_propagator_decide(clingo_id_t thread_id, clingo_assignment_t const *assignment, clingo_literal_t fallback, void *data, clingo_literal_t *decision);'
    )
    # observer callbacks
    cnt.append(
        'extern "Python" bool pyclingo_observer_init_program(bool incremental, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_begin_step(void *data);')
    cnt.append('extern "Python" bool pyclingo_observer_end_step(void *data);')
    cnt.append(
        'extern "Python" bool pyclingo_observer_rule(bool choice, clingo_atom_t const *head, size_t head_size, clingo_literal_t const *body, size_t body_size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_weight_rule(bool choice, clingo_atom_t const *head, size_t head_size, clingo_weight_t lower_bound, clingo_weighted_literal_t const *body, size_t body_size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_minimize(clingo_weight_t priority, clingo_weighted_literal_t const* literals, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_project(clingo_atom_t const *atoms, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_output_atom(clingo_symbol_t symbol, clingo_atom_t atom, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_output_term(clingo_symbol_t symbol, clingo_literal_t const *condition, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_output_csp(clingo_symbol_t symbol, int value, clingo_literal_t const *condition, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_external(clingo_atom_t atom, clingo_external_type_t type, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_assume(clingo_literal_t const *literals, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_heuristic(clingo_atom_t atom, clingo_heuristic_type_t type, int bias, unsigned priority, clingo_literal_t const *condition, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_acyc_edge(int node_u, int node_v, clingo_literal_t const *condition, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_term_number(clingo_id_t term_id, int number, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_term_string(clingo_id_t term_id, char const *name, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_term_compound(clingo_id_t term_id, int name_id_or_type, clingo_id_t const *arguments, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_element(clingo_id_t element_id, clingo_id_t const *terms, size_t terms_size, clingo_literal_t const *condition, size_t condition_size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_atom(clingo_id_t atom_id_or_zero, clingo_id_t term_id, clingo_id_t const *elements, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_atom_with_guard(clingo_id_t atom_id_or_zero, clingo_id_t term_id, clingo_id_t const *elements, size_t size, clingo_id_t operator_id, clingo_id_t right_hand_side_id, void *data);'
    )
    # application callbacks
    cnt.append(
        'extern "Python" char const *pyclingo_application_program_name(void *data);'
    )
    cnt.append(
        'extern "Python" char const *pyclingo_application_version(void *data);'
    )
    cnt.append(
        'extern "Python" unsigned pyclingo_application_message_limit(void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_application_main(clingo_control_t *control, char const *const * files, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" void pyclingo_application_logger(clingo_warning_t code, char const *message, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_application_print_model(clingo_model_t const *model, clingo_default_model_printer_t printer, void *printer_data, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_application_register_options(clingo_options_t *options, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_application_validate_options(void *data);'
    )
    # application options callbacks
    cnt.append(
        'extern "Python" bool pyclingo_application_options_parse(char const *value, void *data);'
    )
    # ast callbacks
    cnt.append(
        'extern "Python" bool pyclingo_ast_callback(clingo_ast_t const *, void *);'
    )
    # script callbacks
    cnt.append(
        'extern "Python" bool pyclingo_script_execute(clingo_location_t *loc, char const *code, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_script_call(clingo_location_t *loc, char const *name, void *arguments, size_t size, void *symbol_callback, void *symbol_callback_data, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_script_callable(char const * name, bool *ret, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_script_main(clingo_control_t *ctl, void *data);'
    )

    code = ''

    if action == "embed":
        ffi.embedding_api('''\
bool pyclingo_execute(void *loc, char const *code, void *data);
bool pyclingo_call(void *loc, char const *name, void *arguments, size_t size, void *symbol_callback, void *symbol_callback_data, void *data);
bool pyclingo_callable(char const * name, bool *ret, void *data);
bool pyclingo_main(void *ctl, void *data);
''')

        ffi.embedding_init_code(f"""\
import os
import sys
import clingo.script

sys.path.insert(0, os.getcwd())
""")

        code = '''\
#ifdef CFFI_DLLEXPORT
#undef CFFI_DLLEXPORT
#define CFFI_DLLEXPORT
#endif
#ifdef PYPY_VERSION
void pyclingo_finalize() { }
#else
void pyclingo_finalize() {
    if (Py_IsInitialized()) {
        PyGILState_Ensure();
        Py_Finalize();
    }
}
#endif
'''
    else:
        cnt.append(
            'extern "Python" bool pyclingo_execute(void *loc, char const *code, void *data);'
        )
        cnt.append(
            'extern "Python" bool pyclingo_call(void *loc, char const *name, void *arguments, size_t size, void *symbol_callback, void *symbol_callback_data, void *data);'
        )
        cnt.append(
            'extern "Python" bool pyclingo_callable(char const * name, bool *ret, void *data);'
        )
        cnt.append(
            'extern "Python" bool pyclingo_main(void *ctl, void *data);')

    if action != "header":
        ffi.set_source('_clingo', f'''\
#include <clingo.h>
{code}
''')
        ffi.cdef('\n'.join(cnt))
        ffi.emit_c_code('_clingo.c')
    else:
        with open('_clingo.cdef', 'w') as f:
            f.write(''.join(f'{line}\n' for line in cnt))
Example #10
0
filenames = os.listdir(sys.argv[1])

# order header files by the same order that they are found in inside legato.h
# so that e.g. typedefs are not referenced before declaration

with open(os.path.join(os.environ["LEGATO_ROOT"], 'framework/include/', "legato.h")) as f:
    legatoh = f.readlines()

def index_in_legatoh(header):
    return next((lineno for lineno, line in enumerate(legatoh)
                if line.startswith('#include "%s"' % header)), 100)

filenames = sorted(filenames, key=lambda x: index_in_legatoh(x.replace('_cdef','')))


for fname in filenames:
    with open(os.path.join(sys.argv[1], fname)) as f:
        cdef += f.read() + "\n"
    m = re.search("le_(.+)_cdef.h",fname)
    if m:
        c_source += '#include <le_%s.h>\n' % m.group(1)
    else:
        print("Warning, wrong filename format for '%s', so we're not including the implementation header.")

ffibuilder.cdef(cdef)
ffibuilder.set_source("_liblegato_py", c_source)


if __name__ == "__main__":
    ffibuilder.emit_c_code(os.path.join(sys.argv[2], "_liblegato_py.c"))
Example #11
0
ffibuilder.set_source("gps_converter",
                      r"""
    #include <math.h>
    #include <wgs84.h>

    void gps_to_euclidean(size_t num_pts, long double *input, long double *output)
    {
        const long double to_rad = M_PI / 180.0l;

        size_t i;
        for(i = 0; i < num_pts; ++i) {
            wgs84_to_euclidean(
                input[i*3] * to_rad,
                input[i*3 + 1] * to_rad,
                input[i*3 + 2],
                &output[i*3]
            );
        }
    }
    """,
                      extra_objects=['build/libwgs84.a'],
                      include_dirs=['external/libwgs84/src'])

ffibuilder.cdef("""
    void gps_to_euclidean(size_t num_pts, long double *input, long double *output);
""")

if __name__ == "__main__":
    ffibuilder.emit_c_code("build/gps_converter.c")
Example #12
0

cdef_types_lines = read_file(cdef_types_fn)
cdef_api_lines = read_file(cdef_api_fn)
cdef_callback_lines = read_file(sample_callback_fn)

cdef_segments = []

cdef_segments.append(cdef_types_lines)
cdef_segments.append(cdef_api_lines)
cdef_segments.append(cdef_callback_lines)

print("len(cdef_segments): %d" % len(cdef_segments))

for ndx in range(len(cdef_segments)):
    print("ndx: %d" % ndx)
    ffibuilder.cdef(cdef_segments[ndx])

if nocompile:
    c_fn = "%s.c" % module_name
    ffibuilder.emit_c_code(c_fn)

else:
    ffibuilder.compile(verbose=True)

    # hack
    if sysver == 3:
        os.rename("_ddccffi3.cpython-36m-x86_64-linux-gnu.so", "_ddccffi3.so")
    # else:
    #     os.rename("_ddccffi.so", "_ddccffi2.so")
Example #13
0
ffibuilder = FFI()

path = os.path.dirname(os.path.abspath(__file__))

cnt = []
with open(os.path.join(path, '..', 'libclingcon', 'clingcon.h')) as f:
    for line in f:
        if not re.match(r' *(#|//|extern *"C" *{|}$|$)', line):
            cnt.append(
                re.sub(r'[A-Z_]+_VISIBILITY_DEFAULT ', '', line).strip())
cnt.append(
    'extern "Python" bool pyclingcon_rewrite(clingo_ast_t *ast, void *data);')
code = '\n'.join(cnt)

ffibuilder.cdef(f'''\
typedef uint64_t clingo_symbol_t;
typedef struct clingo_ast_statement clingo_ast_statement_t;
typedef struct clingo_ast clingo_ast_t;
typedef struct clingo_control clingo_control_t;
typedef struct clingo_options clingo_options_t;
typedef struct clingo_model clingo_model_t;
typedef struct clingo_statistics clingo_statistics_t;
{code}
''')

ffibuilder.set_source("_clingcon", """\
#include "clingcon.h"
""")

ffibuilder.emit_c_code('_clingcon.c')
Example #14
0
from cffi import FFI
from pathlib import Path

ffi = FFI()

ffi.set_source(
    "_flux._hostlist",
    """
#include <flux/hostlist.h>


// TODO: remove this when we can use cffi 1.10
#ifdef __GNUC__
#pragma GCC visibility push(default)
#endif
            """,
)

cdefs = """
    void free (void *);
"""

with open("_hostlist_preproc.h") as h:
    cdefs = cdefs + h.read()

ffi.cdef(cdefs)
if __name__ == "__main__":
    ffi.emit_c_code("_hostlist.c")
    # Ensure target mtime is updated, emit_c_code() may not do it
    Path("_hostlist.c").touch()
Example #15
0
cdef = ""

# Regexp for the C prototype of functions. Can be 'extern "Python" xxx yyyy'
functionProto = re.compile('^\w+ [\w\"]+( \w+)*\n*\(\n*( +.*\n)+\);\n*',
                           re.MULTILINE)
# Regexp for the service instance name
serviceInstancePtr = re.compile("const char\*\* \w*ServiceInstanceNamePtr;")
# FIXME: cffi produces an error for typedef with parameter of type le_result_t.
resultParam = re.compile("    le_result_t result,")

# Add the cdef of the included APIs (USETYPES in the .api file)
# But clean the cdef before to avoid errors.
for apiFile in glob.glob(os.path.dirname(cdef_path) + "/includedApi/*_cdef.h"):
    with open(apiFile) as f:
        # Remove the functions. Keep only the typedefs, the structures
        # and the constants
        data = re.sub(functionProto, "", f.read())
        data = re.sub(serviceInstancePtr, "", data)
        # TO REMOVE
        data = re.sub(resultParam, "int result,", data)
        cdef += data

# Add the main cdef file
with open(cdef_path) as f:
    cdef += f.read()

ffibuilder.cdef(cdef, override=True)

if __name__ == "__main__":
    ffibuilder.emit_c_code(os.path.join(out_dir, api_name+'_native.c'))
Example #16
0
beer_err
beer_renderer_add_sprite_node(struct BeerSprite *sprite, struct BeerRenderNode **r_node);

beer_err
beer_renderer_remove_node(struct BeerRenderNode *node);

enum BeerKeyCode
{
    BEER_KEY_UNKNOWN,
    BEER_KEY_W,
    BEER_KEY_A,
    BEER_KEY_S,
    BEER_KEY_D,
    BEER_KEY_ESC,
    BEER_KEY_SPACE,
    BEER_KEY_MAX
};

struct BeerKeyState
{
    bool pressed;
};

beer_err
beer_key_get_state(enum BeerKeyCode key, struct BeerKeyState *r_state);
""")

if __name__ == '__main__':
    ffibuilder.emit_c_code('_beer.c')
Example #17
0
import argparse

from cffi import FFI

ffibuilder = FFI()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--out", type=str, required=True)
    parser.add_argument("--cdef", type=str, required=True)
    parser.add_argument("--ext-name", type=str, required=True)
    parser.add_argument("--source", type=str, required=True)
    args = parser.parse_args()
    with open(args.cdef) as fp:
        ffibuilder.cdef(fp.read())
    with open(args.source) as fp:
        ffibuilder.set_source(args.ext_name, fp.read(), compiler_verbose=False)
    ffibuilder.emit_c_code(args.out)
Example #18
0
ffibuilder = FFI()

path = os.path.dirname(os.path.abspath(__file__))

cnt = []
with open(os.path.join(path, '..', 'libclingo-lpx', 'clingo-lpx.h')) as f:
    for line in f:
        if not re.match(r' *(#|//|extern *"C" *{|}$|$)', line):
            cnt.append(
                re.sub(r'[A-Z_]+_VISIBILITY_DEFAULT ', '', line).strip())
cnt.append(
    'extern "Python" bool pyclingolpx_rewrite(clingo_ast_t *ast, void *data);')
code = '\n'.join(cnt)

ffibuilder.cdef(f'''\
typedef uint64_t clingo_symbol_t;
typedef struct clingo_ast_statement clingo_ast_statement_t;
typedef struct clingo_ast clingo_ast_t;
typedef struct clingo_control clingo_control_t;
typedef struct clingo_options clingo_options_t;
typedef struct clingo_model clingo_model_t;
typedef struct clingo_statistics clingo_statistics_t;
{code}
''')

ffibuilder.set_source("_clingolpx", """\
#include "clingo-lpx.h"
""")

ffibuilder.emit_c_code('_clingolpx.c')
Example #19
0
def generate_c(action):
    clingo_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))

    ffi = FFI()

    cnt = []
    with open(f'{clingo_dir}/libclingo/clingo.h') as f:
        for line in f:
            if not re.match(r' *(#|//|extern *"C" *{|}$|$)', line):
                cnt.append(
                    line.replace('CLINGO_VISIBILITY_DEFAULT ', '').strip())

    # callbacks
    cnt.append(
        'extern "Python" bool pyclingo_solve_event_callback(clingo_solve_event_type_t type, void *event, void *data, bool *goon);'
    )
    cnt.append(
        'extern "Python" void pyclingo_logger_callback(clingo_warning_t code, char const *message, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_ground_callback(clingo_location_t const *location, char const *name, clingo_symbol_t const *arguments, size_t arguments_size, void *data, clingo_symbol_callback_t symbol_callback, void *symbol_callback_data);'
    )
    # propagator callbacks
    cnt.append(
        'extern "Python" bool pyclingo_propagator_init(clingo_propagate_init_t *init, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_propagator_propagate(clingo_propagate_control_t *control, clingo_literal_t const *changes, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" void pyclingo_propagator_undo(clingo_propagate_control_t const *control, clingo_literal_t const *changes, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_propagator_check(clingo_propagate_control_t *control, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_propagator_decide(clingo_id_t thread_id, clingo_assignment_t const *assignment, clingo_literal_t fallback, void *data, clingo_literal_t *decision);'
    )
    # observer callbacks
    cnt.append(
        'extern "Python" bool pyclingo_observer_init_program(bool incremental, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_begin_step(void *data);')
    cnt.append('extern "Python" bool pyclingo_observer_end_step(void *data);')
    cnt.append(
        'extern "Python" bool pyclingo_observer_rule(bool choice, clingo_atom_t const *head, size_t head_size, clingo_literal_t const *body, size_t body_size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_weight_rule(bool choice, clingo_atom_t const *head, size_t head_size, clingo_weight_t lower_bound, clingo_weighted_literal_t const *body, size_t body_size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_minimize(clingo_weight_t priority, clingo_weighted_literal_t const* literals, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_project(clingo_atom_t const *atoms, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_output_atom(clingo_symbol_t symbol, clingo_atom_t atom, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_output_term(clingo_symbol_t symbol, clingo_literal_t const *condition, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_output_csp(clingo_symbol_t symbol, int value, clingo_literal_t const *condition, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_external(clingo_atom_t atom, clingo_external_type_t type, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_assume(clingo_literal_t const *literals, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_heuristic(clingo_atom_t atom, clingo_heuristic_type_t type, int bias, unsigned priority, clingo_literal_t const *condition, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_acyc_edge(int node_u, int node_v, clingo_literal_t const *condition, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_term_number(clingo_id_t term_id, int number, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_term_string(clingo_id_t term_id, char const *name, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_term_compound(clingo_id_t term_id, int name_id_or_type, clingo_id_t const *arguments, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_element(clingo_id_t element_id, clingo_id_t const *terms, size_t terms_size, clingo_literal_t const *condition, size_t condition_size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_atom(clingo_id_t atom_id_or_zero, clingo_id_t term_id, clingo_id_t const *elements, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_observer_theory_atom_with_guard(clingo_id_t atom_id_or_zero, clingo_id_t term_id, clingo_id_t const *elements, size_t size, clingo_id_t operator_id, clingo_id_t right_hand_side_id, void *data);'
    )
    # application callbacks
    cnt.append(
        'extern "Python" char const *pyclingo_application_program_name(void *data);'
    )
    cnt.append(
        'extern "Python" char const *pyclingo_application_version(void *data);'
    )
    cnt.append(
        'extern "Python" unsigned pyclingo_application_message_limit(void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_application_main(clingo_control_t *control, char const *const * files, size_t size, void *data);'
    )
    cnt.append(
        'extern "Python" void pyclingo_application_logger(clingo_warning_t code, char const *message, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_application_print_model(clingo_model_t const *model, clingo_default_model_printer_t printer, void *printer_data, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_application_register_options(clingo_options_t *options, void *data);'
    )
    cnt.append(
        'extern "Python" bool pyclingo_application_validate_options(void *data);'
    )
    # application options callbacks
    cnt.append(
        'extern "Python" bool pyclingo_application_options_parse(char const *value, void *data);'
    )
    # ast callbacks
    cnt.append(
        'extern "Python" bool pyclingo_ast_callback(clingo_ast_t const *, void *);'
    )

    if action == "embed":
        ffi.embedding_api('''\
bool pyclingo_execute_(void *loc, char const *code, void *data);
bool pyclingo_call_(void *loc, char const *name, void *arguments, size_t size, void *symbol_callback, void *symbol_callback_data, void *data);
bool pyclingo_callable_(char const * name, bool *ret, void *data);
bool pyclingo_main_(void *ctl, void *data);
''')

        ffi.embedding_init_code(f"""\
from collections.abc import Iterable
from traceback import format_exception
import __main__
from clingo._internal import _ffi, _handle_error, _lib
from clingo.control import Control
from clingo.symbol import Symbol

def _cb_error_top_level(exception, exc_value, traceback):
    msg = "".join(format_exception(exception, exc_value, traceback))
    _lib.clingo_set_error(_lib.clingo_error_runtime, msg.encode())
    return False

@_ffi.def_extern(onerror=_cb_error_top_level)
def pyclingo_execute_(loc, code, data):
    exec(_ffi.string(code).decode(), __main__.__dict__, __main__.__dict__)
    return True

@_ffi.def_extern(onerror=_cb_error_top_level)
def pyclingo_call_(loc, name, arguments, size, symbol_callback, symbol_callback_data, data):
    symbol_callback = _ffi.cast('clingo_symbol_callback_t', symbol_callback)
    arguments = _ffi.cast('clingo_symbol_t*', arguments)
    context = _ffi.from_handle(data).data if data != _ffi.NULL else None
    py_name = _ffi.string(name).decode()
    fun = getattr(__main__ if context is None else context, py_name)

    args = []
    for i in range(size):
        args.append(Symbol(arguments[i]))

    ret = fun(*args)
    symbols = list(ret) if isinstance(ret, Iterable) else [ret]

    c_symbols = _ffi.new('clingo_symbol_t[]', len(symbols))
    for i, sym in enumerate(symbols):
        c_symbols[i] = sym._rep
    _handle_error(symbol_callback(c_symbols, len(symbols), symbol_callback_data))
    return True

@_ffi.def_extern(onerror=_cb_error_top_level)
def pyclingo_callable_(name, ret, data):
    py_name = _ffi.string(name).decode()
    ret[0] = py_name in __main__.__dict__ and callable(__main__.__dict__[py_name])
    return True

@_ffi.def_extern(onerror=_cb_error_top_level)
def pyclingo_main_(ctl, data):
    __main__.main(Control(_ffi.cast('clingo_control_t*', ctl)))
    return True
""")

    if action != "header":
        ffi.set_source('_clingo', '#include <clingo.h>')
        ffi.cdef('\n'.join(cnt))
        ffi.emit_c_code('_clingo.c')
    else:
        with open('_clingo.cdef', 'w') as f:
            f.write(''.join(f'{line}\n' for line in cnt))
Example #20
0
def prepare(space,
            cdef,
            module_name,
            source,
            w_includes=None,
            w_extra_source=None):
    try:
        import cffi
        from cffi import FFI  # <== the system one, which
        from cffi import recompiler  # needs to be at least cffi 1.0.4
        from cffi import ffiplatform
    except ImportError:
        py.test.skip("system cffi module not found or older than 1.0.0")
    if cffi.__version_info__ < (1, 2, 0):
        py.test.skip("system cffi module needs to be at least 1.2.0")
    space.appexec([], """():
        import _cffi_backend     # force it to be initialized
    """)
    includes = []
    if w_includes:
        includes += space.unpackiterable(w_includes)
    assert module_name.startswith('test_')
    module_name = '_CFFI_' + module_name
    rdir = udir.ensure('recompiler', dir=1)
    rdir.join('Python.h').write('#define PYPY_VERSION XX\n'
                                '#define PyMODINIT_FUNC /*exported*/ void\n')
    path = module_name.replace('.', os.sep)
    if '.' in module_name:
        subrdir = rdir.join(module_name[:module_name.index('.')])
        os.mkdir(str(subrdir))
    else:
        subrdir = rdir
    c_file = str(rdir.join('%s.c' % path))
    ffi = FFI()
    for include_ffi_object in includes:
        ffi.include(include_ffi_object._test_recompiler_source_ffi)
    ffi.cdef(cdef)
    ffi.set_source(module_name, source)
    ffi.emit_c_code(c_file)

    base_module_name = module_name.split('.')[-1]
    sources = []
    if w_extra_source is not None:
        sources.append(space.str_w(w_extra_source))
    ext = ffiplatform.get_extension(
        c_file,
        module_name,
        include_dirs=[str(rdir)],
        export_symbols=['_cffi_pypyinit_' + base_module_name],
        sources=sources)
    ffiplatform.compile(str(rdir), ext)

    for extension in ['so', 'pyd', 'dylib']:
        so_file = str(rdir.join('%s.%s' % (path, extension)))
        if os.path.exists(so_file):
            break
    else:
        raise Exception("could not find the compiled extension module?")

    args_w = [space.wrap(module_name), space.wrap(so_file)]
    w_res = space.appexec(
        args_w, """(modulename, filename):
        import imp
        mod = imp.load_dynamic(modulename, filename)
        assert mod.__name__ == modulename
        return (mod.ffi, mod.lib)
    """)
    ffiobject = space.getitem(w_res, space.wrap(0))
    ffiobject._test_recompiler_source_ffi = ffi
    if not hasattr(space, '_cleanup_ffi'):
        space._cleanup_ffi = []
    space._cleanup_ffi.append(ffiobject)
    return w_res