命令 `python setup.py build_ext --inplace` 总是创建一个新目录

The command `python setup.py build_ext --inplace` always create a new directory

假设我有一个 python 结构如下的包:

foo/
  __init__.py
  setup.py
  bar/
    __init__.py
    bar.pyx

setup.py的内容是

from distutils.core import setup
from Cython.Build import cythonize
import numpy as np

setup(
    ext_modules=cythonize("bar/bar.pyx"),
    include_dirs=[np.get_include()]
)

那我就运行

python setup.py build_ext --inplace

因为我需要编译后的文件bar.so正好放在bar/中。但是前面的命令在 bar 下创建了一个新目录 foo/bar/,并将 bar.so 放在那里,比如说

foo/
  __init__.py
  setup.py
  bar/
    __init__.py
    bar.pyx
    foo/
      bar/
        bar.so

而我需要的是

foo/
  __init__.py
  setup.py
  bar/
    __init__.py
    bar.pyx
    bar.so

这些烦人的事情发生在我把foobar包起来之后。如果我删除 foo/__init__.pybar/__init__.py,那么 bar.so 将出现在 foo/ 中,但仍然不会出现 foo/bar/。我已阅读手册,但没有找到解决此问题的选项。

那么如果我要求bar.so出现在正确的位置,同时保留两个__init__.py文件,我该怎么办?

setup.py 不应该存在于包中。您需要将包向上移动一个目录:

foo/
  setup.py
  foo/
    __init__.py
    bar/
      __init__.py
      bar.pyx

这是我遇到的大多数包所遵循的结构。


关于 scikit-learn,您曾用它来获得灵感:

我当然不知道 scikit-learn 对它们的多个 setup.py 文件做了什么,但我敢打赌说外部 setup.py 正在使用(调用、导入) 其他 setup.pys,将子包配置的详细信息分发给那些 setup.pys。它只是不太明显,因为(我认为)distutils/setuptools 正在做大量的这种导入工作。

因此,外部设置负责整个包,内部设置负责子包的细节。

不过到头来还是隔了一层setup.py一个大文件。尝试 运行

python setup.py build_ext --inplace

在任何内部 setup.pys 上,它要么失败,要么什么都不做(至少对于我给它的两次尝试)。

因此,那些子包 setup.py 可能更恰当地被视为 setup_config.py 文件。

作为一个有趣的结果,安装该软件包会将那些 setup.py 文件保留在它们各自的子包中(以及 sklearn 中的文件)。当一个人使用这些包时,也许会有一些用处,但我想这只是 scikit-learn 设置过程和包含所有 *.py 文件的产物。