how to write setup.py to install python extention (xxx.so file) built by SWIG?

horbat picture horbat · Jun 30, 2016 · Viewed 7.4k times · Source

Using SWIG to build python extensions (xxx.so) is easier than distutils. You don't need to write a wrap.c program to wrap your original c program. So I'd like using SWIG than Distutils. But There is no methods to install extensions(xxx.so) automatically by writing a setup.py file. This troubled me for many days.

To explain the question more intelligible, I use the Step strategy to make it clear.

STEP 1: There is a original C/C++ code. And then use SWIG to create a Python wrapper.

STEP 2: Use Distuils (write a setup.py) or just gcc command line to create Python extension file. The name of the Python extension is xxx.so. Obviously, in this step, you can combine the compiling and installation together by using Distuils.

STEP 3: install the xxx.so Python extension by writing a setup.py.

I just don't know the STEP 3 that how to write a setup.py to install xxx.so Python extensions.

Is there any way to install python extensions (xxx.so) by writing setup.py and not using sys.path.append() or sys.path.insert() methods?

Thank you very much for any answer provided by you !

In the end, I tried the STEP 2 method that combine compilation and installation together. It can work correctly, but it's not my purpose that only install _xxx.so Python extension using setup.py.

directory structure:

setup.py
src/
    libdemo/
        __init__.py
        LibHello.py
lib/
    palindrome.c   # original C code
    palindrome_wrap.c  # Python wrapper built by SWIG

setup.py code:

#-*- coding:utf-8 -*-
import sys
import os
from setuptools import setup, find_packages, Extension

libPath = "lib"

moduleLibPalindrome = Extension(
      name = 'libdemo._palindrome', 
      sources = [os.path.join(libPath, 'palindrome_wrap.c'), 
            os.path.join(libPath, 'palindrome.c')]
)
setup (
      name = 'test_example',
      version = '0.1',
      author = "Hobart",
      description = "Install extension from original C/C++",
      packages= find_packages(where = 'src'),
      package_dir = {'':'src'},
      ext_modules=[moduleLibPalindrome]
)

result check :

>>> from libdemo import _palindrome
>>> dir(_palindrome)
['SWIG_PyInstanceMethod_New', '__builtins__', '__doc__', '__file__',      '__name__', '__package__', 'is_palindrome']
>>> _palindrome.is_palindrome('asddsa')
1
>>> 

The C code source file and _palindrome.so file are shown as following. you can download and do experiment on your computer.

Answer

m7thon picture m7thon · Jun 30, 2016

Distutils is not about writing extensions, but about compiling and installing them. SWIG can help you creating the Python wrappers for your C/C++ code, but does not handle compiling and installing them.

So, distutils can (and should) be used to install the SWIG generated extensions. See the SWIG docs on using distutils.

EDIT: I am a little confused about what you are trying to do. Normally, you would use distutils for compiling and installing your extension. This can still be done in two separate steps by calling

python setup.py build_ext
python setup.py install

However, if I understand you correctly, for whatever reason, you have a precompiled extension (i.e., xxx.py and _xxx.so), and wish to merely install these using e.g. distutils.

You can use the package_data keyword for distutils, i.e., the following setup.py:

from distutils.core import setup
setup (name = 'xxx',
       version = '0.1',
       author = "Nobody",
       description = """Install precompiled extension""",
       py_modules = ["xxx"],
       packages=[''],
       package_data={'': ['_xxx.so']},
       )