Far from a c expert but for me using ubuntu, the following works:

main.c:

#include "foo_api.h"
#include <stdio.h>


int main(int argc, char *argv[]) {
     Py_Initialize();
     initfoo();
     import_foo();
     double arr[5] = {1,2,3,4,5};
     int i = 0;
     foo(arr);
     for(i = 0; i < 5; i++)
    {
      printf("%f\n", arr[i]);
    }
     Py_Finalize();
     return 0;
}

foo.pyx:

cdef public api  foo(double* x):
   x[0] = 0.0

From the same directory:

$ cython foo.pyx 

Then:

$ cc -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7   -o foo  *.c -lpython2.7 

Then just run.

$ ./foo
0.000000
2.000000
3.000000
4.000000
5.000000

I used pkg-config --cflags python to get the flags:

 $ pkg-config --cflags python
-I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7 

Without calling Py_Initialize (Initialize the Python interpreter. In an application embedding Python, this should be called before using any other Python/C API functions;), you will get:

Fatal Python error: PyThreadState_Get: no current thread
Aborted (core dumped)

Without initfoo() or import_foo() you get a:

 Segmentation fault (core dumped)

If you don't call Py_Finalize:

Py_Initialize a no-op when called for a second time (without calling Py_Finalize() first).

To get the delorean example from the docs to run:

main.py:

#include "delorean_api.h"
#include <stdio.h>
Vehicle car;


int main(int argc, char *argv[]) {
     Py_Initialize();
     initdelorean();
     import_delorean();
     car.speed = atoi(argv[1]);
     car.power = atof(argv[2]);
     activate(&car);
     Py_Finalize();
     return 0;
}

delorean.pyx:

ctypedef public struct Vehicle:
    int speed
    float power

cdef api void activate(Vehicle *v):
    if v.speed >= 88 and v.power >= 1.21:
        print "Time travel achieved"
    else:
        print("Sorry Marty")

The procedure is the same, the only change was I had to use ctypedef with the Vehicle struct or else in main or use I had t use struct Vehicle car; in main:

$ cython delorean.pyx
$ cc  -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7   -o delorean  *.c -lpython2.7  
$ ./delorean 1 1
Sorry Marty
$ ./delorean 100 2
Time travel achieved

You can also get it to work without using Py_Initialize etc...

In foo.pyx you just need to make the function public:

cdef public  foo(double* x):
   x[0] = 0.0

I added #include <python2.7/Python.h> just imported foo.hin main.c and removed Py_Initialize(); etc. Just importing python.h would not work for me but that may not be the case for everyone.

#include <python2.7/Python.h>
#include "foo.h"
#include <stdio.h>


int main(int argc, char *argv[]) {
     double arr[5] = {1,2,3,4,5};
     int i = 0;
     foo(arr);
     for(i = 0; i < 5; i++)
    {
      printf("%f\n", arr[i]);
    }

     return 0;
}

Compiling was the same:

$ cython foo.pyx 
$ cc -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7   -o foo  *.c -lpython2.7 
$ ./foo
0.000000
2.000000
3.000000
4.000000
5.000000

If you are using the api version then just include the api header or vice versa as per the docs However, note that you should include either modulename.h or modulename_api.h in a given C file, not both, otherwise you may get conflicting dual definitions.

To do the same with the delorean example I had to use libc.stdio to print the strings to avoid a segmentation fault:

from libc.stdio cimport printf

ctypedef public  struct Vehicle:
    int speed
    float power

cdef public void activate(Vehicle *v):
    if v.speed >= 88 and v.power >= 1.21:
        printf("Time travel achieved\n")
    else:
        printf("Sorry Marty\n")

main:

#include <python2.7/Python.h>
#include <stdio.h>
#include "delorean.h"

Vehicle car;


int main(int argc, char *argv[]) {
     car.speed = atoi(argv[1]);
     car.power = atof(argv[2]);
     activate(&car);
     return 0;
}

It might make more sense to return the values:

ctypedef public  struct Vehicle:
    int speed
    float power

cdef public  char* activate(Vehicle *v):
    if v.speed >= 88 and v.power >= 1.21:
        return  "Time travel achieved"
    return "Sorry Marty"

main:

#include <python2.7/Python.h>
#include <stdio.h>
#include "delorean.h"

Vehicle car;

