【问题标题】:Adding output file to Python extension将输出文件添加到 Python 扩展
【发布时间】:2012-05-11 22:59:54
【问题描述】:

我已经定义了一个自定义 build_ext 来构建一个时髦的扩展,我正试图让它对 pip 友好。以下是我正在做的精简版。

foo_ext = Extension(
  name='foo/_foo',
  sources=foo_sources,
)

class MyBuildExt(build_ext):
  def build_extension(self, ext):
    # This standalone script builds the __init__.py file 
    #  and some .h files for the extension
    check_call(['python', 'build_init_file.py'])

    # Now that we've created all the init and .h code
    #  build the C/C++ extension using setuptools/distutils
    build_ext.build_extension(self, ext)

    # Include the generated __init__.py in the build directory 
    #  which is something like `build/lib.linux-x86/foo/`.  
    #  How can I get setuptools/distutils to install the 
    #  generated file automatically?!
    generated_file = 'Source/foo/__init__.py'
    output_path = '/'.join(self.get_outputs()[0].split('/')[:-1])
    self.move_file(generated_file, output_path)

setup(
    ...,
    ext_modules = [foo_ext],
    cmdclass={'build_ext' : MyBuildExt},
)

打包这个模块并使用 pip 安装后,我的 virtualenv 的 site-packages 目录中有一个模块 foo。目录结构如下所示。

foo/
foo/__init__.py
foo/_foo.so

egg-info/SOURCES.txt 文件不包括我手动创建/移动的 __init__.py 文件。当我执行pip uninstall foo 时,该命令会将foo/__init__.py 留在我的virtualenv 的站点包中。我想 pip 删除整个包。如何将生成的 __init__.py 文件添加到已安装的输出文件列表中?

我知道这是令人作呕和骇人听闻的,所以我欢迎恶心和骇人听闻的答案!

尝试:

  1. 添加了packages=['foo'] -- 当我这样做时,pip 不会构建扩展。还尝试调整包名称的文件路径/命名空间版本——没有区别。

【问题讨论】:

    标签: python pip setuptools distutils python-extensions


    【解决方案1】:

    为了让 distutils 安装 Python 包,你需要传递 packages=['foo'],如果你把它放在不是项目根目录的地方(我是指 setup.py 旁边的 foo 目录脚本),就像您在这里所做的那样,您还必须通过 package_dir={'foo': 'Source'} 或使用更简单的布局。如果您的 setup.py 脚本包含此 packages 参数,则 build 命令将调用 build_py 命令将 Python 源文件(和目录)移动到 build 目录,稍后将由 install 命令复制。

    这里的问题是您的foo/__init__.py 文件是由build_ext 命令构建的,该命令在build_py 之后运行。您需要使用自定义构建命令覆盖它:

    class MyBuild(build):
      sub_commands = [('build_clib', build.has_c_libraries),
                      ('build_ext', build.has_ext_modules),
                      ('build_py', build.has_pure_modules),
                      ('build_scripts', build.has_scripts),
                     ]
    
    setup(..., cmdclass={'build': MyBuild, 'build_ext': MyBuildExt})
    

    sub_commands 属性中的元素是(命令名,调用函数来决定是否运行命令)的元组;这在源代码中有记录,但我不记得文档中是否解释过。在标准构建类中 build_py 在 build_clib 之前。我可能会在 Python 2.7 的下一个版本中对此进行更改,因为据报道它与 2to3 转换的交互很糟糕。

    【讨论】:

    • 这很好,我学到了一些关于 distutils 的知识。谢谢,埃里克!
    【解决方案2】:

    首先,您的 Extension 实例中的 name 参数应该是模块名称 (foo._foo),而不是路径。

    您是否尝试将 packages=['foo'] 添加到您的设置调用中?

    【讨论】:

    • 我认为文件层次结构/命名空间差异转化为同一件事。
    • 不过,使用正确的格式而不是靠运气来工作并没有什么坏处。我想我已经找到了解决您的问题的方法,如果我有时间,我明天会发布另一个答案。保持希望:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 1970-01-01
    • 2019-01-26
    • 2023-03-06
    • 2022-01-25
    • 1970-01-01
    • 2014-11-05
    相关资源
    最近更新 更多