Search code examples
pythonwindowscythonsetuptoolsdistutils

Cython embed on Windows


I have read How to enable `--embed` with cythonize? and Cython --embed flag in setup.py but this method does not work on Windows. Let's say we have:

# app.py
print("hello")
# build.py
import setuptools   # allows us to avoid calling vcvarsall.bat, see https://stackoverflow.com/a/53172602/
from distutils.core import setup
from Cython.Build import cythonize
from Cython.Compiler import Options
Options.embed = "main"
setup(ext_modules=cythonize(r'app.py', build_dir="release"), script_args=['build'], options={'build': {'build_lib': 'release'}})

Running this build.py script on Python 3.8 for Windows does not produce an app.exe file like it would with the command line command:

cython app.py --embed

Instead, it produces a .pyd file.

How to use cythonize + embed from a Python script, producing a .exe, on Windows?


Solution

  • Solved: in fact the problem did not come from cythonize itself, but from the fact distutils.core.setup(...) is configured to compile+link into a .pyd instead of a .exe.

    Here is the solution:

    from distutils._msvccompiler import MSVCCompiler    # "from distutils.msvccompiler" did not work for me!
    from Cython.Compiler import Options
    Options.embed = "main"
    cythonize(r'src\app.py', build_dir="build")
    
    compiler = MSVCCompiler()
    compiler.compile([r"build\src\app.c"], include_dirs=["C:/Python38/include"])
    compiler.link_executable([r"build\src\app.obj"], "app", libraries=["python38"], library_dirs=["C:/Python38/libs"], output_dir="release", extra_preargs=["/NOIMPLIB", "/NOEXP"])
    

    The .exe will be in the release folder.

    (Note: I also upgraded Cython to the latest version 0.29.30, it might have helped as well)