Search code examples
pythoncythoncythonize

cythonize doesn't recopmile a modified pyx file after second call in one runtime


I need to generate a pyx file several times and run its recompilation and reload corresponding extension into the program in one runtime. Here is a simplified example:

from setuptools import Extension, setup
from Cython.Build import cythonize
import sys

pyxfile = "foo.pyx"

def write_pyx(incval):
    with open(pyxfile, 'w') as f:
        f.write('cpdef int foo(int x):\n  return x+%i' % incval)

def ext_compile():
    oldargv = sys.argv
    sys.argv = ['thisfile.py', 'build_ext', '--inplace']
    setup(
        ext_modules=cythonize(
            [ Extension("example", [pyxfile]) ],
            compiler_directives={'language_level': 2}
        )
    )
    sys.argv = oldargv

write_pyx(1)
ext_compile()

import example
print "foo(1) =", example.foo(1)

write_pyx(10)
ext_compile()

reload(example)
print "foo(1) =", example.foo(1)

However, when executed, despite the changing pyx file, I have only one compilation. This is the output in the console:

Compiling foo.pyx because it changed.
[1/1] Cythonizing foo.pyx
running build_ext
building 'example' extension
gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/artem/.pyenv/versions/2.7.16/include/python2.7 -c foo.c -o build/temp.linux-x86_64-2.7/foo.o
gcc -pthread -shared -L/home/artem/.pyenv/versions/2.7.16/lib build/temp.linux-x86_64-2.7/foo.o -o build/lib.linux-x86_64-2.7/example.so
copying build/lib.linux-x86_64-2.7/example.so -> 
foo(1) = 2
running build_ext
copying build/lib.linux-x86_64-2.7/example.so -> 
foo(1) = 2

Any idea how can I solve this?


Solution

  • I was able to solve this only when each time I use different names for the pyx file and for the extension:

    from setuptools import Extension, setup
    from Cython.Build import cythonize
    import sys
    import importlib
    
    def write_pyx(pyxfile, incval):
        with open(pyxfile, 'w') as f:
            f.write('cpdef int foo(int x):\n  return x+%i' % incval)
    
    def ext_compile(extname, pyxfile):
        oldargv = sys.argv
        sys.argv = ['thisfile.py', 'build_ext', '--inplace']
        setup(
            ext_modules=cythonize(
                [ Extension(extname, [pyxfile]) ],
                compiler_directives={'language_level': 2}
            )
        )
        sys.argv = oldargv
    
    pyxfile = "foo01.pyx"
    extname = "example01"
    write_pyx(pyxfile, 1)
    ext_compile(extname, pyxfile)
    example = importlib.import_module(extname)
    
    print "foo(1) =", example.foo(1)
    
    pyxfile = "foo10.pyx"
    extname = "example10"
    write_pyx(pyxfile, 10)
    ext_compile(extname, pyxfile)
    example = importlib.import_module(extname)
    
    print "foo(1) =", example.foo(1)
    

    Output is:

    Compiling foo01.pyx because it changed.
    [1/1] Cythonizing foo01.pyx
    running build_ext
    building 'example01' extension
    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/artem/.pyenv/versions/2.7.16/include/python2.7 -c foo01.c -o build/temp.linux-x86_64-2.7/foo01.o
    gcc -pthread -shared -L/home/artem/.pyenv/versions/2.7.16/lib build/temp.linux-x86_64-2.7/foo01.o -o build/lib.linux-x86_64-2.7/example01.so
    copying build/lib.linux-x86_64-2.7/example01.so -> 
    foo(1) = 2
    Compiling foo10.pyx because it changed.
    [1/1] Cythonizing foo10.pyx
    running build_ext
    building 'example10' extension
    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/artem/.pyenv/versions/2.7.16/include/python2.7 -c foo10.c -o build/temp.linux-x86_64-2.7/foo10.o
    gcc -pthread -shared -L/home/artem/.pyenv/versions/2.7.16/lib build/temp.linux-x86_64-2.7/foo10.o -o build/lib.linux-x86_64-2.7/example10.so
    copying build/lib.linux-x86_64-2.7/example10.so -> 
    foo(1) = 11