Le document suivant montre comment créer et utiliser des Dlls sous Linux, il est probable qu'il faille adapter les scripts de compilation sur d'autres versions d'Unix.
L'utilisation des DLLs sous Unix est très semblable à ce qui se fait sous Windows. Sous Unix, l'extension des DLLs est en général .so, et il est courant que le numéro de version soit ajouté derrière l'extension (.so.1, .so.2), un lien symbolique pointant sur la version à utiliser.
Il est possible de lier l'application statiquement ou dynamiquement à la DLL.
Tout comme pour Windows, il faut faire très attention en terme d'interface lorsqu'on décide de la création d'une DLL : Si les prototypes des fonctions ou les structures que l'on passe en argument changent entre 2 versions, cela risque de compromettre le fonctionnement des anciennes applications si cela n'a pas été prévu par le programmeur.
Une solution simple empruntée à Windows peut être de toujours mettre la taille d'une structure en tant que premier membre, et de changer le nom du prototype des fonctions si l'interface change :
// .h (interface de la dll)
// Structure version 1
typedef struct MaStructV1
{
int cb; // Doit être initialisée par l'application
int a; // Quelques membres ...
int b; //
} MaStructV1;
// Structure version 2
typedef struct MaStructV2
{
int cb; // Idem
int a;
int b; // Si l'un des mebre devient obsolète, il faut quand même le conserver
int c; // Nouveau mebre
} MaStructV2;
// Fonction version 1
void maFonction( int a );
// Si le proto change, on change de nom
void maFonction2( int a, int b );
// Prototype avec pointeur
void monAutreFonction( MaStructV2 * pMaStructV2 )
// .c (code de la dll)
void monAutreFonction( MaStructV2 * pMaStructV2 )
{
// On determine la version
if( pMaStructV2->cb == sizeof(MaStructV1) )
{
// C'est une vieille appli V1 qui nous appelle
...
}
else if( pMaStructV2->cb == sizeof(MaStructV2) )
{
// C'est une appli V2 qui nous appelle
...
}
}
Au niveau du code, il n'y a rien de spécial à faire, c'est dans le makefile que l'on indique que le programme a besoin de la DLL.
Pour que le programme fonctionne, il faut mettre à jour la variable d'environnement LD_LIBRARY_PATH qui contient le chemin des DLLs, et ce, même si la DLL est dans le répertoire courant.
# compilation du programme : La seule difference par rapport
# à une compilation classique est que l'on indique le .so
# (libshared.so) au lieu du .o
hellostat: hellostat.o libshared.so
gcc hellostat.o libshared.so -o hellostat
# compilation de la dll
libshared.so: shared.o
gcc -shared -o libshared.so shared.o
# on remarque l'option -fpic
shared.o: shared.cpp
gcc -c -fpic shared.cpp -o shared.o
On utilise l' API dlopen() pour ouvrir la DLL et dlsym() pour aller chercher le pointeur de fonction.
Cette manière de faire est similaire à Windows (utilisation de LoadLibrary() et GetProcAddress()).
// Traitement des erreurs omis pour + de clarete
typedef void (*PFHelloShared)(int );
void *module;
PFHelloShared pfHelloShared;
// ouvre la DLL
module = dlopen("./libshared.so", RTLD_LAZY);
// Recupere un pointeur sur la fonction
pfHelloShared = (PFHelloShared)dlsym(module, "HelloShared");
// Lance la fonction
(*pfHelloShared)(8888);
Dans ce cas, pas besoin de mettre à jour LD_LIBRARY_PATH.