int main(int argc, char *argv[]) {
     car.speed = atoi(argv[1]);
     car.power = atof(argv[2]);
     printf("%s\n",activate(&car));
     return 0;
}
Answer from Padraic Cunningham on Stack Overflow
🌐
Cython
cython.readthedocs.io › en › latest › src › tutorial › cython_tutorial.html
Basic Tutorial — Cython 3.3.0a0 documentation
The Cython compiler will convert it into C code which makes equivalent calls to the Python/C API. But Cython is much more than that, because parameters and variables can be declared to have C data types. Code which manipulates Python values and C values can be freely intermixed, with conversions ...
🌐
GitHub
github.com › cython › cython
GitHub - cython/cython: The most widely used Python to C compiler · GitHub
This makes Cython the ideal language for wrapping external C libraries, and for fast C modules that speed up the execution of Python code. ... Cython has more than 70 million downloads per month on PyPI. You can support the Cython project via Github Sponsors or Tidelift. If you already have a C compiler, just run following command: ... The original Pyrex program, which Cython is based on, was licensed "free of restrictions" (see below).
Starred by 10.7K users
Forked by 1.6K users
Languages   Cython 51.5% | Python 41.9% | C 6.3% | C++ 0.2% | Shell 0.1% | Starlark 0.0%
🌐
GitHub
gist.github.com › vi4hu › a1aae1a6d209705a14bca2b7c4c7625e
Convert and Compile python in c via cython · GitHub
use cython to convert .pyx to .c · compile .c · Test run · example python file: script.py · you can copy or rename both i am copying · cp script.py script.pyx · cython script.pyx --embed · gcc -Os -I /usr/include/python3.8 -o script script.c -lpython3.8 -lpthread -lm -lutil -ldl · ./script · and done. Sign up for free to join this conversation on GitHub.
Top answer
1 of 1
15

Far from a c expert but for me using ubuntu, the following works:

main.c:

#include "foo_api.h"
#include <stdio.h>


int main(int argc, char *argv[]) {
     Py_Initialize();
     initfoo();
     import_foo();
     double arr[5] = {1,2,3,4,5};
     int i = 0;
     foo(arr);
     for(i = 0; i < 5; i++)
    {
      printf("%f\n", arr[i]);
    }
     Py_Finalize();
     return 0;
}

foo.pyx:

cdef public api  foo(double* x):
   x[0] = 0.0

From the same directory:

$ cython foo.pyx 

Then:

$ cc -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7   -o foo  *.c -lpython2.7 

Then just run.

$ ./foo
0.000000
2.000000
3.000000
4.000000
5.000000

I used pkg-config --cflags python to get the flags:

 $ pkg-config --cflags python
-I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7 

Without calling Py_Initialize (Initialize the Python interpreter. In an application embedding Python, this should be called before using any other Python/C API functions;), you will get:

Fatal Python error: PyThreadState_Get: no current thread
Aborted (core dumped)

Without initfoo() or import_foo() you get a:

 Segmentation fault (core dumped)

If you don't call Py_Finalize:

Py_Initialize a no-op when called for a second time (without calling Py_Finalize() first).

To get the delorean example from the docs to run:

main.py:

#include "delorean_api.h"
#include <stdio.h>
Vehicle car;


int main(int argc, char *argv[]) {
     Py_Initialize();
     initdelorean();
     import_delorean();
     car.speed = atoi(argv[1]);
     car.power = atof(argv[2]);
     activate(&car);
     Py_Finalize();
     return 0;
}

delorean.pyx:

ctypedef public struct Vehicle:
    int speed
    float power

cdef api void activate(Vehicle *v):
    if v.speed >= 88 and v.power >= 1.21:
        print "Time travel achieved"
    else:
        print("Sorry Marty")

The procedure is the same, the only change was I had to use ctypedef with the Vehicle struct or else in main or use I had t use struct Vehicle car; in main:

$ cython delorean.pyx
$ cc  -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7   -o delorean  *.c -lpython2.7  
$ ./delorean 1 1
Sorry Marty
$ ./delorean 100 2
Time travel achieved

You can also get it to work without using Py_Initialize etc...

In foo.pyx you just need to make the function public:

cdef public  foo(double* x):
   x[0] = 0.0

I added #include <python2.7/Python.h> just imported foo.hin main.c and removed Py_Initialize(); etc. Just importing python.h would not work for me but that may not be the case for everyone.

