Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to Install ACH Module and Python API Version Mismatch #18

Open
Jarvis-Geun opened this issue Aug 17, 2023 · 2 comments
Open

Unable to Install ACH Module and Python API Version Mismatch #18

Jarvis-Geun opened this issue Aug 17, 2023 · 2 comments

Comments

@Jarvis-Geun
Copy link

I've been attempting to install the ACH module by following the instructions provided on the INSTALL page. Initially, I tried downloading and installing the module using the link provided: http://code.golems.org/src/ach/py_ach-latest.tar.gz. However, it seems that the file is currently not valid, and I'm unable to proceed with the installation using this method.

Subsequently, I followed the instructions on the INSTALL page and attempted to build the setup.py file. However, during this process, I encountered the following error message:

<frozen importlib._bootstrap>:219: RuntimeWarning: Python C API version mismatch for module ach_py: This Python has API version 1013, module ach_py has version -1522732640.

Installation Steps Attempted:

1. Cloned the repository: git clone https://github.com/golems/ach.git
2. Navigated to the ach directory: cd ach
3. Initialized autotools: autoreconf -i
4. Configured the build: ./configure --with-python --enable-dkms=no
5. Executed the build: make
6. Installed the module: sudo make install
7. Navigated to the python directory: cd python
8. Modified the ach_py.c code to adapt it for Python 3 by changing functions like PyInt_AsLong to PyLong_AsLong.
9. Installed the module using Python 3: sudo python3 setup.py install

This is modified ach_py.c

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <Python.h>

#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/stat.h>

#include <string.h>
#include <inttypes.h>

#include "ach.h"

PyMODINIT_FUNC PyInit_ach_py(void);

static PyObject *ach_py_error;

static ach_channel_t *parse_channel_pointer( PyObject *i ) {
    if( PyLong_Check(i) ) {
        return (ach_channel_t*)PyLong_AsLong(i);
    } else if ( PyLong_Check(i) ) {
        return (ach_channel_t*)PyLong_AsVoidPtr(i);
    } else {
        PyErr_SetString( PyExc_TypeError, "invalid channel pointer" );
        return NULL;
    }
}

static PyObject  *raise_error( ach_status_t r ) {
    PyErr_SetString( ach_py_error, ach_result_to_string(r) );
    return NULL;
}

static PyObject *
ach_error( PyObject *self, PyObject *args ) {
    (void)self;
    int r;
    if( !PyArg_ParseTuple(args, "i", &r ) ) {
        return NULL;
    }
    return raise_error((ach_status_t)r);
}

static PyObject *
open_channel( PyObject *self, PyObject *args ) {
    (void)self;
    const char *name = NULL;
    long frame_count = 0, frame_size = 0;
    if( !PyArg_ParseTuple(args, "sll", &name, &frame_count, &frame_size ) ) {
        return NULL;
    }
    /* Alloc struct */
    ach_channel_t *c = (ach_channel_t*)malloc(sizeof(ach_channel_t));

    /* Open it */
    ach_status_t r = ach_open(c, name, NULL);

    /* Create channel if necessary */
    if( ACH_ENOENT == r ) {
        r = ach_create( name, (size_t)frame_count, (size_t)frame_size, NULL );
        if( ach_status_match(r, ACH_MASK_OK | ACH_MASK_EEXIST) ) {
            r = ach_open(c, name, NULL);
        }
    }

    /* Check result */
    if( ACH_OK != r ) {
        return raise_error(r);
    }

    return PyLong_FromVoidPtr(c);
}

static PyObject *
close_channel( PyObject *self, PyObject *args ) {
    (void)self;

    PyObject *py_chan;
    if( !PyArg_ParseTuple(args, "O", &py_chan) ) {
        return NULL;
    }

    ach_channel_t *c = parse_channel_pointer(py_chan);
    if( NULL == c ) {
        return NULL;
    }

    ach_status_t r = ach_close(c);
    if( ACH_OK != r ) {
        return raise_error(r);
    }

    free(c);

    Py_RETURN_NONE;
}

