【问题标题】:Make distutils look for numpy header files in the correct place让 distutils 在正确的位置查找 numpy 头文件
【发布时间】:2011-01-23 16:58:08
【问题描述】:

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

cimport numpy as np

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

我还有以下 distutils setup.py(复制自Cython user guide):

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
)

当我尝试使用 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

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

【问题讨论】:

    标签: python numpy distutils cython


    【解决方案1】:

    使用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
    )
    

    【讨论】:

    • 我在 ipython 笔记本中使用 %%cython 魔法时遇到了同样的问题。我想知道是否也有一个简单的解决方法
    • 对于以非numpy 相关工作为例的任何人,numpy.get_include 的定义是here。
    • 我不确定我是否正确实现了它,但看起来这使得setup.py 对远程安装毫无用处。你得到一个错误`ModuleNotFoundError: No module named 'numpy'`
    • 将尝试使其与 pipenv 一起使用,与 pip install 一起使用谢谢
    • 应该get_numpy_include() 不是np.get_include()?
    【解决方案2】:

    对于不使用 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
    )
    

    【讨论】:

      【解决方案3】:

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

      如果您的项目依赖于 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
      )
      

      您可以使用类似的技巧将 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
      )
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-27
        • 2011-09-24
        • 1970-01-01
        相关资源
        最近更新 更多