Notes on building Cython using setup.py
dev/python | dev/cython
Basic structure
from setuptools import Extension, setup
from Cython.Build import cythonize
extensions = [
Extension(
name=...,
sources=[
...
],
include_dirs=[
...
],
library_dirs=[
...
],
libraries=[
...
],
runtime_library_dirs=[
...
],
define_macros=[
(..., ...),
...
],
extra_compile_args=[
...
],
extra_link_args=[
...
],
language='...',
),
...
]
setup(
ext_modules=cythonize(extensions, language_level='3'),
zip_safe=False,
)
Notes:
-
name=...: to be explained in detail below -
sources=[...]: from my experiments, seem must contain one and only one.pyxCython source -
language_level='3'is used when developing in Python 3. -
zip_safe=Falseis used as per cython doc -
define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")]can be used when devloping using newer version ofnumpy, to avoid compile-time warnings, despite harmless
Name of Extension
the full name of the extension, including any packages – ie. not a filename or pathname, but Python dotted name
For example, a name foo.bar will generate ./foo/bar.*.so file, where * can be obtained by invoke on command line python3-config --extension-suffix, e.g. ./foo/bar.cpython-39-darwin.so.
The file path is relative to build root, the location where setup.py sits.
Precedence of import
Suppose the extension we are talking about is named foo.bar.
Let’s assume there’s already a directory named ./foo/bar/.
Open Python prompt under build root and type from foo.bar import xxx where xxx is anything defined in foo.bar.
This should work fine.
Now add an empty foo/bar/__init__.py.
Repeat the above process; it should echo AttributeError on xxx.
This means that the Python package foo.bar takes precedence over the extension module foo.bar.
Another circumstance.
Again the extension is named foo.bar.
However, there’s now a directory ./foo/ with bar.py and __init__.py inside.
From my experiment, this time extension foo.bar takes precedence over the Python package foo.bar.
It appears quite involved to me. So the best practice might be just to avoid having name collision with Python module/package.