Repository: amaork/libi2c (language: python)

Issue:
Build failed: redefinition
redefinition of ‘union i2c_smbus_data’
redefinition of ‘struct i2c_msg’

FIXED by comment #include <linux/i2c.h> in src/i2c.h


Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index c82ccd7..92d56b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,9 @@ __pycache__/
 objs
 depend
 
+# ide things
+.vscode/
+
+# build dirs
+builddir/
+build/
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 89ebec6..f0d043b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,15 @@
 PYTHON		= python
 CC		= $(CROSS)gcc
 AR		= $(CROSS)ar
-CFLAGS		= -Wall -g -fPIC
+VERSION=$(shell head -n 1 VERSION)
+INCDIR = include
+CFLAGS		= -Wall -I$(INCDIR) -Wextra -g -fPIC -DLIBI2C_VERSION="$(VERSION)"
 LDSHFLAGS	= -rdynamic -shared 
 ARFLAGS		= rcv
 CODE_STYLE	= astyle --align-pointer=name --align-reference=name --suffix=none --break-blocks --pad-oper --pad-header --break-blocks --keep-one-line-blocks --indent-switches --indent=spaces
 
 SOURCES=$(filter-out src/pyi2c.c, $(wildcard src/*.c))
-HEADERS=$(wildcard src/*.h)
+HEADERS=$(wildcard $(INCDIR)/i2c/*.h)
 OBJECTS=$(SOURCES:.c=.o)
 TARGETS = libi2c.a libi2c.so pylibi2c.so
 
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..7dff5b8
--- /dev/null
+++ b/VERSION
@@ -0,0 +1,1 @@
+0.2.1
\ No newline at end of file
diff --git a/example/Makefile b/example/Makefile
index 85c9c8d..d835bc3 100644
--- a/example/Makefile
+++ b/example/Makefile
@@ -3,7 +3,7 @@ AR			= $(CROSS)ar
 CFLAGS		= -Wall -g
 LDSHFLAGS	= -rdynamic -shared 
 ARFLAGS		= rcv
-CFLAGS		+= -I../src
+CFLAGS		+= -I../include
 LDFLAGS		= -L.. -li2c -Wl,-R -Wl,..
 
 OBJDIR=../objs
diff --git a/example/i2c_tools.c b/example/i2c_tools.c
index 12768f5..e67bd5a 100644
--- a/example/i2c_tools.c
+++ b/example/i2c_tools.c
@@ -2,11 +2,11 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
-#include "i2c.h"
+#include "i2c/i2c.h"
 
 void print_i2c_data(const unsigned char *data, size_t len)
 {
-    int i = 0;
+    size_t i = 0;
 
     for (i = 0; i < len; i++) {
 
@@ -111,7 +111,8 @@ int main(int argc, char **argv)
     /* Print i2c device description */
     fprintf(stdout, "%s\n", i2c_get_device_desc(&device, i2c_dev_desc, sizeof(i2c_dev_desc)));
 
-    size_t i;
+    size_t i = 0;
+    ssize_t ret = 0;
     unsigned char buf[256];
     size_t buf_size = sizeof(buf);
     memset(buf, 0, buf_size);
@@ -137,7 +138,9 @@ int main(int argc, char **argv)
     fprintf(stdout, "Write data:\n");
     print_i2c_data(buf, buf_size);
 
-    if (i2c_write_handle(&device, 0x0, buf, buf_size) != buf_size) {
+    ret = i2c_write_handle(&device, 0x0, buf, buf_size);
+    if (ret != -1 || (size_t)ret != buf_size)
+    {
 
         fprintf(stderr, "Write i2c error!\n");
         exit(-4);
@@ -149,7 +152,9 @@ int main(int argc, char **argv)
     usleep(100000);
     memset(buf, 0, buf_size);
 
-    if (i2c_read_handle(&device, 0x0, buf, buf_size) != buf_size) {
+    ret = i2c_read_handle(&device, 0x0, buf, buf_size);
+    if (ret == -1 || (size_t)ret != buf_size)
+    {
 
         fprintf(stderr, "Read i2c error!\n");
         exit(-5);
diff --git a/example/i2c_without_internal_address.c b/example/i2c_without_internal_address.c
index f51ef7b..bd4306e 100644
--- a/example/i2c_without_internal_address.c
+++ b/example/i2c_without_internal_address.c
@@ -1,13 +1,14 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
-#include "i2c.h"
+#include "i2c/i2c.h"
 
-int main(int argc, char **argv)
+int main()
 {
     int fd;
     I2CDevice device;
     const char *data = "9876543";
+    ssize_t ret;
 
     /* First open i2c bus */
     if ((fd = i2c_open("/dev/i2c-0")) == -1) {
@@ -26,8 +27,9 @@ int main(int argc, char **argv)
     device.iaddr_bytes = 0; /* Set this to zero, and using i2c_ioctl_xxxx API will ignore chip internal address */
 
     /* Write data to i2c */
-    if (i2c_ioctl_write(&device, 0x0, data, strlen(data)) != strlen(data)) {
-
+    ret = i2c_ioctl_write(&device, 0x0, data, strlen(data));
+    if (ret == -1 || (size_t)ret != strlen(data))
+    {
         /* Error process */
     }
 
diff --git a/example/meson.build b/example/meson.build
new file mode 100644
index 0000000..c44338f
--- /dev/null
+++ b/example/meson.build
@@ -0,0 +1,15 @@
+examples = [
+  'i2c_tools',
+  'i2c_without_internal_address',
+]
+
+foreach example: examples
+  exe = executable(example, example + '.c',
+    link_with: libi2c,
+    include_directories: i2c_incdir,
+    c_args: [
+      cflags,
+      '-D_DEFAULT_SOURCE',
+    ],
+  )
+endforeach
\ No newline at end of file
diff --git a/src/i2c.h b/include/i2c/i2c.h
similarity index 100%
rename from src/i2c.h
rename to include/i2c/i2c.h
diff --git a/include/meson.build b/include/meson.build
new file mode 100644
index 0000000..d258ebd
--- /dev/null
+++ b/include/meson.build
@@ -0,0 +1,7 @@
+i2c_incdir = include_directories('.')
+
+# public headers
+install_headers(['i2c/i2c.h'],
+  # i2c.h can clash with linux/i2c.h, so we put it in a subdir
+  subdir: meson.project_name(),
+)
\ No newline at end of file
diff --git a/libi2c.wrap b/libi2c.wrap
new file mode 100644
index 0000000..b611c4f
--- /dev/null
+++ b/libi2c.wrap
@@ -0,0 +1,6 @@
+[wrap-git]
+url = https://github.com/mdegans/libi2c.git
+revision = master
+
+[provide]
+i2c=i2c_dep
\ No newline at end of file
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..c6979f1
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,44 @@
+project('i2c', ['c'],
+  version: run_command(
+    'head', '-n', '1', files('VERSION'),
+  ).stdout().strip(),
+  meson_version: '>= 0.56.0',
+  license: 'MIT',
+  default_options: [
+    'c_std=c11',
+    'warning_level=2',  # -Wall, -Wextra
+    'werror=true',  # -Werror
+  ],
+)
+
+# the c++ compiler object
+cc = meson.get_compiler('c')
+
+# global cflags (public, included in subprojects and pkg-config)
+cflags = ['-DLIBI2C_VERSION="' + meson.project_version() + '"']
+
+# per compiler cflags, if desired
+if cc.get_id() == 'clang'
+  cflags += []
+else
+  cflags += []
+endif
+
+# split the project version
+proj_ver = meson.project_version().split('.')
+# version minus patch revision
+proj_ver_short = proj_ver[0] + '.' + proj_ver[1]
+proj_ver_major = proj_ver[0]
+proj_ver_minor = proj_ver[1]
+proj_ver_patch = proj_ver[2]
+
+# all of this is used by configure_file on i2c_config.h.in
+proj_description = 'Linux userspace i2c operation library'
+proj_url = 'https://github.com/amaork/libi2c'
+binary_package = 'libi2c'
+origin = 'github'
+
+subdir('include')
+subdir('src')
+subdir('example')
+subdir('tests')
\ No newline at end of file
diff --git a/setup.py b/setup.py
index f2520b7..ab61535 100644
--- a/setup.py
+++ b/setup.py
@@ -4,13 +4,22 @@
 setup.py file for pylibi2c
 """
 
+import os
 from distutils.core import setup, Extension
 
-pylibi2c_module = Extension('pylibi2c', sources=['src/i2c.c', 'src/pyi2c.c'],)
+THIS_DIR = os.path.dirname(os.path.abspath(__file__))
+INC_DIR = os.path.join(THIS_DIR, 'include')
+VERSION = open('VERSION').read().strip()
+
+pylibi2c_module = Extension('pylibi2c',
+  sources=['src/i2c.c', 'src/pyi2c.c'],
+  extra_compile_args=['-DLIBI2C_VERSION="' + VERSION + '"'],
+  include_dirs=[INC_DIR],
+)
 
 setup(
     name='pylibi2c',
-    version='0.2',
+    version=VERSION,
     license='MIT',
     author='Amaork',
     author_email="amaork@gmail.com",
diff --git a/src/i2c.c b/src/i2c.c
index 4d556ef..2ce0d6e 100644
--- a/src/i2c.c
+++ b/src/i2c.c
@@ -5,8 +5,7 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <arpa/inet.h>
-#include "i2c.h"
-
+#include "i2c/i2c.h"
 
 /* I2C default delay */
 #define I2C_DEFAULT_DELAY 1
@@ -261,6 +260,7 @@ ssize_t i2c_read(const I2CDevice *device, unsigned int iaddr, void *buf, size_t
 ssize_t i2c_write(const I2CDevice *device, unsigned int iaddr, const void *buf, size_t len)
 {
     ssize_t remain = len;
+    ssize_t ret;
     size_t cnt = 0, size = 0;
     const unsigned char *buffer = buf;
     unsigned char delay = GET_I2C_DELAY(device->delay);
@@ -284,9 +284,11 @@ ssize_t i2c_write(const I2CDevice *device, unsigned int iaddr, const void *buf,
         /* Copy data to tmp_buf */
         memcpy(tmp_buf + device->iaddr_bytes, buffer, size);
 
-        /* Write to buf content to i2c device length is address length and write buffer length */
-        if (write(device->bus, tmp_buf, device->iaddr_bytes + size) != device->iaddr_bytes + size) {
-
+        /* Write to buf content to i2c device length  is address length and
+                write buffer length */
+        ret = write(device->bus, tmp_buf, device->iaddr_bytes + size);
+        if (ret == -1 || (size_t)ret != device->iaddr_bytes + size)
+        {
             perror("I2C write error:");
             return -1;
         }
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 0000000..85b2428
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,54 @@
+# source for core library
+i2c_src = [
+  'i2c.c',
+]
+
+# shared and/or static library
+libi2c = library(meson.project_name(), i2c_src,
+  c_args: [
+    cflags,
+    '-D_DEFAULT_SOURCE',
+  ],
+  include_directories: i2c_incdir,
+  install: true,
+)
+
+# dependency for use in subprojects (only)
+i2c_dep = declare_dependency(
+  compile_args: cflags,
+  include_directories: i2c_incdir,
+  link_with: libi2c,
+  version: meson.project_version(),
+)
+
+# pkg-config support
+pkg = import('pkgconfig')
+pkg.generate(libi2c,
+  extra_cflags: cflags,
+)
+
+# python module build follows
+pymod = import('python')
+python_versions = ['python2', 'python3']
+python_testme = []  # python execs and built libraries go in here for testing
+python_src = ['pyi2c.c']
+python_path = meson.current_build_dir()  # used for tests
+
+foreach python_version : python_versions
+  python = pymod.find_installation(python_version, required: false)
+  if python.found()
+    # we still need the python-dev package
+    python_dep = dependency(python_version)
+    message(python_version + ' module enabled')
+    # same arguments as `shared_module`, more or less
+    # https://mesonbuild.com/Python-module.html
+    pylib = python.extension_module('pylibi2c', python_src,
+      dependencies: python_dep,
+      include_directories: i2c_incdir,
+      link_with: libi2c,
+      install: true,
+      c_args: cflags,
+    )
+    python_testme += {'python': python, 'lib': pylib}
+  endif
+endforeach
\ No newline at end of file
diff --git a/src/pyi2c.c b/src/pyi2c.c
index 6300dbe..e5b03ea 100644
--- a/src/pyi2c.c
+++ b/src/pyi2c.c
@@ -1,8 +1,7 @@
 #include <Python.h>
-#include "i2c.h"
+#include "i2c/i2c.h"
 
-
-#define _VERSION_ "0.1"
+#define _VERSION_ LIBI2C_VERSION
 #define _NAME_ "pylibi2c"
 #define _I2CDEV_MAX_SIZE_ 4096
 #define _I2CDEV_MAX_IADDR_BYTES_SIZE 4
@@ -28,6 +27,8 @@ typedef struct {
 
 
 static PyObject *I2CDevice_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+    (void)args;
+    (void)kwds;
 
     I2CDeviceObject *self;
 
@@ -162,7 +163,8 @@ static PyObject *i2c_read_device(I2CDeviceObject *self, PyObject *args, int ioct
         return NULL;
     }
 
-    if (result != len) {
+    if ((uint)result != len)
+    {
         perror("short read");
         return NULL;
     }
@@ -293,13 +295,16 @@ PyDoc_STRVAR(I2CDevice_flags_doc, "ioctl_read/write i2c_msg flags\n\n"
              "I2C_M_NO_RD_ACK\n"
              "In a read message, master A/NA bit is skipped.\n\n");
 static PyObject *I2CDevice_get_flags(I2CDeviceObject *self, void *closure) {
+    (void)closure;
 
     PyObject *result = Py_BuildValue("H", self->dev.flags);
     Py_INCREF(result);
     return result;
 }
 
-static int I2CDevice_set_flags(I2CDeviceObject *self, PyObject *value, void *closeure) {
+static int I2CDevice_set_flags(I2CDeviceObject *self, PyObject *value, void *closure)
+{
+    (void)closure;
 
     if (check_user_input("falgs", value, 0, I2C_M_NOSTART) != 0) {
 
@@ -310,17 +315,19 @@ static int I2CDevice_set_flags(I2CDeviceObject *self, PyObject *value, void *clo
     return 0;
 }
 
-
 /* delay */
 PyDoc_STRVAR(I2CDevice_delay_doc, "i2c internal operate delay, unit milliscond.\n\n");
 static PyObject *I2CDevice_get_delay(I2CDeviceObject *self, void *closure) {
+    (void)closure;
 
     PyObject *result = Py_BuildValue("b", self->dev.delay);
     Py_INCREF(result);
     return result;
 }
 
-static int I2CDevice_set_delay(I2CDeviceObject *self, PyObject *value, void *closeure) {
+static int I2CDevice_set_delay(I2CDeviceObject *self, PyObject *value, void *closure)
+{
+    (void)closure;
 
     if (check_user_input("delay", value, 0, 100) != 0) {
 
@@ -331,17 +338,19 @@ static int I2CDevice_set_delay(I2CDeviceObject *self, PyObject *value, void *clo
     return 0;
 }
 
-
 /* tenbit */
 PyDoc_STRVAR(I2CDevice_tenbit_doc, "True, Enable 10 bit addressing.\n\nFalse, 7 bit addressing(default).\n");
 static PyObject *I2CDevice_get_tenbit(I2CDeviceObject *self, void *closure) {
+    (void)closure;
 
     PyObject *result = self->dev.tenbit ? Py_True : Py_False;
     Py_INCREF(result);
     return result;
 }
 
-static int I2CDevice_set_tenbit(I2CDeviceObject *self, PyObject *value, void *closeure) {
+static int I2CDevice_set_tenbit(I2CDeviceObject *self, PyObject *value, void *closure)
+{
+    (void)closure;
 
     if (check_user_input("tenbit", value, 0, 1) != 0) {
 
@@ -352,20 +361,22 @@ static int I2CDevice_set_tenbit(I2CDeviceObject *self, PyObject *value, void *cl
     return 0;
 }
 
-
 /* iaddr_bytes */
 PyDoc_STRVAR(I2CDevice_page_bytes_doc, "i2c EEPROM max number of bytes per page (must be divisible by 8)\n\n"
              "8, 8 bytes per page, such as 24C01/24C02\n\n"
              "16, 16 bytes per page, such as 24C04/24C08/24C16\n\n"
              "32, 32 bytes per page, such as 24C32/24C64\n\n");
 static PyObject *I2CDevice_get_page_bytes(I2CDeviceObject *self, void *closure) {
+    (void)closure;
 
     PyObject *result = Py_BuildValue("I", self->dev.page_bytes);
     Py_INCREF(result);
     return result;
 }
 
-static int I2CDevice_set_page_bytes(I2CDeviceObject *self, PyObject *value, void *closeure) {
+static int I2CDevice_set_page_bytes(I2CDeviceObject *self, PyObject *value, void *closure)
+{
+    (void)closure;
 
     int page_bytes = 0;
 
@@ -386,7 +397,6 @@ static int I2CDevice_set_page_bytes(I2CDeviceObject *self, PyObject *value, void
     return 0;
 }
 
-
 /* iaddr_bytes */
 PyDoc_STRVAR(I2CDevice_iaddr_bytes_doc, "I2C device internal(word) address bytes.\n\n"
              "0, special device, without internal address\n\n"
@@ -394,13 +404,16 @@ PyDoc_STRVAR(I2CDevice_iaddr_bytes_doc, "I2C device internal(word) address bytes
              "2, 2 byte internal address, such as 24C64\n\n"
              "2, 3 byte internal address, such as 24C1024\n\n");
 static PyObject *I2CDevice_get_iaddr_bytes(I2CDeviceObject *self, void *closure) {
+    (void)closure;
 
     PyObject *result = Py_BuildValue("b", self->dev.iaddr_bytes);
     Py_INCREF(result);
     return result;
 }
 
-static int I2CDevice_set_iaddr_bytes(I2CDeviceObject *self, PyObject *value, void *closeure) {
+static int I2CDevice_set_iaddr_bytes(I2CDeviceObject *self, PyObject *value, void *closure)
+{
+    (void)closure;
 
     if (check_user_input("iaddr_bytes", value, 0, _I2CDEV_MAX_IADDR_BYTES_SIZE) != 0) {
 
@@ -411,24 +424,24 @@ static int I2CDevice_set_iaddr_bytes(I2CDeviceObject *self, PyObject *value, voi
     return 0;
 }
 
-
 static PyGetSetDef I2CDevice_getseters[] = {
 
-    {"flags", (getter)I2CDevice_get_flags, (setter)I2CDevice_set_flags, I2CDevice_flags_doc},
-    {"delay", (getter)I2CDevice_get_delay, (setter)I2CDevice_set_delay, I2CDevice_delay_doc},
-    {"tenbit", (getter)I2CDevice_get_tenbit, (setter)I2CDevice_set_tenbit, I2CDevice_tenbit_doc},
-    {"page_bytes", (getter)I2CDevice_get_page_bytes, (setter)I2CDevice_set_page_bytes, I2CDevice_page_bytes_doc},
-    {"iaddr_bytes", (getter)I2CDevice_get_iaddr_bytes, (setter)I2CDevice_set_iaddr_bytes, I2CDevice_iaddr_bytes_doc},
+    {"flags", (getter)I2CDevice_get_flags, (setter)I2CDevice_set_flags, I2CDevice_flags_doc, NULL},
+    {"delay", (getter)I2CDevice_get_delay, (setter)I2CDevice_set_delay, I2CDevice_delay_doc, NULL},
+    {"tenbit", (getter)I2CDevice_get_tenbit, (setter)I2CDevice_set_tenbit, I2CDevice_tenbit_doc, NULL},
+    {"page_bytes", (getter)I2CDevice_get_page_bytes, (setter)I2CDevice_set_page_bytes, I2CDevice_page_bytes_doc, NULL},
+    {"iaddr_bytes", (getter)I2CDevice_get_iaddr_bytes, (setter)I2CDevice_set_iaddr_bytes, I2CDevice_iaddr_bytes_doc, NULL},
     {NULL},
 };
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 
 static PyTypeObject I2CDeviceObjectType = {
 #if PY_MAJOR_VERSION >= 3
     PyVarObject_HEAD_INIT(NULL, 0)
 #else
-    PyObject_HEAD_INIT(NULL)
-    0,				            /* ob_size */
+    PyObject_HEAD_INIT(NULL) 0, /* ob_size */
 #endif
     I2CDevice_name,		        /* tp_name */
     sizeof(I2CDeviceObject),	/* tp_basicsize */
@@ -469,6 +482,7 @@ static PyTypeObject I2CDeviceObjectType = {
     I2CDevice_new,		        /* tp_new */
 };
 
+#pragma GCC diagnostic pop
 
 static PyMethodDef pylibi2c_methods[] = {
     {NULL}
@@ -486,10 +500,14 @@ void define_constants(PyObject *module) {
 #if PY_MAJOR_VERSION >= 3
 static struct PyModuleDef pylibi2cmodule = {
     PyModuleDef_HEAD_INIT,
-    _NAME_,         /* Module name */
-    pylibi2c_doc,	/* Module pylibi2cMethods */
-    -1,			    /* size of per-interpreter state of the module, size of per-interpreter state of the module,*/
+    _NAME_,       /* Module name */
+    pylibi2c_doc, /* Module pylibi2cMethods */
+    -1,           /* size of per-interpreter state of the module, size of per-interpreter state of the module,*/
     pylibi2c_methods,
+    NULL,
+    0,
+    0,
+    0,
 };
 #endif
 


Test patch:
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 0000000..3840021
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,14 @@
+foreach d : python_testme
+  python = d['python']
+  testname = 'python ' + python.language_version() + ' module'
+  test(testname, python,  # testname, executable
+    args: files('test_pylibi2c.py'),  # full path to test.py
+    depends: d['lib'],  # the library that must be built before
+    workdir: python_path,
+    protocol: 'exitcode',
+    env: [
+      'PYTHONPATH=' + python_path,
+    ],
+    is_parallel: false,
+  )
+endforeach
\ No newline at end of file