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

win64 build process #144

Closed
wqh17101 opened this issue Feb 5, 2021 · 8 comments
Closed

win64 build process #144

wqh17101 opened this issue Feb 5, 2021 · 8 comments

Comments

@wqh17101
Copy link
Contributor

wqh17101 commented Feb 5, 2021

first install MSYS2
then

pacman -Syu --noconfirm autoconf libtool automake make autoconf-archive pkg-config
pacman -S base-devel
cd zbar
autoreconf -vfi
./configure  --host=x86_64-pc-msys --without-java --without-gtk --without-qt  --without-imagemagick  --disable-video --without-python
make
make install

and get a msys-zbar-0.dll in /usr/bin

then build python

pacman -S python-pip
pacman -S python-setuptools
pip install wheel
pacman -S libcrypt libcrypt-devel
cd python
python setup_plus.py bdist_wheel

then i can use zbar normally in the MSYS2 env not the win64 env.
So i decide to build it in mingw64 instead of MSYS2 env.

@wqh17101
Copy link
Contributor Author

wqh17101 commented Feb 5, 2021

open
image

pacman -S mingw-w64-x86_64-toolchain
cd zbar
autoreconf -vfi
./configure  --host=x86_64-w64-mingw32 --without-java --without-gtk --without-qt  --without-imagemagick  --disable-video --without-python
make
make install

and get a libzbar-0.dll in /mingw64/bin

then build python

pacman -S mingw-w64-x86_64-python-setuptools
pacman -S mingw-w64-x86_64-python-wheel
cd python
python setup_plus.py bdist_wheel

then i can use zbar normally in the mingw env

@wqh17101
Copy link
Contributor Author

wqh17101 commented Feb 5, 2021

to set host
you can use gcc -v to see what host you should use
image

@wqh17101
Copy link
Contributor Author

wqh17101 commented Feb 7, 2021

