我有一个仅在我的Python扩展中使用的标头C ++库。我希望能够将它们安装到Python的包含路径中,这样我就可以使用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
在这种情况下,会安装一些so*.egg
,但标题不会存储在编译器可用的位置。
当模块稍微复杂一点,并且有一些目录层次结构时,我也会遇到问题。对于以下setup.py
from setuptools import setup
setup(
name = 'so',
description = 'Example',
headers = [
'so.h',
'so/implementation.h',
],
)
问题是标题已安装到
/usr/local/include/python3.6m/so/so.h
/usr/local/include/python3.6m/so/implementation.h
因此扁平化原始文件结构。
如何解决这两个问题?
答案 0 :(得分:4)
如何使用
python3 setup.py install
安装标头文件?
不幸的是,只要您使用setuptools
,就无法做到。当你致电setuptools.setup()
时,幕后会发生什么?正在构建一个egg安装程序(bdist_egg
)并安装(通过easy_install
),bdist_egg
和easy_install
都不支持包含/安装标头。虽然distribution
对象带有头信息,但在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()
中的其他关键字参数以及所有其他好东西,不用说无法卸载通过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))
香草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