static PyObject *
result_string( PyObject *self, PyObject *args ) {
    (void)self;
    int r;
    if( !PyArg_ParseTuple(args, "i", &r ) ) {
        return NULL;
    }
    return PyUnicode_FromString( ach_result_to_string((enum ach_status)r) );
}

static PyObject *
put_buf( PyObject *self, PyObject *args ) {
    (void)self;

    PyObject *py_chan, *b;
    // get arg objects
    if( !PyArg_ParseTuple(args, "OO", &py_chan, &b) ) {
        return NULL;
    }

    // parse channel
    ach_channel_t *c = parse_channel_pointer(py_chan);
    if( NULL == c ) {
        return NULL;
    }

    // parse buffer
    if( ! PyObject_CheckBuffer(b) ) {
        PyErr_SetString( PyExc_TypeError, "invalid buffer" );
        return NULL;
    }

    // view buffer
    Py_buffer buf;
    if( PyObject_GetBuffer( b, &buf, PyBUF_SIMPLE ) ) {
        PyErr_SetString( PyExc_BufferError, "couldn't view buffer" );
        return NULL;
    }

    // make the damn call
    ach_status_t r = ach_put( c, buf.buf, (size_t)buf.len );

    // check the result
    if( ACH_OK != r ) {
        PyErr_SetString( ach_py_error, ach_result_to_string(r) );
        return NULL;
    }

    // cleanup
    PyBuffer_Release(&buf);
    Py_RETURN_NONE;
}

static PyObject *
get_buf( PyObject *self, PyObject *args ) {
    (void)self;

    PyObject *py_chan, *b;
    int wait, last;
    // get arg objects
    if( !PyArg_ParseTuple(args, "OOii", &py_chan, &b, &wait, &last) ) {
        return NULL;
    }

    // parse channel
    ach_channel_t *c = parse_channel_pointer(py_chan);
    if( NULL == c ) {
        return NULL;
    }

    // parse buffer
    if( ! PyObject_CheckBuffer(b) ) {
        PyErr_SetString( PyExc_TypeError, "invalid buffer" );
        return NULL;
    }

    // view buffer
    Py_buffer buf;
    if( PyObject_GetBuffer( b, &buf, PyBUF_WRITABLE ) ) {
        PyErr_SetString( PyExc_BufferError, "couldn't view writable buffer" );
        return NULL;
    }

    // parse opts
    int opts = 0;
    if (wait) opts |= ACH_O_WAIT;
    if (last) opts |= ACH_O_LAST;

    // make the damn call
    size_t frame_size;
    ach_status_t r = ach_get( c, buf.buf, (size_t)buf.len,
                              &frame_size, NULL, opts );
    // cleanup
    PyBuffer_Release(&buf);

    // return
    switch(r) {
    case ACH_OK:
    case ACH_STALE_FRAMES:
    case ACH_MISSED_FRAME:
    case ACH_TIMEOUT:
    case ACH_CANCELED:
        return Py_BuildValue("ik", r, frame_size);

    case ACH_OVERFLOW:
    case ACH_INVALID_NAME:
    case ACH_BAD_SHM_FILE:
    case ACH_FAILED_SYSCALL:
    case ACH_CLOSED:
    case ACH_EEXIST:
    case ACH_ENOENT:
    case ACH_BUG:
    case ACH_EINVAL:
    case ACH_CORRUPT:
    case ACH_BAD_HEADER:
    case ACH_EACCES:
    case ACH_EINTR:
    case ACH_EFAULT:
    case ACH_ENOTSUP:
        return raise_error(r);
    }

    return NULL;

}

static PyObject *
flush_channel( PyObject *self, PyObject *args ) {
    (void)self;

    PyObject *py_chan;
    // get arg objects
    if( !PyArg_ParseTuple(args, "O", &py_chan) ) {
        return NULL;
    }

    // parse channel
    ach_channel_t *c = parse_channel_pointer(py_chan);
    if( NULL == c ) {
        return NULL;
    }

    // make the damn call
    ach_status_t r = ach_flush( c );

    // check the result
    if( ACH_OK != r ) {
        PyErr_SetString( ach_py_error, ach_result_to_string(r) );
        return NULL;
    }

    // cleanup
    Py_RETURN_NONE;
}