i am a Python user so that i used setup.py to build zbar.
Most problems i met is that Windows doesn`t have some .h which can be found only in the Linux. So i made a zbar-lite involving the minium denpendency only support scanning image for Python can be anything else such as read image or video process on its own and .
i make a preparation.sh like below

mkdir -p src/zbar/video
cp ../zbar/video/null.c src/zbar/video/
cp -r ../zbar/decoder src/zbar/
cp -r ../zbar/qrcode src/zbar/
mkdir zbar
cp ../python/*.c zbar/
cp ../python/*.h zbar/
cp ../include/zbar.h src/
cp ../include/config.h src/

cp ../zbar/config.c src/zbar/
cp ../zbar/convert.c src/zbar/
cp ../zbar/debug.h src/zbar/
cp ../zbar/decoder.c src/zbar/
cp ../zbar/decoder.h src/zbar/
cp ../zbar/error.c src/zbar/
cp ../zbar/error.h src/zbar/
cp ../zbar/event.h src/zbar/
cp ../zbar/image.c src/zbar/
cp ../zbar/image.h src/zbar/
cp ../zbar/img_scanner.c src/zbar/
cp ../zbar/img_scanner.h src/zbar/
cp ../zbar/mutex.h src/zbar/
cp ../zbar/qrcode.h src/zbar/
cp ../zbar/refcnt.c src/zbar/
cp ../zbar/refcnt.h src/zbar/
cp ../zbar/scanner.c src/zbar/
cp ../zbar/sqcode.c src/zbar/
cp ../zbar/sqcode.h src/zbar/
cp ../zbar/svg.h src/zbar/
cp ../zbar/symbol.c src/zbar/
cp ../zbar/symbol.h src/zbar/
cp ../zbar/thread.h src/zbar/
cp ../zbar/timer.h src/zbar/
cp ../zbar/video.c src/zbar/
cp ../zbar/video.h src/zbar/
cp ../zbar/window.h src/zbar/

and a setup.py like below

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os

try:
    import setuptools
    from setuptools import setup, Extension

    setuptools_opts = dict()
except ImportError:
    from distutils.core import setup
    from distutils.extension import Extension

    setuptools_opts = {}

import os
import ctypes
import ctypes.util


def get_c_file(target_dir):
    return [os.path.join(target_dir, x) for x in os.listdir(target_dir) if x.endswith(".c")]


SRCS = get_c_file("src/zbar") + \
       get_c_file("src/zbar/decoder") + \
       get_c_file("src/zbar/video") + \
       get_c_file("src/zbar/qrcode") + get_c_file("zbar")
SRCS.remove(os.path.join("zbar", "processor.c"))

INCLUDE = ['./src', './src/zbar', "./src/zbar/decoder", "./src/zbar/qrcode", "./zbar"]


def has_libc_iconv():
    if os.name != 'posix':
        return False
    libc = ctypes.CDLL(ctypes.util.find_library('c'))
    return hasattr(libc, 'iconv')


# don't try to link to standalone iconv library if it's already in libc
# (iconv is in glibc, but on OS X one needs a stanalone libiconv)
LIBS = [] if has_libc_iconv() else ['iconv']
zbar = Extension('zbar', sources=SRCS, include_dirs=INCLUDE, libraries=LIBS)

setup(name='zbar-lite',
      version='0.23.1',
      description='zbar package',
      url='https://github.com/mchehab/zbar',
      author='Qinghua Wang',
      author_email='597935261@qq.com',
      ext_modules=[zbar],
      # packages=['zbar'],
      license='MIT',
      **setuptools_opts)

also add a Macro ZBAR_LITE to zbarmodule.h and add controller like below

/*------------------------------------------------------------------------
 *  Copyright 2009-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
 *
 *  This file is part of the ZBar Bar Code Reader.
 *
 *  The ZBar Bar Code Reader is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Lesser Public License as
 *  published by the Free Software Foundation; either version 2.1 of
 *  the License, or (at your option) any later version.
 *
 *  The ZBar Bar Code Reader is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser Public License
 *  along with the ZBar Bar Code Reader; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 *  Boston, MA  02110-1301  USA
 *
 *  http://sourceforge.net/projects/zbar
 *------------------------------------------------------------------------*/

#include <Python.h>
#include <stddef.h>
#include <zbar.h>

#ifndef _ZBARMODULE_H_
#define _ZBARMODULE_H_

#define ZBAR_LITE 1

#if PY_MAJOR_VERSION < 3
typedef struct {
    PyBaseExceptionObject base;
    PyObject *obj;
} zbarException;

extern PyTypeObject zbarException_Type;
#endif


extern struct PyModuleDef zbar_moduledef;

#if PY_MAJOR_VERSION >= 3
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
#define GETMODSTATE() (GETSTATE(PyState_FindModule(&zbar_moduledef)))
#else
extern struct module_state zbar_state;
#define GETSTATE(m) (&zbar_state)
#define GETMODSTATE() (&zbar_state)
#endif


//extern PyObject *zbarErr_Set(PyObject *self);

typedef struct {
#if PY_MAJOR_VERSION >= 3
    PyLongObject val;           /* parent type is the long type */
#else
    PyIntObject val;            /* integer value is super type */
#endif
    PyObject *name;             /* associated string name */
} zbarEnumItem;

extern PyTypeObject zbarEnumItem_Type;

extern zbarEnumItem *zbarEnumItem_New(PyObject *byname,
                                        PyObject *byvalue,
                                        int val,
                                        const char *name);

typedef struct {
    PyObject_HEAD
    PyObject *byname, *byvalue; /* zbarEnumItem content dictionaries */
} zbarEnum;

extern PyTypeObject zbarEnum_Type;

extern zbarEnum *zbarEnum_New(void);
extern int zbarEnum_Add(zbarEnum *self,
                         int val,
                         const char *name);
extern zbarEnumItem *zbarEnum_LookupValue(zbarEnum *self,
                                          int val);
extern PyObject *zbarEnum_SetFromMask(zbarEnum *self,
                                      unsigned int mask);

typedef struct {
    PyObject_HEAD
    zbar_image_t *zimg;
    PyObject *data;
} zbarImage;

extern PyTypeObject zbarImage_Type;

extern zbarImage *zbarImage_FromImage(zbar_image_t *zimg);
extern int zbarImage_validate(zbarImage *image);

typedef struct {
    PyObject_HEAD
    const zbar_symbol_set_t *zsyms;
} zbarSymbolSet;

extern PyTypeObject zbarSymbolSet_Type;

extern zbarSymbolSet*
zbarSymbolSet_FromSymbolSet(const zbar_symbol_set_t *zsyms);

#define zbarSymbolSet_Check(obj) PyObject_TypeCheck(obj, &zbarSymbolSet_Type)

typedef struct {
    PyObject_HEAD
    const zbar_symbol_t *zsym;
    PyObject *data;
    PyObject *loc;
} zbarSymbol;

extern PyTypeObject zbarSymbol_Type;

extern zbarSymbol *zbarSymbol_FromSymbol(const zbar_symbol_t *zsym);
extern zbarEnumItem *zbarSymbol_LookupEnum(zbar_symbol_type_t type);

typedef struct {
    PyObject_HEAD
    const zbar_symbol_t *zsym;
    zbarSymbolSet *syms;
} zbarSymbolIter;

extern PyTypeObject zbarSymbolIter_Type;

extern zbarSymbolIter *zbarSymbolIter_FromSymbolSet(zbarSymbolSet *syms);

#if ZBAR_LITE != 1
typedef struct {
    PyObject_HEAD
    zbar_processor_t *zproc;
    PyObject *handler;
    PyObject *closure;
} zbarProcessor;

extern PyTypeObject zbarProcessor_Type;

#define zbarProcessor_Check(obj) PyObject_TypeCheck(obj, &zbarProcessor_Type)
#endif

typedef struct {
    PyObject_HEAD
    zbar_image_scanner_t *zscn;
} zbarImageScanner;

extern PyTypeObject zbarImageScanner_Type;

typedef struct {
    PyObject_HEAD
    zbar_decoder_t *zdcode;
    PyObject *handler;
    PyObject *args;
} zbarDecoder;

extern PyTypeObject zbarDecoder_Type;

typedef struct {
    PyObject_HEAD
    zbar_scanner_t *zscn;
    zbarDecoder *decoder;
} zbarScanner;

extern PyTypeObject zbarScanner_Type;

extern int object_to_bool(PyObject *obj,
                          int *val);
extern int parse_dimensions(PyObject *seq,
                            int *dims,
                            int n);


struct module_state {
    PyObject *zbar_exc[ZBAR_ERR_NUM];
    zbarEnumItem *color_enum[2];
    zbarEnum *config_enum;
    zbarEnum *modifier_enum;
    PyObject *symbol_enum;
    zbarEnumItem *symbol_NONE;
    zbarEnum *orient_enum;
};

#endif

add to zbarmodule.c

/*------------------------------------------------------------------------
 *  Copyright 2009-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
 *
 *  This file is part of the ZBar Bar Code Reader.
 *
 *  The ZBar Bar Code Reader is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Lesser Public License as
 *  published by the Free Software Foundation; either version 2.1 of
 *  the License, or (at your option) any later version.
 *
 *  The ZBar Bar Code Reader is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser Public License
 *  along with the ZBar Bar Code Reader; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 *  Boston, MA  02110-1301  USA
 *
 *  http://sourceforge.net/projects/zbar
 *------------------------------------------------------------------------*/

#include "zbarmodule.h"

typedef struct enumdef {
    const char *strval;
    int intval;
} enumdef;

static char *exc_names[] = {
    "zbar.Exception",
    NULL,
    "zbar.InternalError",
    "zbar.UnsupportedError",
    "zbar.InvalidRequestError",
    "zbar.SystemError",
    "zbar.LockingError",
    "zbar.BusyError",
    "zbar.X11DisplayError",
    "zbar.X11ProtocolError",
    "zbar.WindowClosed",
    "zbar.WinAPIError",
};

static const enumdef symbol_defs[] = {
    { "NONE",           ZBAR_NONE },
    { "PARTIAL",        ZBAR_PARTIAL },
    { "EAN8",           ZBAR_EAN8 },
    { "UPCE",           ZBAR_UPCE },
    { "ISBN10",         ZBAR_ISBN10 },
    { "UPCA",           ZBAR_UPCA },
    { "EAN13",          ZBAR_EAN13 },
    { "ISBN13",         ZBAR_ISBN13 },
    { "DATABAR",        ZBAR_DATABAR },
    { "DATABAR_EXP",    ZBAR_DATABAR_EXP },
    { "I25",            ZBAR_I25 },
    { "CODABAR",        ZBAR_CODABAR },
    { "CODE39",         ZBAR_CODE39 },
    { "PDF417",         ZBAR_PDF417 },
    { "QRCODE",         ZBAR_QRCODE },
    { "SQCODE",         ZBAR_SQCODE },
    { "CODE93",         ZBAR_CODE93 },
    { "CODE128",        ZBAR_CODE128 },
    { NULL, }
};

static const enumdef config_defs[] = {
    { "ENABLE",         ZBAR_CFG_ENABLE },
    { "ADD_CHECK",      ZBAR_CFG_ADD_CHECK },
    { "EMIT_CHECK",     ZBAR_CFG_EMIT_CHECK },
    { "ASCII",          ZBAR_CFG_ASCII },
    { "BINARY",         ZBAR_CFG_BINARY },
    { "MIN_LEN",        ZBAR_CFG_MIN_LEN },
    { "MAX_LEN",        ZBAR_CFG_MAX_LEN },
    { "UNCERTAINTY",    ZBAR_CFG_UNCERTAINTY },
    { "POSITION",       ZBAR_CFG_POSITION },
    { "X_DENSITY",      ZBAR_CFG_X_DENSITY },
    { "Y_DENSITY",      ZBAR_CFG_Y_DENSITY },
    { NULL, }
};

static const enumdef modifier_defs[] = {
    { "GS1",            ZBAR_MOD_GS1 },
    { "AIM",            ZBAR_MOD_AIM },
    { NULL, }
};

static const enumdef orient_defs[] = {
    { "UNKNOWN",        ZBAR_ORIENT_UNKNOWN },
    { "UP",             ZBAR_ORIENT_UP },
    { "RIGHT",          ZBAR_ORIENT_RIGHT },
    { "DOWN",           ZBAR_ORIENT_DOWN },
    { "LEFT",           ZBAR_ORIENT_LEFT },
    { NULL, }
};


#if PY_MAJOR_VERSION < 3
struct module_state zbar_state;
#endif


int
object_to_bool (PyObject *obj,
                int *val)
{
    int tmp = PyObject_IsTrue(obj);
    if(tmp < 0)
        return(0);
    *val = tmp;
    return(1);
}

int
parse_dimensions (PyObject *seq,
                  int *dims,
                  int n)
{
    if(!PySequence_Check(seq) ||
       PySequence_Size(seq) != n)
        return(-1);

    int i;
    for(i = 0; i < n; i++, dims++) {
        PyObject *dim = PySequence_GetItem(seq, i);
        if(!dim)
            return(-1);
#if PY_MAJOR_VERSION >= 3
        *dims = PyLong_AsSsize_t(dim);
#else
        *dims = PyInt_AsSsize_t(dim);
#endif
        Py_DECREF(dim);
        if(*dims == -1 && PyErr_Occurred())
            return(-1);
    }
    return(0);
}


static PyObject*
version (PyObject *self,
         PyObject *args)
{
    if(!PyArg_ParseTuple(args, ""))
        return(NULL);

    unsigned int major, minor;
    zbar_version(&major, &minor, NULL);

    return(Py_BuildValue("II", major, minor));
}

static PyObject*
set_verbosity (PyObject *self,
               PyObject *args)
{
    int verbosity;
    if(!PyArg_ParseTuple(args, "i", &verbosity))
        return(NULL);

    zbar_set_verbosity(verbosity);

    Py_INCREF(Py_None);
    return(Py_None);
}

static PyObject*
increase_verbosity (PyObject *self,
                    PyObject *args)
{
    if(!PyArg_ParseTuple(args, ""))
        return(NULL);

    zbar_increase_verbosity();

    Py_INCREF(Py_None);
    return(Py_None);
}

static PyMethodDef zbar_functions[] = {
    { "version",            version,            METH_VARARGS, NULL },
    { "set_verbosity",      set_verbosity,      METH_VARARGS, NULL },
    { "increase_verbosity", increase_verbosity, METH_VARARGS, NULL },
    { NULL, },
};


#if PY_MAJOR_VERSION >= 3

static int zbar_traverse(PyObject *m, visitproc visit, void *arg) {
    Py_VISIT(GETSTATE(m)->zbar_exc[0]);
    return 0;
}

static int zbar_clear(PyObject *m) {
    Py_CLEAR(GETSTATE(m)->zbar_exc[0]);
    return 0;
}


struct PyModuleDef zbar_moduledef = {
    PyModuleDef_HEAD_INIT,
    "zbar",
    NULL,
    sizeof(struct module_state),
    zbar_functions,
    NULL,
    zbar_traverse,
    zbar_clear,
    NULL
};

#define INITERROR return NULL

PyMODINIT_FUNC
PyInit_zbar(void)

#else
#define INITERROR return

PyMODINIT_FUNC
initzbar(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
    /* initialize types */
    zbarEnumItem_Type.tp_base = &PyLong_Type;
#else
    zbarEnumItem_Type.tp_base = &PyInt_Type;
    zbarException_Type.tp_base = (PyTypeObject*)PyExc_Exception;

    if(PyType_Ready(&zbarException_Type) < 0)
        INITERROR;
#endif
#if ZBAR_LITE !=1
    if(PyType_Ready(&zbarEnumItem_Type) < 0 ||
       PyType_Ready(&zbarEnum_Type) < 0 ||
       PyType_Ready(&zbarImage_Type) < 0 ||
       PyType_Ready(&zbarSymbol_Type) < 0 ||
       PyType_Ready(&zbarSymbolSet_Type) < 0 ||
       PyType_Ready(&zbarSymbolIter_Type) < 0 ||
       PyType_Ready(&zbarProcessor_Type) < 0 ||
       PyType_Ready(&zbarImageScanner_Type) < 0 ||
       PyType_Ready(&zbarDecoder_Type) < 0 ||
       PyType_Ready(&zbarScanner_Type) < 0)
#else
    if(PyType_Ready(&zbarEnumItem_Type) < 0 ||
       PyType_Ready(&zbarEnum_Type) < 0 ||
       PyType_Ready(&zbarImage_Type) < 0 ||
       PyType_Ready(&zbarSymbol_Type) < 0 ||
       PyType_Ready(&zbarSymbolSet_Type) < 0 ||
       PyType_Ready(&zbarSymbolIter_Type) < 0 ||
       PyType_Ready(&zbarImageScanner_Type) < 0 ||
       PyType_Ready(&zbarDecoder_Type) < 0 ||
       PyType_Ready(&zbarScanner_Type) < 0)
        INITERROR;
#endif
    /* initialize module */
#if PY_MAJOR_VERSION >= 3
    PyObject *mod = PyModule_Create(&zbar_moduledef);
#else
    PyObject *mod = Py_InitModule("zbar", zbar_functions);
#endif
    if(!mod)
        INITERROR;

#if PY_MAJOR_VERSION >= 3
    if(PyState_AddModule(mod, &zbar_moduledef)) {
        Py_DECREF(mod);
        INITERROR;
    }
#endif

    struct module_state *st = GETSTATE(mod);

    /* initialize constant containers */
    st->config_enum = zbarEnum_New();
    st->modifier_enum = zbarEnum_New();
    st->symbol_enum = PyDict_New();
    st->orient_enum = zbarEnum_New();
    if(!st->config_enum || !st->modifier_enum || !st->symbol_enum || !st->orient_enum) {
        Py_DECREF(mod);
        INITERROR;
    }

    /* internally created/read-only type overrides */
    zbarEnum_Type.tp_new = NULL;
    zbarEnum_Type.tp_setattr = NULL;
    zbarEnum_Type.tp_setattro = NULL;

    /* zbar internal exception objects */
#if PY_MAJOR_VERSION >= 3
    st->zbar_exc[0] = PyErr_NewException("zbar.Exception", NULL, NULL);
#else
    st->zbar_exc[0] = (PyObject*)&zbarException_Type;
#endif
    if (st->zbar_exc[0] == NULL) {
        Py_DECREF(mod);
        INITERROR;
    }

    st->zbar_exc[ZBAR_ERR_NOMEM] = NULL;
    zbar_error_t ei;
    for(ei = ZBAR_ERR_INTERNAL; ei < ZBAR_ERR_NUM; ei++) {
        st->zbar_exc[ei] = PyErr_NewException(exc_names[ei], st->zbar_exc[0], NULL);
        if (!st->zbar_exc[ei]) {
            Py_DECREF(mod);
            INITERROR;
        }
    }

    /* add types to module */
    PyModule_AddObject(mod, "EnumItem", (PyObject*)&zbarEnumItem_Type);
    PyModule_AddObject(mod, "Image", (PyObject*)&zbarImage_Type);
    PyModule_AddObject(mod, "Config", (PyObject*)st->config_enum);
    PyModule_AddObject(mod, "Modifier", (PyObject*)st->modifier_enum);
    PyModule_AddObject(mod, "Orient", (PyObject*)st->orient_enum);
    PyModule_AddObject(mod, "Symbol", (PyObject*)&zbarSymbol_Type);
    PyModule_AddObject(mod, "SymbolSet", (PyObject*)&zbarSymbolSet_Type);
    PyModule_AddObject(mod, "SymbolIter", (PyObject*)&zbarSymbolIter_Type);
#if ZBAR_LITE != 1
    PyModule_AddObject(mod, "Processor", (PyObject*)&zbarProcessor_Type);
#endif
    PyModule_AddObject(mod, "ImageScanner", (PyObject*)&zbarImageScanner_Type);
    PyModule_AddObject(mod, "Decoder", (PyObject*)&zbarDecoder_Type);
    PyModule_AddObject(mod, "Scanner", (PyObject*)&zbarScanner_Type);

    for(ei = 0; ei < ZBAR_ERR_NUM; ei++)
        if(st->zbar_exc[ei])
            PyModule_AddObject(mod, exc_names[ei] + 5, st->zbar_exc[ei]);

    /* add constants */
    PyObject *dict = PyModule_GetDict(mod);
    st->color_enum[ZBAR_SPACE] =
        zbarEnumItem_New(dict, NULL, ZBAR_SPACE, "SPACE");
    st->color_enum[ZBAR_BAR] =
        zbarEnumItem_New(dict, NULL, ZBAR_BAR, "BAR");

    const enumdef *item;
    for(item = config_defs; item->strval; item++)
        zbarEnum_Add(st->config_enum, item->intval, item->strval);
    for(item = modifier_defs; item->strval; item++)
        zbarEnum_Add(st->modifier_enum, item->intval, item->strval);
    for(item = orient_defs; item->strval; item++)
        zbarEnum_Add(st->orient_enum, item->intval, item->strval);

    PyObject *tp_dict = zbarSymbol_Type.tp_dict;
    for(item = symbol_defs; item->strval; item++)
        zbarEnumItem_New(tp_dict, st->symbol_enum, item->intval, item->strval);
    st->symbol_NONE = zbarSymbol_LookupEnum(ZBAR_NONE);

#if PY_MAJOR_VERSION >= 3
    return mod;
#endif
}

#if ZBAR_LITE != 1

PyObject*
zbarErr_Set (PyObject *self)
{
    const void *zobj = ((zbarProcessor*)self)->zproc;
    zbar_error_t err = _zbar_get_error_code(zobj);

    struct module_state *st = GETMODSTATE();

    if(err == ZBAR_ERR_NOMEM)
        PyErr_NoMemory();
    else if(err < ZBAR_ERR_NUM) {
        PyObject *type = st->zbar_exc[err];
        assert(type);
        PyErr_SetObject(type, self);
    }
    else
        PyErr_SetObject(st->zbar_exc[0], self);
    return(NULL);
}
#endif

you only need to do like below

sh preparation.sh
python setup.py install

@wqh17101
Copy link
Contributor Author

wqh17101 commented Feb 8, 2021

success

D:\mingw64\bin\gcc.exe -shared -s build\temp.win-amd64-3.7\Release\src\zbar\config.o build\temp.win-amd64-3.7\Release\src\zbar\convert.o build\temp.win-amd64-3.7\Release\src\zbar\decoder.o build\temp.win-amd64-3.7\Release\src\zbar\error.o build\temp.win-amd64-3.7\Release\src\zbar\image.o build\temp.win-amd64-3.7\Release\src\zbar\img_scanner.o build\temp.win-amd64-3.7\Release\src\zbar\refcnt.o build\temp.win-amd64-3.7\Release\src\zbar\scanner.o build\temp.win-amd64-3.7\Release\src\zbar\sqcode.o build\temp.win-amd64-3.7\Release\src\zbar\symbol.o build\temp.win-amd64-3.7\Release\src\zbar\video.o build\temp.win-amd64-3.7\Release\src\zbar\decoder\codabar.o build\temp.win-amd64-3.7\Release\src\zbar\decoder\code128.o build\temp.win-amd64-3.7\Release\src\zbar\decoder\code39.o build\temp.win-amd64-3.7\Release\src\zbar\decoder\code93.o build\temp.win-amd64-3.7\Release\src\zbar\decoder\databar.o build\temp.win-amd64-3.7\Release\src\zbar\decoder\ean.o build\temp.win-amd64-3.7\Release\src\zbar\decoder\i25.o build\temp.win-amd64-3.7\Release\src\zbar\decoder\pdf417.o build\temp.win-amd64-3.7\Release\src\zbar\decoder\qr_finder.o build\temp.win-amd64-3.7\Release\src\zbar\decoder\sq_finder.o build\temp.win-amd64-3.7\Release\src\zbar\video\v4l.o build\temp.win-amd64-3.7\Release\src\zbar\qrcode\bch15_5.o build\temp.win-amd64-3.7\Release\src\zbar\qrcode\binarize.o build\temp.win-amd64-3.7\Release\src\zbar\qrcode\isaac.o build\temp.win-amd64-3.7\Release\src\zbar\qrcode\qrdec.o build\temp.win-amd64-3.7\Release\src\zbar\qrcode\qrdectxt.o build\temp.win-amd64-3.7\Release\src\zbar\qrcode\rs.o build\temp.win-amd64-3.7\Release\src\zbar\qrcode\util.o build\temp.win-amd64-3.7\Release\zbar\decoder.o build\temp.win-amd64-3.7\Release\zbar\enum.o build\temp.win-amd64-3.7\Release\zbar\exception.o build\temp.win-amd64-3.7\Release\zbar\image.o build\temp.win-amd64-3.7\Release\zbar\imagescanner.o build\temp.win-amd64-3.7\Release\zbar\scanner.o build\temp.win-amd64-3.7\Release\zbar\symbol.o build\temp.win-amd64-3.7\Release\zbar\symboliter.o build\temp.win-amd64-3.7\Release\zbar\symbolset.o build\temp.win-amd64-3.7\Release\zbar\zbarmodule.o build\temp.win-amd64-3.7\Release\src\zbar\zbar.cp37-win_amd64.def -LC:\Users\Anaconda3\libs -LC:\Users\Anaconda3\PCbuild\amd64 -liconv -lpython37 -lmsvcr140 -o build\lib.win-amd64-3.7\zbar.cp37-win_amd64.pyd

gcc -v

Using built-in specs.
COLLECT_GCC=D:\mingw64\bin\gcc.exe
COLLECT_LTO_WRAPPER=D:/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/7.3.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-7.3.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw730/x86_64-730-posix-seh-rt_v5-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --enable-libstdcxx-filesystem-ts=yes --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw730/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw730/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw730/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw730/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw730/x86_64-730-posix-seh-rt_v5-rev0/mingw64/opt/include -I/c/mingw730/prerequisites/x86_64-zlib-static/include -I/c/mingw730/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw730/x86_64-730-posix-seh-rt_v5-rev0/mingw64/opt/include -I/c/mingw730/prerequisites/x86_64-zlib-static/include -I/c/mingw730/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw730/x86_64-730-posix-seh-rt_v5-rev0/mingw64/opt/include -I/c/mingw730/prerequisites/x86_64-zlib-static/include -I/c/mingw730/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw730/x86_64-730-posix-seh-rt_v5-rev0/mingw64/opt/lib -L/c/mingw730/prerequisites/x86_64-zlib-static/lib -L/c/mingw730/prerequisites/x86_64-w64-mingw32-static/lib '
Thread model: posix
gcc version 7.3.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)

@wqh17101
Copy link
Contributor Author

wqh17101 commented Feb 9, 2021

in the setup.py you can use

from setuptools.command.build_ext import build_ext

class custom_build_ext(build_ext):
    def build_extensions(self):
        self.compiler.dll_libraries = []
        build_ext.build_extensions(self)

to make no extra libs of dll

for linux config.h is like

/* include/config.h.  Generated from config.h.in by configure.  */
/* include/config.h.in.  Generated from configure.ac by autoheader.  */

/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
   systems. This function is required for `alloca.c' support on those systems.
   */
