我偶然发现了这个小项目,用于创建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
目录名一致。如果不这样做,即使在包已经编译和安装之后,你也会遇到各种各样非常奇怪的运行时错误。