Dans mon installation, arrayobject.h
de numpy se trouve à …/site-packages/numpy/core/include/numpy/arrayobject.h
. J'ai écrit un script Cython trivial qui utilise numpy:
cimport numpy as np
def say_hello_to(name):
print("Hello %s!" % name)
J'ai également le code suivant setup.py
(copié à partir du guide d'utilisation de Cython ):
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("hello", ["hello.pyx"])]
setup(
name = 'Hello world app',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
Lorsque j'essaie de construire avec python setup.py build_ext --inplace
, Cython essaie de faire ce qui suit:
gcc -fno-strict-aliasing -Wno-long-double -no-cpp-precomp -mno-fused-madd \
-fno-common -dynamic -DNDEBUG -g -Os -Wall -Wstrict-prototypes -DMACOSX \
-I/usr/include/ffi -DENABLE_DTRACE -Arch i386 -Arch ppc -pipe \
-I/System/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5 \
-c hello.c -o build/temp.macosx-10.5-i386-2.5/hello.o
De manière prévisible, cela ne parvient pas à trouver arrayobject.h
. Comment faire en sorte que distutils utilise l'emplacement correct des fichiers numpy include (sans que l'utilisateur définisse $ CFLAGS)?
Utilisez numpy.get_include()
:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy as np # <---- New line
ext_modules = [Extension("hello", ["hello.pyx"])]
setup(
name = 'Hello world app',
cmdclass = {'build_ext': build_ext},
include_dirs = [np.get_include()], # <---- New line
ext_modules = ext_modules
)
La réponse donnée par @ vebjorn-ljosa est correcte, mais elle pose problème lorsqu'elle est utilisée avec install_requires=['numpy']
. Dans ce cas, votre fichier setup.py doit importer numpy, ce qui provoquera une erreur si vous essayez de pip install
votre projet sans exécuter pip install numpy
auparavant.
Si votre projet dépend de numpy et que vous souhaitez installer numpy automatiquement en tant que dépendance, vous devez définir include_dirs uniquement lorsque vos extensions sont en cours de construction. Vous pouvez le faire en sous-classant build_ext
:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
class CustomBuildExtCommand(build_ext):
"""build_ext command for use when numpy headers are needed."""
def run(self):
# Import numpy here, only when headers are needed
import numpy
# Add numpy headers to include_dirs
self.include_dirs.append(numpy.get_include())
# Call original build_ext command
build_ext.run(self)
ext_modules = [Extension("hello", ["hello.pyx"])]
setup(
name = 'Hello world app',
cmdclass = {'build_ext': CustomBuildExtCommand},
install_requires=['numpy'],
ext_modules = ext_modules
)
Et vous pouvez utiliser une astuce similaire pour ajouter cython en tant que dépendance automatiquement installée:
from distutils.core import setup
from distutils.extension import Extension
try:
from Cython.setuptools import build_ext
except:
# If we couldn't import Cython, use the normal setuptools
# and look for a pre-compiled .c file instead of a .pyx file
from setuptools.command.build_ext import build_ext
ext_modules = [Extension("hello", ["hello.c"])]
else:
# If we successfully imported Cython, look for a .pyx file
ext_modules = [Extension("hello", ["hello.pyx"])]
class CustomBuildExtCommand(build_ext):
"""build_ext command for use when numpy headers are needed."""
def run(self):
# Import numpy here, only when headers are needed
import numpy
# Add numpy headers to include_dirs
self.include_dirs.append(numpy.get_include())
# Call original build_ext command
build_ext.run(self)
setup(
name = 'Hello world app',
cmdclass = {'build_ext': CustomBuildExtCommand},
install_requires=['cython', 'numpy'],
ext_modules = ext_modules
)
Remarque: ces approches ne fonctionnent qu'avec pip install .
. Ils ne fonctionneront pas pour python setup.py install
ou python setup.py develop
car ces commandes entraînent l'installation de dépendances après votre projet plutôt qu'avant.
Pour ceux qui n'utilisent pas Cython, une légère modification de la solution de R_Beagrie sans cette dépendance consiste à importer simplement build_ext à partir de distutils.command.build_ext au lieu de Cython.
from distutils.core import setup
from distutils.extension import Extension
from distutils.command.build_ext import build_ext
class CustomBuildExtCommand(build_ext):
"""build_ext command for use when numpy headers are needed."""
def run(self):
# Import numpy here, only when headers are needed
import numpy
# Add numpy headers to include_dirs
self.include_dirs.append(numpy.get_include())
# Call original build_ext command
build_ext.run(self)
ext_modules = [Extension("hello", ["hello.c"])]
setup(
name = 'Hello world app',
cmdclass = {'build_ext': CustomBuildExtCommand},
install_requires=['numpy'],
ext_modules = ext_modules
)