#include <python2.7/Python.h>
#include "foo.h"
#include <stdio.h>


int main(int argc, char *argv[]) {
     double arr[5] = {1,2,3,4,5};
     int i = 0;
     foo(arr);
     for(i = 0; i < 5; i++)
    {
      printf("%f\n", arr[i]);
    }

     return 0;
}

Compiling was the same:

$ cython foo.pyx 
$ cc -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7   -o foo  *.c -lpython2.7 
$ ./foo
0.000000
2.000000
3.000000
4.000000
5.000000

If you are using the api version then just include the api header or vice versa as per the docs However, note that you should include either modulename.h or modulename_api.h in a given C file, not both, otherwise you may get conflicting dual definitions.

To do the same with the delorean example I had to use libc.stdio to print the strings to avoid a segmentation fault:

from libc.stdio cimport printf

ctypedef public  struct Vehicle:
    int speed
    float power

cdef public void activate(Vehicle *v):
    if v.speed >= 88 and v.power >= 1.21:
        printf("Time travel achieved\n")
    else:
        printf("Sorry Marty\n")

main:

#include <python2.7/Python.h>
#include <stdio.h>
#include "delorean.h"

Vehicle car;


int main(int argc, char *argv[]) {
     car.speed = atoi(argv[1]);
     car.power = atof(argv[2]);
     activate(&car);
     return 0;
}

It might make more sense to return the values:

ctypedef public  struct Vehicle:
    int speed
    float power

cdef public  char* activate(Vehicle *v):
    if v.speed >= 88 and v.power >= 1.21:
        return  "Time travel achieved"
    return "Sorry Marty"

main:

#include <python2.7/Python.h>
#include <stdio.h>
#include "delorean.h"

Vehicle car;

int main(int argc, char *argv[]) {
     car.speed = atoi(argv[1]);
     car.power = atof(argv[2]);
     printf("%s\n",activate(&car));
     return 0;
}
🌐
Opensource.com
opensource.com › article › 21 › 4 › cython
Optimize your Python code with C | Opensource.com
April 26, 2021 - Cython's cythonize module transforms hello.pyx into a hello.c file and a .so library. The C code is 2,648 lines, so it's quite a lot more text than the single line of hello.pyx source. The .so library is also over 2,000 times larger than its source (54,000 compared to 20 bytes). Then again, Python is required to run a single Python script, so there's a lot of code propping up that single-line hello.pyx file.
🌐
Machine Learning Plus
machinelearningplus.com › blog › how to convert python code to cython (and speed up 100x)?
How to convert Python code to Cython (and speed up 100x)? | machinelearningplus
October 17, 2023 - Using Cython, you can speed up existing Python code by an order of 100x or more. This is possible because Cython converts some of the Python code to C by doing some basic code changes.
🌐
Quora
quora.com › I-want-to-convert-my-Python-code-to-C-with-Cython-and-then-compile-it-to-exe-for-Windows-64-bit-How-can-I-do-that
I want to convert my Python code to C with Cython and then compile it to .exe for Windows 64 bit. How can I do that? - Quora
Answer: You can follow the below steps - 1. As Cython can accept only valid python source file so first make sure that your python code is working without any error/issue. 2. Give a file name extension as .pyx instead of .py extension. 3. Then you can write a Setup.py file for Cython. A basic cy...
Find elsewhere
🌐
InfoWorld
infoworld.com › home › software development › programming languages › python
What is Cython? Python at the speed of C | InfoWorld
June 1, 2023 - Cython lets you talk to the underlying libraries directly, without Python in the way. (C++ libraries are also supported.) If you use Python objects, they’re memory-managed and garbage-collected the same as in regular Python. If you want to, you can also create and manage your own C-level structures, and use malloc/free ...
🌐
YouTube
youtube.com › watch
Cython 3.0: Compiling Python to C, the next generation - YouTube
The Cython project compiles Python to C -- not just to make code faster, but also to wrap external C libraries easily, and make it easy to write C extensions...
Published   July 25, 2023
🌐
GitHub
hplgit.github.io › primer.html › doc › pub › cython › cython-readable.html
Migrating Python to compiled code
August 13, 2020 - Pure Python code for Monte Carlo simulation · The computational problem · A scalar Python implementation · A vectorized Python implementation · Migrating scalar Python code to Cython · A plain Cython implementation · A better Cython implementation · Migrating code to C ·
🌐
Duke University
people.duke.edu › ~ccc14 › sta-663 › FromPythonToC.html
Converting Python Code to C for speed — Computational Statistics in Python 0.1 documentation
Using Cython · Benchmark · Using functions from various compiled languages in Python · C · C++ Fortran · Benchmarking · Wrapping a function from a C library for use in Python · Wrapping functions from C++ library for use in Pyton · Julia and Python · Defining a function in Julia · Using it in Python · Using Python libraries in Julia · Converting Python Code to C for speed ·
Top answer
1 of 4
8

