Methods for Python to Call C/C++ Programs
Recently, while debugging, I encountered a situation where Python was running very slowly, so I researched methods to embed C++ programs in Python. I am documenting this for future reference.
Generally, calling C/C++ programs from Python can be divided into three steps:
- 1. Write the C/C++ implementation program. 2. Compile the C/C++ program into a dynamic library. 3. Call the compiled library in Python. There are some differences to note when Python calls C/C++ programs.
1. Python Calls C Functions
Calling C language programs from Python is relatively simple. Compile the C language program and then use the ctypes module in Python to call it.
C Language Source File: called_c.c
// Compilation command gcc -o libpycall.so -shared -fPIC called_c.c
#include<stdio.h>
int foo(int a, int b){<!-- -->
printf("a:%d, b:%d.", &a, &b);
return 0;
}
Enter the following in the command line or terminal:
gcc -o libpycall.so -shared -fPIC called_c.c
This generates the libpycall.so dynamic library file, after which you can call the foo function in Python.Python File: py_call_c.py
import ctypes
dll = ctypes.cdll.LoadLibrary
lib = dll('./libpycall.so') // Path to the library file just generated
lib.foo(1, 3)
The output of running py_call_c.py is:
a:1, b:3
2. Python Calls C++ Classes
Since C++ supports function overloading, when compiling with g++ in C++ mode, the compiler adds extra information to the function names, making it difficult for the ctypes module to find the functions generated by g++. Therefore, to allow g++ to compile in a C language manner so that the function names can be found, you need to wrap the code with the extern keyword.
C++ Source File: cpp_called.cpp
// Python calls C++ (class) dynamic link library
#include <iostream>
using namespace std;
class TestLib
{<!-- -->
public:
void display();
void display(int a);
};
void TestLib::display() {<!-- -->
cout<<"First display"<<endl;
}
void TestLib::display(int a) {<!-- -->
cout<<"Second display:"<<a<<endl;
}
extern "C" {<!-- -->
TestLib obj;
void display() {<!-- -->
obj.display();
}
void display_int(int a) {<!-- -->
obj.display(a);
}
}
Enter the compilation command in the command line or terminal:
g++ -o libpycallcpp.so -shared -fPIC cpp_called.cpp
Explanation of compilation parameters: -fPIC: generates position-independent code suitable for dynamic linking; -L path: indicates to search for library files in the path directory, e.g., -L. indicates the current directory; -I path: indicates to search for header files in the path directory; -o file: specifies the output file as file; -shared: generates a shared library file;
This generates libpycallcpp.so, which can be called in Python.Python File: py_call_c.py
import ctypes
dll = ctypes.cdll.LoadLibrary
lib = dll('./libpycallcpp.so') // Path to the library file just generated
lib.display()
lib.display_int(0)
The output is:
First display
Second display:0
OK, basic functionality is implemented, and advanced calls will be filled in later.