Question: I came across this little project for creating a C-compiled version of the Black-Scholes function to be used in python. Although the example code seem to have been published in July this year, it seem that the use setup.py type of build has been deprecated beyond legacy builds. Any compilation fails, first complaining about missing MS C++ 14 compiler (which is not true), then further investigation, seem to indicate that setup.py can no longer be used. Q: How can I convert the setup.py to a valid pyproject.toml file? 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] )  From the somewhat ambiguous website (above), I created the following tree structure. $ tree -L 3 ./ ./ ├── black_scholes │ ├── black_scholes │ │ ├── Makefile │ │ ├── __init__.py │ │ └── bs.c │ ├── pyproject.toml │ └── setup.py ├── README.md └── bs_test.py  Possibly relevant questions:  Is there a simple way to convert setup.py to pyproject.toml Pip error: Microsoft Visual C++ 14.0 is required How to solve "error: Microsoft Visual C++ 14.0 or greater is required" when installing Python packages? 'setup.py install is deprecated' warning shows up every time I open a terminal in VSCode 

Answer: After having wasted 2 days on trying to circumvent the required Visual Studio C++ Build tools requirements, the only unfortunate option that would work, was to submit to the >7GB download in order to get my 20 line C-function to compile and install nicely on Py3.10. (Follow this.) Using an external _custom_build.py Here are the files that worked: # 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] )  Then for the 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"  This is using an external build file called _custom_build.py, as suggested from the SO link above. # _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"], ) )  However, it seem that the extra_compile_args are completely ignored...  It would have been great if someone could come up with an alternative solution to build using smaller compiler, like MinGW or so.  The final tree should look like this: $ 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   Using a src build with setup.py & pyproject.toml UPDATE: 2022-11-14 The above procedure turned out to be very messy and also gave different results depending on how you used pip install. In the end I completely changed the flat folder structure to use a src based structure. The working project now look like this: # 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  and the content of the files are like this: # 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)  and # 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"]  Here it is very important that the package name coincide with the src/black_scholes directory name. If not you will have all sorts of very weird run-time errors even after the package has compiled and installed.