Learn to Create Libraries for Python with C/C++

Simple and functional!


Learn to Create Libraries for Python with C/C++


In this article we will see: how to create libraries for Python with C++, the process is similar to the post/video we saw on C++ for Lua.

The libraries of several programming languages are written in C and C++, as the performance is much higher than writing in the language itself.

There are a large number of libraries for Python that are written in C++, the most famous are:


Creating a basic Hello World

Let’s create a directory (libpycpp/) and a main.cpp file:

mkdirlibpycpp
cd libpycpp
vim main.cpp

01. Most basic code of all: Prints: Hello World

main.cpp

// 01. Include Python.h header
#include <Python.h>

// 02. Register the signature of your function
// and the logical content of your function
int world(){
   printf("Hello, World!\n");
   return 0;
}

// 03. Handles your function arguments
// and return to Python
static PyObject* world(PyObject* self, PyObject* args){
   return Py_BuildValue("s", world());
}

// 04. Creates an array of static type PyMethodDef
// which stores all your functions
static PyMethodDef hello_methods[] = {
   {"world", world, METH_VARARGS, "Print Hello World."},
   {NULL, NULL, 0, NULL} // Enter the end of the list
   // Python function | your role | arguments(METH_VARARGS = 1) | What does she do
};

// 05. Creates the structure with the name of the module you
// want to use in Python
static struct PyModuleDef hello_module = {
   PyModuleDef_HEAD_INIT, // Informs the base
   "hello", // The name of your library
   NULL, // The name of the documentation
   -1, // The module size, -1 is the maximum size
   hello_methods // The module name with underscore and methods at the end
};

// 06. Similar to the main() function, gateway to Python.
// The return type must be: PyMODINIT_FUNC
// The name must be PyInit_ the name of your lib (void arguments)
PyMODINIT_FUNC PyInit_hello(void){
   return PyModule_Create(&hello_module); // Return PyModule_Create and pointer & the PyModuleDef struct
}

To compile:

g++ -shared -o hello.so -fpic main.cpp -I /usr/include/python3.12 # Enter the version on your system

Using:

vim script.py

import hello

hello.world()

02. Using parameters for function

1. Create a new base function:

int add(int x, int y){
   return x + y;
}

2. Create the return

// Does not necessarily have to be the same name
static PyObject* add(PyObject* self, PyObject* args){
   int a, b;
   // ii = 2 integers
   if(!PyArg_ParseTuple(args, "ii", &a, &b)){
     return NULL;
   }
   // i = returns an integer
   return Py_BuildValue("i", add(a, b));
}

3. Add to array

static PyMethodDef hello_methods[] = {
   {"world", world, METH_VARARGS, "Print Hello World."},
   {"add", add, METH_VARARGS, "Add two number."}, // Add to list
   {NULL, NULL, 0, NULL} // Enter the end of the list
};

Using:

vim script.py

import hello

print(hello.add(3, 6))

numb1 = 36
numb2 = 90

print("The sum is: ", hello.add(numb1, numb2))

python script.py


03. Creating a function that receives string

  1. Let’s call this function echo:
int echo(const char* str){
   printf("%s", str);
   return 0;
}
  1. PyObject function:
static PyObject* echo(PyObject* self, PyObject* args){
   const char* str;
   if(!PyArg_ParseTuple(args, "s", &str)){
     return NULL;
   }
   return Py_BuildValue("s", echo(str));
}
  1. Add to the array:
static PyMethodDef hello_methods[] = {
   {"world", world, METH_VARARGS, "Print Hello World."},
   {"add", add, METH_VARARGS, "Add two number."},
   {"echo", echo, METH_VARARGS, "Print string"}, // HERE
   {NULL, NULL, 0, NULL} // Enter the end of the list
};

Compile and test:

hello.echo("Thanks, this is cool!\n")

I made the library of that code from video that plays MP3 with C++ and created a lib.

If you want to test on your machine, follow the steps:

i1. Copy and create the files (playmp3.hpp and playmp3.cpp) from the playmp3 video post available at: 🎶 How to Play MP3 with C++ 🎻 🎼 Code Music

  1. Create main.cpp and add the code below:
#include <Python.h>
#include "playmp3.hpp"

int mp3(char* song){
  auto p = std::make_unique<PlayMP3>();
  p->music(song);
  p->play();
  return 0;
}

static PyObject* mp3(PyObject* self, PyObject* args){
  char* music;
  if (!PyArg_ParseTuple(args, "s", &music)) {
    return NULL;
  }
  mp3(music);
  return Py_BuildValue("");
}

static PyMethodDef playmp3_methods[] = {
  {"mp3", mp3, METH_VARARGS, "Play MP3"},
  {NULL, NULL, 0, NULL}
};

static struct PyModuleDef playmp3_module = {
  PyModuleDef_HEAD_INIT,
  "playmp3",
  NULL,
  -1,
  playmp3_methods
};

PyMODINIT_FUNC PyInit_playmp3(void) {
  return PyModule_Create(&playmp3_module);
}
  1. Add the libalsa.so path to the environment variable: LD_LIBRARY_PATH:
echo export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(dirname "$(find /usr/lib* -name "libalsa.so" 2>/dev/null)") >> ~/.bashrc
  1. Close and open the terminal or run the command below:
source ~/.bashrc
  1. Compile:
g++ -shared -o playmp3.so -fpic main.cpp playmp3.cpp \
   -I /usr/include/python* \# Change to the path on your system
   -lmpg123 -lao $(find /usr/lib* -name "libalsa.so")
  1. Create a Python file: player.py
import playmp3 as play
play.mp3("music.mp3")

In music.mp3 replace with the song you want to listen to!

Then just run:

python player.py

If you want to use the library directly on your system:

sudo mv playmp3.so /usr/local/lib
echo 'export PYTHONPATH="${PYTHONPATH}:/usr/local/lib"' >> ~/.bashrc
source ~/.bashrc

If you want to use a different output plugin for libao, such as the “oss” (Open Sound System) plugin, use:

export AO_DRIVER=oss
python player.py

Watch the video

The video is in Portuguese, but it is possible to follow it even without audio.

For more information, visit: https://docs.python.org/3/c-api/index.html


python cpp clanguage


Share


YouTube channel

Subscribe


Marcos Oliveira

Marcos Oliveira

Software developer
https://github.com/terroo

Related articles