我在Python扩展中使用了仅 header 的C++库。我希望能够将它们安装到Python的include路径,以便可以使用python3 setup.py build轻松编译扩展。我的能力有限,但是有两件事我无法工作(请参见下文):

  • 如何使用python3 setup.py install安装头文件?目前,我只得到一些*.egg文件,但没有安装头文件。
  • 如何保留模块的文件结构?当前,文件结构被错误地弄平了。

  • 什么有效

    使用以下setup.py
    from setuptools import setup
    
    setup(
       name        = 'so',
       description = 'Example',
       headers     = [
          'so.h',
       ],
    )
    

    我可以将模块上传到PyPi:
    python3 setup.py bdist_wheel --universal
    twine upload dist/*
    

    然后使用pip安装它:
    pip3 install so
    

    在我的系统上,然后我在这里找到标题
    /usr/local/include/python3.6m/so/so.h
    

    当我使用Python编译扩展时可用。

    如何使用“python3 setup.py install”?

    使用这种策略,我不能简单地运行
    python3 setup.py install
    

    在这种情况下,将安装一些so*.egg,但 header 不会存储在编译器可用的位置。

    如何保留文件结构?

    当模块稍微复杂一点,并且有一些目录层次结构时,我也会遇到问题。对于以下setup.py
    from setuptools import setup
    
    setup(
      name        = 'so',
      description = 'Example',
      headers     = [
        'so.h',
        'so/implementation.h',
      ],
    )
    

    问题是将 header 安装到
    /usr/local/include/python3.6m/so/so.h
    /usr/local/include/python3.6m/so/implementation.h
    

    从而使原始文件结构扁平化。

    如何解决这两个问题?

    最佳答案



    不幸的是,只要您使用setuptools,您就不能这样做。调用setuptools.setup()会在后台发生什么?一个egg安装程序正在构建(bdist_egg命令)并安装(通过easy_install),并且bdist_eggeasy_install都不支持包含/安装头文件。尽管distribution对象带有 header 信息,但在install命令期间从未请求过它。这是一个老的众所周知的问题,但从未解决,因为显然,头文件的安装不适合egg build/install过程。

    因此,您有三个选择(或者至少我知道三个选择)。不推荐使用它们中的两个(两者都导致切换到distutils),并且仅出于完整性考虑提供它们:

    distutils安装(不推荐)

    $ sed 's/from setuptools import setup/from distutils.core import setup/' setup.py
    

    这样,好的distutils在执行python setup.py install时将负责安装,不会构建任何egg安装程序,而是会调用install_headers。但是,这还包括放弃setuptools的所有功能,包括setup()中的其他关键字args和其他所有好东西,不用说,无法通过distutils卸载通过pip安装的软件包。
    old-and-unmanageable安装(不推荐)

    使用以下命令运行安装
    $ python setup.py install --old-and-unmanageable
    

    如果您明确希望运行setuptools安装,这是distutils提供的开关。不会安装egg安装程序,而是会调用distutils.command.install.install。因此,安装与裸distutils安装相同。

    这种方法的缺点:与裸distutils安装相同,外加:setuptools谴责开关的使用;如果您忘记提供它,则必须先安装鸡蛋,然后重新进行安装。

    python setup.py install替换pip install(推荐)
    pip能够从源目录安装软件包;只是发出
    $ pip install dir/
    

    假设dir包含setup.py。这样,就可以从源文件中构建一个wheel文件(与bdist_wheel中的文件相同;实际上,该命令首先运行)并安装,可以很好地管理头文件的安装。



    您将需要稍微调整install_headers命令:
    import os
    from distutils.command.install_headers import install_headers as install_headers_orig
    from setuptools import setup
    
    class install_headers(install_headers_orig):
    
        def run(self):
            headers = self.distribution.headers or []
            for header in headers:
                dst = os.path.join(self.install_dir, os.path.dirname(header))
                self.mkpath(dst)
                (out, _) = self.copy_file(header, dst)
                self.outfiles.append(out)
    
    setup(
        name='so',
        headers=['h1.h', 'subtree/h2.h'],
        cmdclass={'install_headers': install_headers},
        ...
    )
    

    这里必不可少的是生产线
    dst = os.path.join(self.install_dir, os.path.dirname(header))
    

    Vanilla install_headers copies the header files directly to install_dir ;重载的install_headers命令中的上述行还负责头文件名中的最终子目录。在安装软件包时,现在应该保留子目录:
    $ pip show -f so | grep include
      ../../../include/site/python3.6/so/h1.h
      ../../../include/site/python3.6/so/subtree/h2.h
    

    关于python - 使用Python安装仅 header 的库,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50101740/

    10-14 17:37
    查看更多