Création de greffon (plugin) en C

Portrait de trax

Pré-requis

  • Base en C
  • Compilation d'une librairie dynamique (voir tutoriel librairie C).
  • Un cerveau, un pc, un compilateur C, un pot de cacahuètes...

Pourquoi ?

La capacité à charger des modules externes pour un programme peut être utile dans le sens ou elle permet :

  • D'obtenir un exécutable plus léger
  • De permettre une évolutivité par l'ajout de fonctionnalités
  • De permettre une collaboration plus facile au projet (l'ajoute d'un plugin est souvent plus simple que de modifier le code source directement)
  • distribution de fonctionnalités supplémentaire simple

Le principe

Nous devons placer le code de notre greffon dans un fichier à part. Pour cela nous utiliserons des librairies dynamiques (.so sous Linux ou .dll sous windows). Le logiciel ne peut connaître à priori les fonctionnalités du module, il doit alors faire de l'instrospection sur la librairie pour la découvrir.

En action

Pour charger la librairie lors de l'exécution de notre programme nous utiliserons a fonction dlopen(). Pour charger une fonction de la lib, nous utiliserons dlsym() et dlclose() pour la fermer.

Un peu comme dans tous les langages de programmation, nous devons avoir une fonction référence pour entrer dans notre librairie. Libre a nous de l'appeler comme bon nous semble. Mais tous les autres greffons devrons avoir la même fonction, avec la même structure. Cette fonction aura pour rôle de présenter la librairie a notre programme et entre autre lui lister les fonctions présentes.

#include <dlfcn.h>		/* dlopen dlsyms dlclose */
#include <stdio.h>
#include <stdlib.h>
 
#include <trax.h>		/* include de la librairie */
 
typedef int fonc(int);
 
int main(){
	void *lib;
	fonc *myFonc;
	if((lib = dlopen("libtrax.so", RTLD_LAZY)) == NULL){ /* charge la librairie */
		fprintf(stderr, "Impossible de charger le librairie\n");
		return -1;
	}
 
	if ((myFonc = dlsym(lib, "test")) == NULL){ /* charge la fonction "test" de la librairie */
		fprintf(stderr, "Impossible de charger la fonction d'initialisation\n");
		return -1;
	}
	myFonc(42); /* utilise la fonction test de la librairie*/
 
	printf("%d\n",test(42));
	dlclose(lib);
	return 0;
}