1

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?

Artem
  • 53
  • 4
  • 1
    Even if it would compile, reload would still not work as you expect, see for example: https://stackoverflow.com/a/55172547/5769463 – ead Mar 29 '20 at 15:24

1 Answers1

0

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
Artem
  • 53
  • 4