python - 使用 Python 安装仅标头库
问题描述
我有一个仅在我的 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
然后在我的系统上找到标题here
/usr/local/include/python3.6m/so/so.h
当我用 Python 编译扩展时可用。
如何使用“python3 setup.py install”?
使用这种策略我不能简单地运行
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
从而使原始文件结构变平。
如何解决这两个问题?
解决方案
如何使用
python3 setup.py install
安装头文件?
不幸的是,只要您使用setuptools
. 当你打电话时,引擎盖下会发生什么setuptools.setup()
?正在构建(bdist_egg
命令)和安装(通过easy_install
)的 egg 安装程序,既不bdist_egg
也不easy_install
支持包含/安装标头。尽管该对象带有标头信息,但在命令distribution
期间从不请求它。install
这是一个从未解决的老问题,因为很明显,头文件的安装不适合 egg 构建/安装过程。
因此,您有三个选项(或者我知道的至少三个选项)。不推荐使用其中两个(都导致切换到distutils
),仅出于完整性考虑而提供:
裸机distutils
安装(不推荐)
$ sed 's/from setuptools import setup/from distutils.core import setup/' setup.py
这样,good ol'distutils
将在安装时负责安装python setup.py install
,不会构建并install_headers
调用 egg 安装程序。但是,这也包括放弃setuptools
包含附加关键字 argssetup()
和所有其他好东西的所有功能,不用说distutils
通过pip
.
old-and-unmanageable
安装(不推荐)
运行安装
$ python setup.py install --old-and-unmanageable
setuptools
如果您明确希望运行distutils
安装,这是一个开关。egg 安装程序没有被构建,而是distutils.command.install.install
被调用。因此,安装与裸distutils
安装相同。
这种方法的缺点:与bare distutils
install plus相同: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))
vanillainstall_headers
将头文件直接复制到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-3.x - 计算熊猫中两列之间的动态差异
- javascript - Javascript:使用类比在需要时创建对象有什么好处?
- discord.js - 什么在 discord.js 中将消息定义为“缓存”
- c# - 从 MainActivity 类将新字符串注入 Fragment/ViewModel
- c# - C# Selenium 代理选项
- flutter-layout - Flutter:可滚动的内容位于模糊的小部件下方
- angular - Angular Json Schema Form根据来自另一个选择字段的值动态更改titleMap
- python - 是否有类似于 R 的矩阵(c())的 Python 参数?
- c# - Asp.Net Web 应用程序中的 linq 查询“必须是可简化节点”错误
- python - 如何将字符串的第一个和最后一个字母大写?