如何解决将预编译的扩展名放在非纯Python Wheel软件包的根文件夹中
TL; DR 如何使distutils / setuptools正确地包含非纯数据文件?
我有一个项目,该项目使用自定义工具链进行一些非平凡的代码生成,然后用SWIG包装生成的代码,最后构建Python扩展。 Cmake很好地封装了所有这些内容,最后,我在项目的根目录中有了一个文件夹,该文件夹与任何其他Python软件包完全一样。
我想要一个简单的setup.py
,因此我可以将此包包装到轮子中,然后将其运送到PyPI,这样普通的Python用户就不必处理构建过程。 SO上有很多关于如何强制设置工具生成非纯轮的答案,然后您可以使用package_data
字段或MANIFEST.in
文件来捆绑扩展名。
问题是此方法导致格式错误,因为扩展名包含在purelib
下而不是根目录下(扩展名属于Root-Is-Pure: False
目录下)。一些工具和发行版依靠这种分隔是正确的。
我不感兴趣的问题:自定义扩展以从setup.py
内部运行cmake(不想添加用于配置项目的另一层间接操作,不想在构建选项更改时维护它),修改生成的转轮,我宁愿避免向setup.py
解决方法
这有效。 distutils
和setuptools
必须是现有的中央Python基础架构中设计最糟糕的部分。
from setuptools import setup,find_packages,Extension
from setuptools.command.build_ext import build_ext
import os
import pathlib
import shutil
suffix = '.pyd' if os.name == 'nt' else '.so'
class CustomDistribution(Distribution):
def iter_distribution_names(self):
for pkg in self.packages or ():
yield pkg
for module in self.py_modules or ():
yield module
class CustomExtension(Extension):
def __init__(self,path):
self.path = path
super().__init__(pathlib.PurePath(path).name,[])
class build_CustomExtensions(build_ext):
def run(self):
for ext in (x for x in self.extensions if isinstance(x,CustomExtension)):
source = f"{ext.path}{suffix}"
build_dir = pathlib.PurePath(self.get_ext_fullpath(ext.name)).parent
os.makedirs(f"{build_dir}/{pathlib.PurePath(ext.path).parent}",exist_ok = True)
shutil.copy(f"{source}",f"{build_dir}/{source}")
def find_extensions(directory):
extensions = []
for path,_,filenames in os.walk(directory):
for filename in filenames:
filename = pathlib.PurePath(filename)
if pathlib.PurePath(filename).suffix == suffix:
extensions.append(CustomExtension(os.path.join(path,filename.stem)))
return extensions
setup(
# Stuff
ext_modules = find_extensions("PackageRoot"),cmdclass = {'build_ext': build_CustomExtensions}
distclass = CustomDistribution
)
我正在将扩展复制到构建目录中,仅此而已。我们忽略了这种分布,以向鸡蛋信息作者撒谎,说明它们具有任何扩展性,而一切都是肉汁。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。