/*
Chargement dynamique d'une bibliothèque
Exemple simple et commenté

Pour compiler test.c :
gcc -rdynamic -o release/test test.c -ldl

Par iri <iri@irizone.net>
*/

#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>

int main (int argc, char ** argv)
{
	/* valeur retournée lors du déchargement de la bibliothèque */
	int res;
	/* handle qui sera associé à la bibliothèque .so si chargement correct */
	void * handle;
	/* erreur "lisible" si le chargement de la bibliothèque est foireux */
	char * erreur;
	/* type retournée par le symbôle recherché */
	int (* fun)(int);

	
	/* chargement de la bibliothèque, via 'dlopen' (fonction POSIX)
	- le path, absolue (dans ce cas, il commence par un slash /) ou relatif (dans
	ce cas,  le chemin doit être connu du PATH)
	- un flag (ou une combinaison) :
		hardload.c utilise la combinaison RTLD_GLOBAL|RTLD_NOW :
			- RTLD_GLOBAL : les références externes seront résolues avec toutes 
			les bibliothèques et dépendances ouvertes auparavant (i.e. avant
			l'appel de dlopen)
			- RTLD_NOW : la résolution de tous les symbôles indéfinis seront fait
			avant le retour de dlopen. Donc si cette résolution échoue, le chargement
			échoue également */
	handle = dlopen ("/home/iri/Works/devscol/scol-x11-v45/libtest-x11-v45/release/libtest.so", RTLD_GLOBAL|RTLD_NOW);
	
	/* Si dlopen renvoie NULL(non-zéro plus exactement), c'est que le chargement
	a échoué. On affiche donc l'erreur sur la sortie standard et on quitte le
	programme */
	if (! handle)
	{
        printf ("%s", "\ndlopen\n");
        fputs (dlerror (), stderr);
        printf ("%s", "\ndlopen\n");
        exit(EXIT_FAILURE);
    }
    
    /* dlerror contient la dernière erreur rencontrée, un second appel retournera
    toujours NULL. C'est ce qu'on fait ici, pour la "vider" */
    dlerror();
    
    /* sortie de confirmation */
    printf ("ok, bibliotheque chargée !");
    
    /* on recherche le symbôle nommé "test" dans la bibliothèque précédemment
    chargée.
    Si celui-ci est trouvé, fun contiendra son adresse mémoire, sinon dlerror
    sera non-NULL (on l'a purgé juste avant) et contiendra le retour erreur */
    fun = dlsym (handle, "test");
    if ((erreur = dlerror()) != NULL)  
    {
        printf ("%s", "\ndlsym\n");
        printf ("%s0", erreur);
        printf ("%s", "\ndlsym\n");
        exit (EXIT_FAILURE);
    }
    
    /* traitement avec une fonction chargée de la bibliothèque  */
    printf ("\nresultat : %d\n", (*fun)(5));
    
    /* on fermeet on décharge la bibliothèque (si plus rien n'y fait encore référence) */
    res = dlclose(handle);
    if (res != 0)
    	printf("dlclose : %d\n", res);
    exit (EXIT_SUCCESS);
}

/*
Code de la bibliothèque :

int test (int t)
{
	return t*2;
}
*/



    