/* #undef CRAY_STACKSEG_END */

/* Define to 1 if using `alloca.c'. */
/* #undef C_ALLOCA */

/* whether to build support for Codabar symbology */
#define ENABLE_CODABAR 1

/* whether to build support for Code 128 symbology */
#define ENABLE_CODE128 1

/* whether to build support for Code 39 symbology */
#define ENABLE_CODE39 1

/* whether to build support for Code 93 symbology */
#define ENABLE_CODE93 1

/* whether to build support for DataBar symbology */
#define ENABLE_DATABAR 1

/* whether to build support for EAN symbologies */
#define ENABLE_EAN 1

/* whether to build support for Interleaved 2 of 5 symbology */
#define ENABLE_I25 1

/* Define to 1 if translation of program messages to the user's native
   language is requested. */
#define ENABLE_NLS 1

/* whether to build support for PDF417 symbology (incomplete) */
#define ENABLE_PDF417 1 

/* whether to build support for QR Code */
#define ENABLE_QRCODE 1

/* whether to build support for SQ Code */
#define ENABLE_SQCODE 1

/* Define to 1 if you have the `alarm' function. */
#define HAVE_ALARM 1

/* Define to 1 if you have `alloca', as a function or macro. */
/* #undef HAVE_ALLOCA */

/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
   */
