24

I am trying to compile, install and run a package that we'll call myPackage. It contains a *.pyx file that calls the function fftw_set_timelimit() from library fftw. Currently, when I run a script clientScript.py that imports the package I obtain the following error message :

Traceback (most recent call last):
  File "clientScript.py", line 5, in <module>
    import myPackage.myModule
ImportError: /usr/local/lib/python2.7/dist-packages/myPackage/myModule.so: undefined symbol: fftw_set_timelimit

From what I understand (I am quite new to python and cython), the linking with the C library is not yet performed in my package. Indeed, my setup.py file looks like this :

from setuptools   import setup,find_packages
from Cython.Build import cythonize
import os

setup(
    name = "myPackage",
    version = "0.0.1",
    url = "none",
    author = "me",
    author_email = "me@me.me",
    packages=find_packages(),
    ext_modules = cythonize("pyClo/pyClo.pyx"),
)

As you can see my setup.py file uses setuptools. I decided to do so since it is recommended by the Python Packaging User Guide. However, the instructions in the Cython documentation use distutils instead. Linking libraries is done through a call to distutils.Extension('file',['file.pyx'],libraries='fftw'). How do I achieve the same result using setuptools ?

Gael Lorieul
  • 3,006
  • 4
  • 25
  • 50

1 Answers1

31

It turns out setuptools has a module setuptools.extension.Extension which is used in the same way as the distutils.extension.Extension module .

In the end, the setup.py file looks something like :

from setuptools import setup, find_packages
from setuptools.extension import Extension
from Cython.Build import cythonize

extensions = [
    Extension(
        "myPackage.myModule",
        ["myPackage/myModule.pyx"],
        include_dirs=['/some/path/to/include/'], # not needed for fftw unless it is installed in an unusual place
        libraries=['fftw3', 'fftw3f', 'fftw3l', 'fftw3_threads', 'fftw3f_threads', 'fftw3l_threads'],
        library_dirs=['/some/path/to/include/'], # not needed for fftw unless it is installed in an unusual place
    ),
]

setup(
    name = "myPackage",
    packages = find_packages(),
    ext_modules = cythonize(extensions)
)

Here is an overview of my installation directory :

.
├── MANIFEST.in
├── myPackage
│   └── myModule.pyx
├── README.rst
└── setup.py

where myModule.pyx is the file that calls fftw_set_timelimit().

MANIFEST.in contains :

include myPackage/*.*

and README.rst is a mere plain text file.

Gael Lorieul
  • 3,006
  • 4
  • 25
  • 50
  • 2
    According to [distutils documentation](https://docs.python.org/2/distutils/apiref.html#distutils.core.Extension), `distutils.core.Extension` takes as a first argument : "_the full name of the extension, including any packages — ie. not a filename or pathname, but Python dotted name_" Therefore, instead of `"myPackage/myModule"`, one should have `"myPackage.myModule"`. – SylM Oct 12 '16 at 15:27
  • @SylM I haven't been using python in a while now… So it's going to be some effort for me to double check that replacing the slash "/" by a point "." as you are suggesting indeed works. However if you test the solution and tell me it's ok, then I'll edit my answer accordingly. By "testing the solution" I mean starting a new project from scratch and making sure you can make it work. Would you like to do that ? ;) – Gael Lorieul Oct 25 '16 at 13:43
  • @GLorieul I have just used the above template using the dotted name syntax, and successfully compiled. – Gilly Feb 16 '17 at 04:24
  • 1
    @Gilly thanks! I updated my answer accordingly : can you double check that the edit I made is correct please? – Gael Lorieul Feb 16 '17 at 09:28