Check the documentation. It's not enough to do gcc x.c -o x.

This page explains compilation: http://docs.cython.org/src/reference/compilation.html

There's a lot more to it, but a direct answer is:

Compiling your .c files will vary depending on your operating system. Python documentation for writing extension modules should have some details for your system. Here we give an example on a Linux system:

$ gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I/usr/include/python2.7 -o yourmod.so yourmod.c

Of course in your situation it's going to be something closer to -I/usr/include/python3.4, or even $(pkg-config --libs --cflags python3). And you're not building with -shared, because you want an executable.

Shortest "this has to work" set of commands is:

cython3 --embed greet.py -o greet.c
gcc $(pkg-config --libs --cflags python3) greet.c -o greet

You need to install pkg-config if it's missing.

2 of 4
0

As @viraptor's answer shows you and as per my comment, your main problem is that you need to tell your C compiler (e.g. gcc) where to find the python headers required (pyconfig.h and Python.h). To do this, you need to pass a -I option to gcc.

The other answer suggests using pkg-config to add this to your command line. However, like you, with Ubuntu 14.04, cython3 and python3-dev installs, using this method leads the compiled program to exit with a segmentation fault for me.

So, I suggest you go back to basics. After

cython greet.py -o greet.c

Run the following command. It assumes that Python.h and friends are in the standard place (i.e. you've done a standard install of python3-dev)

gcc -I/usr/include/python3.4m -o greet greet.c -lpython3.4m

If that doesn't work - use find / -iname Python.h to find the location of the necessary files and alter the -I path accordingly.

In time, when you want to use cython on more complex programs, such as those that link to other C libraries, you'll need to learn about the other options you need to pass to gcc to get it to compile and link correctly. To get you going, though, the above should work (tested on Ubuntu 14.04 as per your spec)

P.S. I'm not sure why the pkg-config suggestion doesn't work - but for me it seems to add in an extra path to -I which breaks things.

🌐
Python Programming
pythonprogramming.net › introduction-and-basics-cython-tutorial
Optimizing with Cython Introduction - Cython Tutorial
One option we have to analyze areas where we could attempt to use cython is via cythonize's html output. For example, let's take our original Python script, convert to .pyx: #furthertesting.pyx def test(x): y = 0 for i in range(x): y += i return y ... Yellow lines hint at Python interaction. Click on a line that starts with a "+" to see the C code that Cython generated for it.
🌐
CodeConvert AI
codeconvert.ai › python-to-c-converter
Free Python to C Converter — AI Code Translation | CodeConvert AI
Yes. You can convert Python to C for free without creating an account for up to 2 conversions per day.
🌐
FutureLearn
futurelearn.com › home › blog
Interfacing C code with Cython
October 25, 2022 - In this article we discuss how external code written in C can be utilized from Python code with the help of Cython.
🌐
DigitalOcean
digitalocean.com › community › tutorials › boosting-python-scripts-cython
Boosting Python Scripts With Cython | DigitalOcean
May 2, 2025 - In this article, we’ll explore how you can use Cython to supercharge your Python code by converting it into fast, compiled C code—without leaving the comfort of Python syntax.
🌐
GeeksforGeeks
geeksforgeeks.org › cython-to-wrap-existing-c-code
Cython to Wrap Existing C Code | GeeksforGeeks
March 29, 2019 - Easily tuning of readable Python code into plain C performance by adding static type declarations. Use of combined source code level debugging to find bugs in given Python, Cython and C code.
🌐
Medium
medium.com › @v1per › cython-use-c-c-functions-in-python-fcb91dae8533
Cython — use C/C++ functions in Python | by Himanshu Das | Medium
September 17, 2023 - This is Cython’s official github repo. According to the readme: Cython is a Python compiler that makes writing C extensions for Python as easy as Python itself.