/* #undef HAVE_ALLOCA_H */

/* Define to 1 if you have the <arpa/inet.h> header file. */
/* #undef HAVE_ARPA_INET_H */

/* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the
   CoreFoundation framework. */
/* #undef HAVE_CFLOCALECOPYCURRENT */

/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in
   the CoreFoundation framework. */
/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */

/* Define to 1 if you have the `clock_gettime' function. */
#define HAVE_CLOCK_GETTIME 1

/* Define to 1 to use dbus */
/* #undef HAVE_DBUS */

/* Define if the GNU dcgettext() function is already present or preinstalled.
   */
#define HAVE_DCGETTEXT 1

/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1

/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1

/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1

/* Define to 1 if you have the <features.h> header file. */
#define HAVE_FEATURES_H 1

/* Define to 1 if you have the <float.h> header file. */
#define HAVE_FLOAT_H 1

/* Define to 1 if you have the `floor' function. */
/* #undef HAVE_FLOOR */

/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
/* #undef HAVE_FSEEKO */

/* Define to 1 if you have the `getcwd' function. */
#define HAVE_GETCWD 1

/* Define to 1 if you have the `getpagesize' function. */
#define HAVE_GETPAGESIZE 1

/* Define if the GNU gettext() function is already present or preinstalled. */
#define HAVE_GETTEXT 1

