TCC
https://bellard.org/tcc/Tiny C Compiler est un interpréteur de langage C écrit par Fabrice Bellard.
Il est rapide et sans dépendance exotique genre bison lex yacc qui sont de bons choix pour écrire un compilateur (beaucoup d'applications GNU s'en servent, ce sont des outils qui génèrent le code C pour créer un compilateur), mais Fabrice a tout fait à la main.
Petit et puissant, ce compilateur C peut se compiler sous la forme d'une librairie statique, qu'un exécutable vient embarquer pour exposer certaines de ses fonctions dans un script syntaxe C (et LibC).
Comme Fabrice l'explique dans les documents, voir libtcc.h et libtcc_test.c qui montre comment exposer une fonction, comment appeler une fonction du script depuis le C.
Comme pour tous les autres interpréteurs,
* l'exécutable expose certaines fonctions qui peuvent être invoquées depuis le script;
* et vice-versa l'exécutable peut lui aussi invoquer des fonctions du script.
Pour compiler la lib
sur Linux 64 bits
Télécharger tcc-0.9.24 et décompresser
$ cd tcc-0.9.24Créer config.h
#define TCC_VERSION "0.9.24" // dans la source il y a un config.h windows, on est en ELF donc j'ai mis PE 0 et pas 1, ça marche #define TCC_TARGET_PE 0 #define CONFIG_TCCDIR "."Créer la librairie statique
// pour 32 bits: $ gcc -m32 -Os -fno-strict-aliasing tcc.c -D LIBTCC -c -o libtcc.o $ gcc tcc.c -D LIBTCC -c -o libtcc.o $ ar rcs libtcc.a libtcc.oPuis récupérer libtcc.h et libtcc.a, pas besoin du reste.
Programme qui embarque l'interpréteur TCC
(c'est libtcc_test.c amélioré)#include <stdlib.h> #include <stdio.h> #include "libtcc.h" TCCState *tcc; // Pour appeler ici une fonction du script void triggerScriptCallback(const char*fonc, int a){ int (*func)(int); unsigned long val; tcc_get_symbol(tcc, &val, fonc); func = (void *)val; func(a); } // Fonction exposée void sayHello(int a){ printf("Hello from C function %d\n", a); } // Charge un script char* loadFile(){ FILE * f; long len; char * s; f = fopen ("script.c", "rb"); if (f==NULL) return NULL; fseek (f, 0, SEEK_END); len = ftell (f); rewind (f); s = (char*) malloc (len); if (s == NULL) return NULL; fread (s,1,len,f); fclose (f); return s; } int main(int argc, char **argv) { TCCState *tcc; char* script; // code C tcc = tcc_new(); if (!tcc) { fprintf(stderr, "Could not create tcc state\n"); return 1; } tcc_set_output_type(tcc, TCC_OUTPUT_MEMORY); script = loadFile(); tcc_compile_string(tcc, script); // Exposition de fonctions (pour que le script appelle une fonction C) tcc_add_symbol(tcc, "sayHello", (unsigned long)&sayHello); // ici on peut en mettre d'autres, mais ne pas exposer celle-là! //tcc_add_symbol(tcc, "loadFile", (unsigned long)&loadFile); tcc_relocate(tcc); // Appelle une fonction du script triggerScriptCallback("main"); // en appelle une 2e pour voir si ça marche triggerScriptCallback("onAccept", 404); free(script); tcc_delete(tcc); return 0; }
script.c
Contenu du script interprété:int main(int a) { printf("Script started\n"); sayHello(25); // appelle fonction C return 0; } void onAccept(int sk) { printf("accepted %d\n", sk); }
Compiler un programme en embarquant la librairie statique 32 bits
$ gcc -s -m32 main.c -L. -ltcc -ldl -o test $ ./test Script started Hello from C function 25 accepted 404 data du socket 404 [le message] 11 $
Conclusion
Je m'en sers pour interfacer la librairie pixlib pour modifier des images, c'est vraiment top.Ça servira aussi pour spécifier le comportement de l'application "Tourelle caméra": quand le code sera satisfaisant il pourra éventuellement être compilé, ce qui fera gagner pas mal de temps de développement (pas besoin de recompiler après chaque petite modif).