static PyObject *
chmod_channel( PyObject *self, PyObject *args ) {
    (void)self;

    PyObject *py_chan;
    int mode;
    // get arg objects
    if( !PyArg_ParseTuple(args, "Oi", &py_chan, &mode) ) {
        return NULL;
    }

    // parse channel
    ach_channel_t *c = parse_channel_pointer(py_chan);
    if( NULL == c ) {
        return NULL;
    }

    // make the damn call
    ach_status_t r = ach_chmod( c, (mode_t)mode );

    // check the result
    if( ACH_OK != r ) {
        PyErr_SetString( ach_py_error, ach_result_to_string(r) );
        return NULL;
    }

    // cleanup
    Py_RETURN_NONE;
}

static PyObject *
unlink_channel( PyObject *self, PyObject *args ) {
    (void)self;

    const char *name;
    // get arg objects
    if( !PyArg_ParseTuple(args, "s", &name) )  {
        return NULL;
    }

    // make the damn call
    ach_status_t r = ach_unlink( name );

    // check the result
    if( ACH_OK != r ) {
        PyErr_SetString( ach_py_error, ach_result_to_string(r) );
        return NULL;
    }

    // cleanup
    Py_RETURN_NONE;
}


static PyMethodDef module_methods[] = {
   { "open_channel", (PyCFunction)open_channel, METH_VARARGS, NULL },
   { "close_channel", (PyCFunction)close_channel, METH_VARARGS, NULL },
   { "put_buf", (PyCFunction)put_buf, METH_VARARGS, NULL },
   { "get_buf", (PyCFunction)get_buf, METH_VARARGS, NULL },
   { "ach_error", (PyCFunction)ach_error, METH_VARARGS, NULL },
   { "result_string", (PyCFunction)result_string, METH_VARARGS, NULL },
   { "flush_channel", (PyCFunction)flush_channel, METH_VARARGS, NULL },
   { "chmod_channel", (PyCFunction)chmod_channel, METH_VARARGS, NULL },
   { "unlink_channel", (PyCFunction)unlink_channel, METH_VARARGS, NULL },
   { NULL, NULL, 0, NULL }
};

static struct PyModuleDef module = {
    PyModuleDef_HEAD_INIT,
    "ach_py",  /* name of module */
    NULL,      /* module documentation, may be NULL */
    -1,        /* size of per-interpreter state of the module,
                  or -1 if the module keeps state in global variables. */
    module_methods
};

