如何用pyproject替换setup.py.本地C构建依赖?



我偶然发现了这个小项目,用于创建Black-Scholes函数的c编译版本,以便在python中使用。

尽管示例代码似乎是在今年7月发布的,但似乎使用setup.py类型的构建已经被弃用,超出了遗留构建。任何编译失败,首先抱怨缺少MS C++ 14编译器(这不是真的),然后进一步调查,似乎表明setup.py不能再使用。

Q:如何将setup.py转换为有效的pyproject.toml文件?

from setuptools import setup, Extension
ext = Extension('bs', sources=['black_scholes/bs.c'])
setup(
name="black_scholes",
version="0.0.1",
description="European Options Pricing Library",
packages=['black_scholes'],
ext_modules=[ext]
)

从这个有点模糊的网站(上面),我创建了下面的树结构:

$ tree -L 3 ./
./
├── black_scholes
│   ├── black_scholes
│   │   ├── Makefile
│   │   ├── __init__.py
│   │   └── bs.c
│   ├── pyproject.toml
│   └── setup.py
├── README.md
└── bs_test.py

可能相关的问题:

  • 是否有简单的方法将setup.py转换为pyproject.toml
  • Pip错误:需要Microsoft Visual c++ 14.0
  • 如何解决"错误:需要Microsoft Visual c++ 14.0或更高版本"安装Python包时?
  • 'setup.py install is deprecate '每次我在VSCode
  • 中打开终端时都会显示警告

在试图规避所需的Visual StudioC++ Build tools要求上浪费了2天之后,唯一不幸的选择是提交到>7GB下载,以便让我的20行c函数编译并安装在Py3.10上。(遵循这一点。)

使用外部_custom_build.py

下面是有效的文件:

# setup.py
from setuptools import setup, Extension
ext = Extension('bs', sources=['black_scholes/bs.c'])
setup(
name="black_scholes",
version="0.0.1",
description="European Options Pricing Library",
packages=['black_scholes'],
ext_modules=[ext]
)

对于pyproject.toml:

# pyproject.toml
[build-system]
requires = ["setuptools>=61.0", "cython"]
build-backend = "setuptools.build_meta"
[project]
name        = "black_scholes"
description = "European Options Pricing Library"
version     = "0.0.1"
readme      = "README.md"
requires-python = ">=3.7"
authors = [
{ name="Example Author", email="author@example.com" },
]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
keywords = ["quant", "portfolio"]
[project.urls]
"Homepage" = "https://pyquantnews.com/how-to-45x-python-performance-with-c/"
[tool.setuptools]
py-modules = ["_custom_build"]
[tool.setuptools.cmdclass]
build_py = "_custom_build.build_py"

这是使用名为_custom_build.py的外部构建文件,如上面的SO链接所建议的。

# _custom_build.py
from setuptools import Extension
from setuptools.command.build_py import build_py as _build_py
class build_py(_build_py):
def run(self):
self.run_command("build_ext")
return super().run()
def initialize_options(self):
super().initialize_options()
if self.distribution.ext_modules == None:
self.distribution.ext_modules = []
self.distribution.ext_modules.append(
Extension(
"bs",
sources=["black_scholes/bs.c"],
extra_compile_args=["-std=c17", "-lm", "-Wl", "-c", "-fPIC"],
)
)

然而,extra_compile_args似乎完全被忽略了…

如果有人能想出一个替代的解决方案来使用更小的编译器,比如MinGW之类的。

最后的树应该是这样的:

$ tree -L 3
.
├── black_scholes
│   ├── black_scholes
│   │   ├── Makefile
│   │   └── bs.c
│   ├── .gitignore
│   ├── README.md
│   ├── __init__.py
│   ├── _custom_build.py
│   ├── pyproject.toml
│   └── setup.py
└── bs_test.py

使用src构建setup.py&pyproject.toml

更新:2022-11-14

上面的过程是非常混乱的,也给出了不同的结果,这取决于你如何使用pip install。最后,我完全改变了平面文件夹结构,使用基于src的结构。工作项目现在看起来像这样:

# tree -L 3
.
├── docs
├── examples
│   └── fbs_test.py
├── src
│   ├── black_scholes
│   │   └── __init__.py
│   └── lib
│       ├── Makefile
│       └── fbs.c
├── .gitignore
├── LICENSE.md
├── README.md
├── clean.sh
├── pyproject.toml
└── setup.py

和文件的内容如下:

# setup.py
from setuptools import setup, find_packages, Extension
ext = Extension(
name                = 'black_scholes.fbs',          # 'mypackage.mymodule'
sources             = ['src/lib/fbs.c'],            # list of source files (to compile)
include_dirs        = ['src/lib'],                  # list of directories to search for C/C++ header files (in Unix form for portability)
py_limited_api      = True                          # opt-in flag for the usage of Python's limited API <python:c-api/stable>.
)
setup_args = dict(
packages        = find_packages(where="src"),       # list 
package_dir     = {"": "src"},                      # mapping
ext_modules     = [ext],                            # list
scripts         = ["examples/fbs_test.py"]          # list
)
setup(**setup_args)

# pyproject.toml
[build-system]
requires        = ['setuptools>=61.0']                  # 'cython'
build-backend   = 'setuptools.build_meta'   
[project]
name            = 'black_scholes'
# ...
[tool.setuptools]
package-dir = {"" = "src"}
#py-modules = ["_custom_build"]
[tool.setuptools.packages.find]
where = ["src"]

这里非常重要确保包名与src/black_scholes目录名一致。如果不这样做,即使在包已经编译和安装之后,你也会遇到各种各样非常奇怪的运行时错误。

相关内容

  • 没有找到相关文章

最新更新