/* Define to 1 if you have the `gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1

/* Define to 1 to use GraphicsMagick */
/* #undef HAVE_GRAPHICSMAGICK */

/* Define if you have the iconv() function and it works. */
#define HAVE_ICONV 1

/* Define to 1 to use ImageMagick */
/* #undef HAVE_IMAGEMAGICK */

/* Define to 1 to use ImageMagick 7 */
/* #undef HAVE_IMAGEMAGICK7 */

/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1

/* Define to 1 if you have the <jpeglib.h> header file. */
/* #undef HAVE_JPEGLIB_H */

/* Define to 1 if you have the `jpeg' library (-ljpeg). */
/* #undef HAVE_LIBJPEG */

/* Define to 1 if you have the `pthread' library (-lpthread). */
#define HAVE_LIBPTHREAD 1

/* Define to 1 if you have the <libv4l2.h> header file. */
/* #undef HAVE_LIBV4L2_H */

/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1

/* Define to 1 if you have the <linux/videodev2.h> header file. */
#define HAVE_LINUX_VIDEODEV2_H 1

/* Define to 1 if you have the <linux/videodev.h> header file. */
/* #undef HAVE_LINUX_VIDEODEV_H */

/* Define to 1 if you have the `localeconv' function. */
#define HAVE_LOCALECONV 1

