python 让 distutils 在正确的位置寻找 numpy 头文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2379898/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-04 00:30:48  来源:igfitidea点击:

Make distutils look for numpy header files in the correct place

pythonnumpydistutilscython

提问by Vebjorn Ljosa

In my installation, numpy's arrayobject.his located at …/site-packages/numpy/core/include/numpy/arrayobject.h. I wrote a trivial Cython script that uses numpy:

在我的安装中,numpyarrayobject.h位于…/site-packages/numpy/core/include/numpy/arrayobject.h. 我写了一个使用 numpy 的简单 Cython 脚本:

cimport numpy as np

def say_hello_to(name):
    print("Hello %s!" % name)

I also have the following distutils setup.py(copied from the Cython user guide):

我还有以下 distutils setup.py(从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
)

When I try to build with python setup.py build_ext --inplace, Cython tries to do the following:

当我尝试使用 构建时python setup.py build_ext --inplace,Cython 尝试执行以下操作:

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

Predictably, this fails to find arrayobject.h. How can I make distutils use the correct location of numpy include files (without making the user define $CFLAGS)?

可以预见,这无法找到arrayobject.h. 如何让 distutils 使用 numpy 包含文件的正确位置(不让用户定义 $CFLAGS)?

回答by Vebjorn Ljosa

Use numpy.get_include():

使用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"],
                                  include_dirs=[get_numpy_include()])]   # <---- New argument

setup(
  name = 'Hello world app',
  cmdclass = {'build_ext': build_ext},       
  ext_modules = ext_modules
)

回答by R_Beagrie

The answer given by @vebjorn-ljosa is correct, but it causes problems when used in conjunction with install_requires=['numpy']. In this situation, your setup.py needs to import numpy, which will cause an error if you try to pip installyour project without running pip install numpyfirst.

@vebjorn-ljosa 给出的答案是正确的,但与install_requires=['numpy']. 在这种情况下,您的 setup.py 需要导入 numpy,如果您pip install在没有pip install numpy先运行的情况下尝试您的项目,则会导致错误。

If your project depends on numpy, and you want numpy to be installed automatically as a dependency, you need to set include_dirs only when your extensions are actually being built. You can do this by subclassing build_ext:

如果您的项目依赖于 numpy,并且您希望 numpy 作为依赖项自动安装,则仅在实际构建扩展时才需要设置 include_dirs。您可以通过子类化来做到这一点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
)

And you can use a similar trick to add cython as an automatically installed dependency:

您可以使用类似的技巧将 cython 添加为自动安装的依赖项:

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
)

Note: these approaches only work with pip install .. They won't work for python setup.py installor python setup.py developas in these commands cause dependencies to be installed after your project, rather than before.

注意:这些方法仅适用于pip install .. 它们不适用于python setup.py installpython setup.py develop因为在这些命令中导致依赖项在您的项目之后而不是之前安装。

回答by tgbrooks

For anyone not using Cython, a slight modification of R_Beagrie's solution without that dependency is if you simply import build_ext from distutils.command.build_ext instead of Cython.

对于不使用 Cython 的任何人,如果您只是从 distutils.command.build_ext 而不是 Cython 导入 build_ext,则对没有这种依赖性的 R_Beagrie 解决方案稍作修改。

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
)