Salut, et bienvenue sur le forum.
Le sujet a déjà été traité à maintes reprises, mais bon...
Ce qu'il faut, c'est être en mesure de faire la distinction entre l'étape de compilation de la dll elle-même et celle de l'utilisation de la dll.
Le plus simple pour y arriver est d'utiliser les directives conditionnelles du préprocesseur préprocesseur.
L'idée générale est de définir un terme (considéré comme unique) qui prendra une valeur particulière au moment de la compilation de la dll et une valeur différente lorsqu'on utilisera cette dll.
Nous nous aiderons en cela de la possibilité qui nous est offerte de définir un "token" directement dans l'instruction de compilation ( sous Gcc, cette possibilité nous est offerte en rajoutant un "flag" -DUN_TERME_PARTICULIER)
Nous veillerons également à ce que ce "UN_TERME_PARTICULIER" soit aussi unique que possible de manière à éviter les mauvaises compréhensions de la part du compilateur et donc le risque qu'il croie que l'on est occupé à compiler la dll alors que nous sommes en fait occupés à... vouloir l'utiliser.
Comme "token" à définir dans l'instruction de compilation, il est courent de choisir un terme proche de BUILD_MY_DLL dans lequel nous remplacerions MY_DLL par... le nom de la dll à créer.
La compilation des différents fichiers d'implémentation de la dll se ferait donc avec une commande proche de
gcc -c monfichier.c -DBUILD_MY_DLL -o monfichier.o
Maintenant que nous avons à peu pres fait le tour de la manière de préciser au compilateur que nous compilons la dll, nous pouvons nous attaquer au fichier qui permettra de choisir entre l'exportation (qui doit avoir lieu lorsque l'on compile la dll) et l'importation (qui doit avoir lieu lorsque l'on utilise la dll).
Comme il est souvent nécessaire d'avoir plusieurs fichiers d'implémentation, le plus facile est de mettre l'ensemble du mécanisme permettant le choix dans un fichier d'en-tête séparé, qu'il nous "suffira" d'inclure dans les différents fichiers.
nous pouvons décider d'appeler ce fichier, par exemple config_dll.h et il prend une forme proche de
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #ifndef CONFIG_DLL_H // le garde anti inclusion multiple
#define CONFIG_DLL_H
/* si le symbole existe, c'est que nous compilons la dll... nous devons
* donc exporter les différents types et fonctions
* sinon, c'est que nous utilisons la dll, et nous devons donc importer
* les différents types et fonctions
* le terme choisi pour prendre la valeur adéquate pourrait etre
* MY_DLL_APY dans lequel on remplacerait MY_DLL par le nom de la dll
* en cours de compilation ou d'utilisation
*/
#if defined(BUILD_MY_DLL)
#define MY_DLL_API __declspec(dllexport)
#else
#define MY_DLL_API __declspec(dllimport)
#endif //fin du test conditionnel
#endif //fin du garde anti inclusion multiple |
Il "suffira" ensuite d'inclure ce fichier d'en-tête dans tous les fichiers où l'on retrouve des symboles devant être exportés, comme par exemple
fichier1.h
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include "config_dll.h"
#ifndef FICHIER1_H
#define FICHIER1_H
/* L'idéal est de présenter les symboles à exportés sous une forme compatible
* avec le C
*/
extern "C"
{
/* la déclaration d'une fonction devant être exportée */
void MY_DLL_API foo(/* paramètres éventuels */);
}
#endif |
fichier1.cpp
1 2 3 4 5 6 7 8 9 10 11
| /* config_dll.h est inclus "d'office" lorsque l'on inclu fichier1.h grace
* au jeu des inclusions en cascades
*/
#include "fichier1.h"
externe "C"
{
void MY_DLL_API foo(/* paramètres éventuels */)
{
/* ce qui doit être fait */
}
} |
Partager