Cela ne compile pas Python en code machine. Mais permet de créer une bibliothèque partagée pour appeler du code Python.
Si ce que vous recherchez est un moyen simple d'exécuter du code Python à partir de C sans vous fier à des éléments execp. Vous pouvez générer une bibliothèque partagée à partir de code python encapsulé avec quelques appels à l' API d'intégration Python . Eh bien, l'application est une bibliothèque partagée, un .so que vous pouvez utiliser dans de nombreuses autres bibliothèques / applications.
Voici un exemple simple qui crée une bibliothèque partagée, que vous pouvez lier avec un programme C. La bibliothèque partagée exécute le code Python.
Le fichier python qui sera exécuté est pythoncalledfromc.py
:
# -*- encoding:utf-8 -*-
# this file must be named "pythoncalledfrom.py"
def main(string): # args must a string
print "python is called from c"
print "string sent by «c» code is:"
print string
print "end of «c» code input"
return 0xc0c4 # return something
Vous pouvez l'essayer avec python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO')
. Il produira:
python is called from c
string sent by «c» code is:
HELLO
end of «c» code input
La bibliothèque partagée sera définie par ce qui suit callpython.h
:
#ifndef CALL_PYTHON
#define CALL_PYTHON
void callpython_init(void);
int callpython(char ** arguments);
void callpython_finalize(void);
#endif
L'associé callpython.c
est:
// gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <python2.7/Python.h>
#include "callpython.h"
#define PYTHON_EXEC_STRING_LENGTH 52
#define PYTHON_EXEC_STRING "import pythoncalledfromc; pythoncalledfromc.main(\"%s\")"
void callpython_init(void) {
Py_Initialize();
}
int callpython(char ** arguments) {
int arguments_string_size = (int) strlen(*arguments);
char * python_script_to_execute = malloc(arguments_string_size + PYTHON_EXEC_STRING_LENGTH);
PyObject *__main__, *locals;
PyObject * result = NULL;
if (python_script_to_execute == NULL)
return -1;
__main__ = PyImport_AddModule("__main__");
if (__main__ == NULL)
return -1;
locals = PyModule_GetDict(__main__);
sprintf(python_script_to_execute, PYTHON_EXEC_STRING, *arguments);
result = PyRun_String(python_script_to_execute, Py_file_input, locals, locals);
if(result == NULL)
return -1;
return 0;
}
void callpython_finalize(void) {
Py_Finalize();
}
Vous pouvez le compiler avec la commande suivante:
gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so
Créez un fichier nommé callpythonfromc.c
qui contient les éléments suivants:
#include "callpython.h"
int main(void) {
char * example = "HELLO";
callpython_init();
callpython(&example);
callpython_finalize();
return 0;
}
Compilez-le et exécutez:
gcc callpythonfromc.c callpython.so -o callpythonfromc
PYTHONPATH=`pwd` LD_LIBRARY_PATH=`pwd` ./callpythonfromc
Ceci est un exemple très basique. Cela peut fonctionner, mais selon la bibliothèque, il peut être encore difficile de sérialiser les structures de données C vers Python et de Python vers C.Les choses peuvent être quelque peu automatisées ...
Nuitka pourrait être utile.
Il y a aussi numba mais ils ne visent pas tous les deux à faire exactement ce que vous voulez. La génération d'un en-tête C à partir de code Python est possible, mais uniquement si vous spécifiez comment convertir les types Python en types C ou si vous pouvez déduire ces informations. Voir python astroid pour un analyseur Python ast.