Unfortunately the proposed first answer made by @Roan does not work for me, and the execution fail.
Before to see the second answer made by @Dunes which works for me, I supposed the problem comes from cython, even I do cython3 -3 caller.pyx
(strangely -2
by default), and I followed An Easy Guide to Understanding PyImport_ImportModule in Python, without any use of cython.
I give it in case to not use cython interests someone.
I am on a Pi5 Debian 12 (Bookworm) with Python 3.11
main.c is now :
#include <Python.h>
int main() {
// Initialize the Python interpreter
Py_Initialize();
// Add the current directory to the Python module search path
PyRun_SimpleString("import sys\n"
"sys.path.append('.')\n");
// Import the Module
PyObject* pModule = PyImport_ImportModule("helloworld");
if (pModule == 0)
PyErr_Print();
else {
// Use the Module to access the function
PyObject* pFunc = PyObject_GetAttrString(pModule, "hw");
if (pFunc && PyCallable_Check(pFunc)) {
PyObject_CallFunction(pFunc, "()");
Py_XDECREF(pFunc);
Py_XDECREF(pModule);
}
else
PyErr_Print();
}
// Clean up
Py_Finalize();
return 0;
}
helloworld.py is unchanged, caller.pyx is not relevant and does not need to exist
Compilation and execution :
bruno@raspberrypi:/tmp $ gcc -g -Wall -I/usr/include/python3.11 -o main main.c -lpython3.11
bruno@raspberrypi:/tmp $ ./main
Hello World
bruno@raspberrypi:/tmp $
There is no memory leaks but some reachable allocated memory is still not free (accessible from global vars then) :
bruno@raspberrypi:/tmp $ valgrind --leak-check=full ./main
==31826== Memcheck, a memory error detector
==31826== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==31826== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==31826== Command: ./main
==31826==
Hello World
==31826==
==31826== HEAP SUMMARY:
==31826== in use at exit: 408,136 bytes in 15 blocks
==31826== total heap usage: 1,595 allocs, 1,580 frees, 2,871,796 bytes allocated
==31826==
==31826== LEAK SUMMARY:
==31826== definitely lost: 0 bytes in 0 blocks
==31826== indirectly lost: 0 bytes in 0 blocks
==31826== possibly lost: 0 bytes in 0 blocks
==31826== still reachable: 408,136 bytes in 15 blocks
==31826== suppressed: 0 bytes in 0 blocks
==31826== Reachable blocks (those to which a pointer was found) are not shown.
==31826== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==31826==
==31826== For lists of detected and suppressed errors, rerun with: -s
==31826== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
bruno@raspberrypi:/tmp $
So the second answer works for me, and for information with it I still have no memory leaks but still reachable allocated memory :
bruno@raspberrypi:/tmp $ cython3 -3 caller.pyx
/usr/lib/python3/dist-packages/pythran/tables.py:4530: FutureWarning: In the future `np.bool` will be defined as the corresponding NumPy scalar.
if not hasattr(numpy, method):
/usr/lib/python3/dist-packages/pythran/tables.py:4563: FutureWarning: In the future `np.bytes` will be defined as the corresponding NumPy scalar.
obj = getattr(themodule, elem)
bruno@raspberrypi:/tmp $ gcc -g -Wall -I/usr/include/python3.11 -o main caller.c main.c -lpython3.11
bruno@raspberrypi:/tmp $
bruno@raspberrypi:/tmp $ ./main
Hello World
bruno@raspberrypi:/tmp $
bruno@raspberrypi:/tmp $ valgrind --leak-check=full ./main
==31666== Memcheck, a memory error detector
==31666== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==31666== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==31666== Command: ./main
==31666==
Hello World
==31666==
==31666== HEAP SUMMARY:
==31666== in use at exit: 409,145 bytes in 17 blocks
==31666== total heap usage: 1,598 allocs, 1,581 frees, 2,871,853 bytes allocated
==31666==
==31666== LEAK SUMMARY:
==31666== definitely lost: 0 bytes in 0 blocks
==31666== indirectly lost: 0 bytes in 0 blocks
==31666== possibly lost: 0 bytes in 0 blocks
==31666== still reachable: 409,145 bytes in 17 blocks
==31666== suppressed: 0 bytes in 0 blocks
==31666== Reachable blocks (those to which a pointer was found) are not shown.
==31666== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==31666==
==31666== For lists of detected and suppressed errors, rerun with: -s
==31666== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
bruno@raspberrypi:/tmp $