/* Define to 1 if you have the <locale.h> header file. */
#define HAVE_LOCALE_H 1

/* Define to 1 if you have the `malloc' function. */
#define HAVE_MALLOC 1

/* Define to 1 if you have the <malloc.h> header file. */
/* #undef HAVE_MALLOC_H */

/* Define to 1 if you have the `memchr' function. */
#define HAVE_MEMCHR 1

/* Define to 1 if you have the `memmove' function. */
#define HAVE_MEMMOVE 1

/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1

/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1

/* Define to 1 if you have a working `mmap' system call. */
#define HAVE_MMAP 1

/* Define to 1 if you have the <mntent.h> header file. */
/* #undef HAVE_MNTENT_H */

/* Define to 1 if you have the `modf' function. */
#define HAVE_MODF 1

/* Define to 1 if you have the `munmap' function. */
#define HAVE_MUNMAP 1

/* Define to 1 if you have the <netdb.h> header file. */
/* #undef HAVE_NETDB_H */

/* Define to 1 if you have the <netinet/in.h> header file. */
/* #undef HAVE_NETINET_IN_H */

/* Define to 1 if you have the <poll.h> header file. */
#define HAVE_POLL_H 1

/* Define to 1 if you have the `pow' function. */
/* #undef HAVE_POW */

/* Define to 1 if you have the <pthread.h> header file. */
#define HAVE_PTHREAD_H 1

/* Define to 1 if you have the `realloc' function. */
#define HAVE_REALLOC 1

/* Define to 1 if you have the `select' function. */
#define HAVE_SELECT 1

/* Define to 1 if you have the `setenv' function. */
#define HAVE_SETENV 1

/* Define to 1 if you have the <shadow.h> header file. */
/* #undef HAVE_SHADOW_H */

/* Define to 1 if you have the `sqrt' function. */
/* #undef HAVE_SQRT */

/* Define to 1 if you have the <stddef.h> header file. */
#define HAVE_STDDEF_H 1

/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1

/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1

/* Define to 1 if you have the `strcasecmp' function. */
#define HAVE_STRCASECMP 1

/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1

/* Define to 1 if you have the `strdup' function. */
#define HAVE_STRDUP 1

/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1

/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1

/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1

/* Define to 1 if you have the `strrchr' function. */
#define HAVE_STRRCHR 1

/* Define to 1 if you have the `strstr' function. */
#define HAVE_STRSTR 1

/* Define to 1 if you have the `strtol' function. */
#define HAVE_STRTOL 1

/* Define to 1 if you have the `strtoul' function. */
#define HAVE_STRTOUL 1

/* Define to 1 if `st_rdev' is a member of `struct stat'. */
#define HAVE_STRUCT_STAT_ST_RDEV 1

/* Define to 1 if you have the <sys/file.h> header file. */
/* #undef HAVE_SYS_FILE_H */

/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1

/* Define to 1 if you have the <sys/ipc.h> header file. */
#define HAVE_SYS_IPC_H 1

/* Define to 1 if you have the <sys/mman.h> header file. */
#define HAVE_SYS_MMAN_H 1

/* Define to 1 if you have the <sys/mount.h> header file. */
/* #undef HAVE_SYS_MOUNT_H */

/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1

/* Define to 1 if you have the <sys/shm.h> header file. */
#define HAVE_SYS_SHM_H 1

/* Define to 1 if you have the <sys/socket.h> header file. */
/* #undef HAVE_SYS_SOCKET_H */

/* Define to 1 if you have the <sys/statfs.h> header file. */
/* #undef HAVE_SYS_STATFS_H */

/* Define to 1 if you have the <sys/statvfs.h> header file. */
/* #undef HAVE_SYS_STATVFS_H */

/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1

/* Define to 1 if you have the <sys/times.h> header file. */
#define HAVE_SYS_TIMES_H 1

/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1

/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1

/* Define to 1 if you have the <sys/vfs.h> header file. */
/* #undef HAVE_SYS_VFS_H */

/* Define to 1 if the system has the type `uintptr_t'. */
#define HAVE_UINTPTR_T 1

/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1

/* Define to 1 if you have the <values.h> header file. */
/* #undef HAVE_VALUES_H */

/* Define to 1 if you have the <vfw.h> header file. */
/* #undef HAVE_VFW_H */

/* Define to 1 if you have the <X11/extensions/XShm.h> header file. */
/* #undef HAVE_X11_EXTENSIONS_XSHM_H */

/* Define to 1 if you have the <X11/extensions/Xvlib.h> header file. */
/* #undef HAVE_X11_EXTENSIONS_XVLIB_H */

/* Define to 1 if the system has the type `_Bool'. */
#define HAVE__BOOL 1

/* Define as const if the declaration of iconv() needs const. */
#define ICONV_CONST 

/* Library major version */
#define LIB_VERSION_MAJOR 0

/* Library minor version */
#define LIB_VERSION_MINOR 3

/* Library revision */
#define LIB_VERSION_REVISION 0

/* Define to the sub-directory where libtool stores uninstalled libraries. */
#define LT_OBJDIR ".libs/"

/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
   */
/* #undef MAJOR_IN_MKDEV */

/* Define to 1 if `major', `minor', and `makedev' are declared in
   <sysmacros.h>. */
#define MAJOR_IN_SYSMACROS 1

/* Define to 1 if assertions should be disabled. */
/* #undef NDEBUG */

/* Define to 1 if your C compiler doesn't accept -c and -o together. */
/* #undef NO_MINUS_C_MINUS_O */

/* Name of package */
#define PACKAGE "zbar"

/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "mchehab+samsung@kernel.org"

/* Define to the full name of this package. */
#define PACKAGE_NAME "zbar"

/* Define to the full name and version of this package. */
#define PACKAGE_STRING "zbar 0.23.1"

/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "zbar"

/* Define to the home page for this package. */
#define PACKAGE_URL ""

/* Define to the version of this package. */
#define PACKAGE_VERSION "0.23.1"

/* If using the C implementation of alloca, define if you know the
   direction of stack growth for your system; otherwise it will be
   automatically deduced at runtime.
	STACK_DIRECTION > 0 => grows toward higher addresses
	STACK_DIRECTION < 0 => grows toward lower addresses
	STACK_DIRECTION = 0 => direction of growth unknown */
/* #undef STACK_DIRECTION */

/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1

/* Version number of package */
#define VERSION "0.23.1"

/* Define to 1 if the X Window System is missing or not being used. */
#define X_DISPLAY_MISSING 1

/* Program major version (before the '.') as a number */
#define ZBAR_VERSION_MAJOR 0

/* Program minor version (after '.') as a number */
#define ZBAR_VERSION_MINOR 23

/* Program patch version (after the second '.') as a number */
#define ZBAR_VERSION_PATCH 1

/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
/* #undef _LARGEFILE_SOURCE */

/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
   #define below would cause a syntax error. */
/* #undef _UINT32_T */

/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
   #define below would cause a syntax error. */
/* #undef _UINT64_T */

/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
   #define below would cause a syntax error. */
/* #undef _UINT8_T */

/* Minimum Windows API version */
/* #undef _WIN32_WINNT */

/* used only for pthread debug attributes */
#define __USE_UNIX98 1

/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */

/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef gid_t */

/* Define to `__inline__' or `__inline' if that's what the C compiler
   calls it, or to nothing if 'inline' is not supported under any name.  */
#ifndef __cplusplus
/* #undef inline */
#endif

/* Define to the type of a signed integer type of width exactly 32 bits if
   such a type exists and the standard includes do not define it. */
/* #undef int32_t */

/* Define to the type of a signed integer type of width exactly 64 bits if
   such a type exists and the standard includes do not define it. */
/* #undef int64_t */

/* Define to `long int' if <sys/types.h> does not define. */
/* #undef off_t */

/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */

/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef uid_t */

/* Define to the type of an unsigned integer type of width exactly 16 bits if
   such a type exists and the standard includes do not define it. */
/* #undef uint16_t */

/* Define to the type of an unsigned integer type of width exactly 32 bits if
   such a type exists and the standard includes do not define it. */
/* #undef uint32_t */

/* Define to the type of an unsigned integer type of width exactly 64 bits if
   such a type exists and the standard includes do not define it. */
/* #undef uint64_t */

/* Define to the type of an unsigned integer type of width exactly 8 bits if
   such a type exists and the standard includes do not define it. */
/* #undef uint8_t */

/* Define to the type of an unsigned integer type wide enough to hold a
   pointer, if such a type exists, and if the system does not define it. */
/* #undef uintptr_t */

#ifndef X_DISPLAY_MISSING
# define HAVE_X
#endif

which is really different from Windows

@hosiet
Copy link
Contributor

hosiet commented Feb 9, 2021

I see no real value simply posting all your exploration history on GitHub.

If you only want C/C++ library on msys2/mingw platform, please use prebuilt https://packages.msys2.org/package/mingw-w64-x86_64-zbar .

If you want extra bindings of other languages (e.g., Python), please work with existing MSYS2 packagers.

(P.S. These are just my personal suggestions. I am neither zbar upstream nor msys2 packager.)

@wqh17101
Copy link
Contributor Author

wqh17101 commented Feb 9, 2021

I see no real value simply posting all your exploration history on GitHub.

If you only want C/C++ library on msys2/mingw platform, please use prebuilt https://packages.msys2.org/package/mingw-w64-x86_64-zbar .

If you want extra bindings of other languages (e.g., Python), please work with existing MSYS2 packagers.

(P.S. These are just my personal suggestions. I am neither zbar upstream nor msys2 packager.)

This is not a problem but my personal process to show how to build a zbar lib can be used in Windows System instead of MSYS2 or any other subsystem.

Also if i want to use zbar via python binding . for now , i must install lib zbar first ,and then install zbar-python binding. That is not convinient.

So i found a way to build python whl with zbar-python binding and zbar lib all in one lib. So that a python users can just install once to use zbar. Also for python's flexibility , i just want to support the basic functions of zbar---scanning and recognization images to python`s user.

@mchehab
Copy link
Owner

mchehab commented Feb 15, 2021

I'll close it, as this is not really an issue.

Also, we have already an actions workflow to build it using Github's infra. The produced patches are both at the Zbar releases page (https://github.com/mchehab/zbar/releases), where the built files will be retained from 90 days (the maximum policy at Github) and at:

https://linuxtv.org/downloads/zbar/binaries/

@mchehab mchehab closed this as completed Feb 15, 2021
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

3 participants