Easiest way to access C module in Python

bartc bc at freeuk.com
Tue Nov 7 08:11:40 EST 2017


On 07/11/2017 12:14, Lele Gaifax wrote:
> bartc <bc at freeuk.com> writes:
> 
>> But just staying with the "function with no arguments" for the minute (the
>> equivalent of Hello World for this exercise), how would it be done in
>> Cython? Would a working example be simple enough to show in a usenet post?
> 
> fred.c::
> 
>     int fred(void) {
>       return 42;
>     }
> 
> life.pyx::
> 
>     cdef extern:
>         int fred()
> 
>     def life():
>         return fred()
> 
> setup.py::
> 
>     from distutils.core import setup
>     from distutils.extension import Extension
>     from Cython.Build import cythonize
> 
>     setup(
>         ext_modules = cythonize([Extension("life", ["life.pyx", "fred.c"])])
>     )
> 
> $ python setup.py build_ext --inplace

OK, thanks. Although when I get to this bit, my system still says:

17.299999999999997
Traceback (most recent call last):
   File "setup.py", line 1, in <module>
     from distutils.core import setup
  ....

So obviously something is wrong with it, but I'll have to assume it 
normally works.

> Compiling life.pyx because it changed.
> [1/1] Cythonizing life.pyx
> running build_ext
> building 'life' extension
> creating build
> creating build/temp.linux-x86_64-3.6
> x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fdebug-prefix-map=/build/python3.6-5reRaQ/python3.6-3.6.3=. -specs=/usr/share/dpkg/no-pie-compile.specs 
-fstack-protector-strong -Wformat -Werror=format-security -Wdate-time 
-D_FORTIFY_SOURCE=2 -fPIC -I/tmp/ct/include -I/usr/include/python3.6m -c 
life.c -o build/temp.linux-x86_64-3.6/life.o

However, it doesn't look that simple a process, and it seems to solve a 
different problem from the ctypes solution. That one took an EXISTING 
function, already compiled and linked into a binary, and does not need 
the C source nor need to compile it. Often, you will only have the 
binary shared library anyway.

-I/tmp/ct/include -I/usr/include/python3.6m -c fred.c -o 
build/temp.linux-x86_64-3.6/fred.o

OK, compiling fred.c. Is there a dependency on gcc too? This looks more 
like makefile hell. People use languages like Python to get away from 
this stuff.

> x86_64-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -specs=/usr/share/dpkg/no-pie-link.specs -Wl,-z,relro -specs=/usr/share/dpkg/no-pie-link.specs -Wl,-z,relro -g -fdebug-prefix-map=/build/python3.6-5reRaQ/python3.6-3.6.3=. -specs=/usr/share/dpkg/no-pie-compile.specs -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-x86_64-3.6/life.o build/temp.linux-x86_64-3.6/fred.o -o /tmp/ct/life.cpython-36m-x86_64-linux-gnu.so
> $ python -c "import life; print(life.life())"
> 42
> 
> As other said, for a single function accepting no arguments and returning a
> single value Cython may be an heavy tool, but I bet you can imagine more
> complex situations...

In my normal work, I'm calling C functions from interpreted code all the 
time, just not in Python (example below sig).

It's not that complicated. With this Cython solution you have the .c 
(which has to be compiled and linked using this process), you have .pyx, 
whatever that is, you have .py which is not really Python, but has to be 
processed as Cython, and then you have .py which is actual Python, which 
is the code that wanted to call that C function in the first. So simple.

I understand that Cython lets you write Python-like code with special 
annotations that allows it to be compiled to efficient native code (or 
something like that), but that's not what this task is, which is 100% 
Python calling 100% C, with both developed using their normal tools.

-- 
bartc

# in interpreted code, run as normal:

importdll jpeg =
     clang function loadjpeg(string, ref int64, ref int64)ref byte
end

In C:

byte* loadjpeg(char* file, int64* width, int64* height) {...




More information about the Python-list mailing list