PyMODINIT_FUNC PyInit_ach_py(void) {
    PyObject *m;

    // methods
    m = PyModule_Create2(&module, module_methods);
    if( NULL == m ) {
        return NULL;
    }

    // error object
    static char errname[] =  "ach_py.AchException";
    ach_py_error = PyErr_NewException( errname, NULL, NULL);
    Py_INCREF( ach_py_error ); // Reference counts?  Get with the program python!
    PyModule_AddObject(m, "AchException", ach_py_error);

    // keyword/const objects
    PyModule_AddObject( m, "ACH_OK",               PyLong_FromLong( ACH_OK ) );
    PyModule_AddObject( m, "ACH_OVERFLOW",         PyLong_FromLong( ACH_OVERFLOW ) );
    PyModule_AddObject( m, "ACH_INVALID_NAME",     PyLong_FromLong( ACH_INVALID_NAME ) );
    PyModule_AddObject( m, "ACH_BAD_SHM_FILE",     PyLong_FromLong( ACH_BAD_SHM_FILE ) );
    PyModule_AddObject( m, "ACH_FAILED_SYSCALL",   PyLong_FromLong( ACH_FAILED_SYSCALL ) );
    PyModule_AddObject( m, "ACH_STALE_FRAMES",     PyLong_FromLong( ACH_STALE_FRAMES ) );
    PyModule_AddObject( m, "ACH_EAGAIN"      ,     PyLong_FromLong( ACH_EAGAIN ) );
    PyModule_AddObject( m, "ACH_LOCKED"      ,     PyLong_FromLong( ACH_LOCKED ) );
    PyModule_AddObject( m, "ACH_MISSED_FRAME",     PyLong_FromLong( ACH_MISSED_FRAME ) );
    PyModule_AddObject( m, "ACH_TIMEOUT",          PyLong_FromLong( ACH_TIMEOUT ) );
    PyModule_AddObject( m, "ACH_EEXIST",           PyLong_FromLong( ACH_EEXIST ) );
    PyModule_AddObject( m, "ACH_ENOENT",           PyLong_FromLong( ACH_ENOENT ) );
    PyModule_AddObject( m, "ACH_CLOSED",           PyLong_FromLong( ACH_CLOSED ) );
    PyModule_AddObject( m, "ACH_BUG",              PyLong_FromLong( ACH_BUG ) );
    PyModule_AddObject( m, "ACH_EINVAL",           PyLong_FromLong( ACH_EINVAL ) );
    PyModule_AddObject( m, "ACH_CORRUPT",          PyLong_FromLong( ACH_CORRUPT ) );
    PyModule_AddObject( m, "ACH_CANCELED",         PyLong_FromLong( ACH_CANCELED ) );
    PyModule_AddObject( m, "ACH_BAD_HEADER",       PyLong_FromLong( ACH_BAD_HEADER ) );
    PyModule_AddObject( m, "ACH_EACCES",           PyLong_FromLong( ACH_EACCES ) );
    PyModule_AddObject( m, "ACH_O_WAIT",           PyLong_FromLong( ACH_O_WAIT ) );
    PyModule_AddObject( m, "ACH_O_LAST",           PyLong_FromLong( ACH_O_LAST ) );
    /* PyModule_AddObject( m, "ACH_DEFAULT_FRAME_SIZE",   PyLong_FromLong( ACH_DEFAULT_FRAME_SIZE ) ); */
    /* PyModule_AddObject( m, "ACH_DEFAULT_FRAME_COUNT",  PyLong_FromLong( ACH_DEFAULT_FRAME_COUNT ) ); */

    return m;
}

Expected Outcome:
I expected to be able to successfully install the ACH module using the provided source and instructions. However, I encountered the aforementioned error related to the Python C API version mismatch.

Additional Information:

Operating System: x86_64 (amd64)
Python Version: Python 3.8 with anaconda3

Steps to Reproduce:

Clone the ACH repository: git clone https://github.com/golems/ach.git
Follow the installation steps outlined above.

Desired Solution:
I would appreciate any guidance or suggestions on how to resolve the Python C API version mismatch error and successfully install the ACH module.

Thank you for your assistance!

@ndantam
Copy link
Member

ndantam commented Aug 18, 2023

Looks like a python version issue.

  • Is it possible that a different python version is being used to build and then load the module?
  • what does /usr/bin/env python say?
  • Otherwise, could be related to python 3 compatibility.

@Jarvis-Geun
Copy link
Author

Thanks for your reply.

# Result of /usr/bin/env python => system python
/usr/bin/env: ‘python’: No such file or directory
# Result of /usr/bin/env python3 => system python
Python 3.8.10 (default, May 26 2023, 14:05:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ach
<frozen importlib._bootstrap>:219: RuntimeWarning: Python C API version mismatch for module ach_py: This Python has API version 1013, module ach_py has version 2132885920.

When I use anaconda3 with /usr/bin/env python and import ach_py, there is ModuleNotFoundError: No module named 'ach_py'

Python 3.8.17 (default, Jul  5 2023, 21:04:15) 
[GCC 11.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ach
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/geun-desk/ws/ach/python/ach.py", line 43, in <module>
    import ach_py
ModuleNotFoundError: No module named 'ach_py'

When I enter the command ./configure --with-python --enable-dkms=no, the output below is displayed, and it seems that the build is successful using Python version 3.8.

configure: CONFIGURATION SUMMARY
configure: =====================
configure: BUILD:               x86_64-pc-linux-gnu
configure: HOST:                x86_64-pc-linux-gnu
configure: DEBUG:               no
configure: PREFIX:              /usr/local
configure: PYTHON VERSION:      3.8
configure: BUILD JAVA LIB:      no
configure: INSTALL DKMS SOURCE: no
configure: BUILD DKMS MODULE:   no
configure: KBUILD LINUX MODULE: no

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants