Python package using Swig

Ref

Installation

sudo apt install -y libffi-dev python3 python3-dev python3-pip swig &&\
python3 -m pip install -U --user pip setuptools wheel twine keyrings.alt

Package directory structure

workspace
├── LICENSE.txt
├── MANIFEST.in
├── README.md
├── debian
│   └── changelog
├── setup.cfg
├── setup.py
├── c_src
│   └── ...
├── py_src
│   └── package1
│       ├── package2
│       │   ├── __init__.py
│       │   └── module1.py
│       ├── __init__.py
│       └── __main__.py
├── interface
│   └── package.i
└── test
    └── ...

Interface file

%module example

%{
    #include "example.h"
%}

%include "example.h"

C++

class

class Foo
{
public:
    Foo();
    ~Foo();
    int bar( int x );
};

Python에서 class를 사용할 수 있게 기초 틀을 작성해줘야 합니다. __init__.py 등에 작성하면 됩니다.

class Foo:
    def __init__(self):
       self.this = new_Foo()

    def __del__(self):
       delete_Foo(self.this)

    def bar(self, x):
        return Foo_bar(self.this, x)

Python

__init__.py

from <package>._<package> import *

...

Build

setup.py

Ref: https://setuptools.readthedocs.io/en/latest/setuptools.html

from setuptools import setup, Extension
from setuptools.command.sdist import sdist
from setuptools.command.build_py import build_py
from os import path

BASE_DIR = path.dirname(path.abspath(__file__))
CHANGELOG_PATH = path.join(BASE_DIR, "debian/changelog")

ext_modules = [
    Extension(
        "<package>._<package>",
        sources=["interface/<package>.i"],
        libraries=["<package>"],
        swig_opts=["-c++",
            "-I/usr/local/include",
            "-I/usr/include"]
    ),
]

with open(CHANGELOG_PATH, "r") as f:
    version = f.readline()
    version = version.split()
    version = version[1][1:-1]

'''
for upload
'''
class sdist_after_ext(sdist):
    def run(self):
        self.run_command("build_ext")
        return sdist.run(self)

'''
in the distribution when running setup.py bdist or bdist_wheel.
'''
class build_py_after_ext(build_py):
    def run(self):
        self.run_command("build_ext")
        return build_py.run(self)

setup(
    version = version,
    ext_modules = ext_modules,
    cmdclass = {"sdist": sdist_after_ext,
                "build_py": build_py_after_ext},
)

setup.cfg

[metadata]
name =
url =
project_urls =
    Source =

author = Hyeonki Hong
author_email = hhk7734@gmail.com
description =
long-description = file: README.md, debian/changelog
long_description_content_type = text/markdown
keywords =
license =
classifiers =
    Programming Language :: Python :: 3
    License :: OSI Approved :: MIT License
    Operating System :: POSIX :: Linux
    Intended Audience :: Developers
    Topic :: Software Development
    Topic :: System :: Hardware

[options]
package_dir =
    = py_src
packages = find:

[options.packages.find]
where = py_src

Ref: https://pypi.org/classifiers/

MANIFEST.in

include LICENSE.txt
include README.md
include debian/*
include c_src/*
include test/*

Using setuptools

The preferred approach to building an extension module for python is to compile it with setuptools, which comes with all recent versions of python.

python3 setup.py sdist
python3 setup.py install --user

Hand compiling a dynamic module

swig -python example.i
gcc -O2 -c -fPIC example.c example_wrap.c $(python3-config --cflags)
gcc -shared -o _example.so example.o example_wrap.o

pip 등록

dist

python3 setup.py sdist

Test 등록/설치

python3 -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
python3 -m pip install --index-url https://test.pypi.org/simple/ --verbose --user [package]

정식 등록/설치

python3 -m twine upload dist/*
python3 -m pip install [package]