Création d'une bibliothèque portable Pour linux et windows

gcc (GCC) 4.7.2

Bonjour,

je crée une bibliothèque partagée qui compilera sur linux et une dll qui compilera sur windows en utilisant le même code source. Je crée donc une bibliothèque portable Pour linux et windows.

dans mon fichier d'en-tête pour la Bibliothèque est ce module.h

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#define LIB_INTERFACE(type) EXTERN_C __declspec(dllexport) type
#else
#define LIB_INTERFACE(type) type
#endif

LIB_INTERFACE(int) module_init();

#ifdef __cplusplus
}
#endif

dans la source j'ai le module suivant.c

#include "module.h"

LIB_INTERFACE(int) module_init()
{
    /* do something useful
    return 0;
}

et dans mon application d'essai qui reliera et utilisera ce module.j'ai donc ceci:

#include "module.h"

int main(void)
{
    if(module_init() != 0) {
    return -1;
    }
    return 0;
}

1) est-ce que ce que j'ai fait ci-dessus est-ce une implémentation correcte de la création d'une bibliothèque portable Pour linux et windows?

2) je me demande juste comme j'ai enveloppé les fonctions dans extern "C" pour que cette bibliothèque puisse être appelée à partir d'un programme qui a été compilé en C++. Est-ce que j'ai encore besoin de ce EXTERN_C dans ce qui suit:

#define LIB_INTERFACE(type) EXTERN_C __declspec(dllexport) type

3) Qu'est-ce que le but du EXTERN_C ?

merci Beaucoup à l'avance,

26
demandé sur user2284570 2013-10-17 09:29:17

5 réponses

C'est une façon typique d'exporter une API DLL pour Windows et encore soutenir Linux:

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#  ifdef MODULE_API_EXPORTS
#    define MODULE_API __declspec(dllexport)
#  else
#    define MODULE_API __declspec(dllimport)
#  endif
#else
#  define MODULE_API
#endif

MODULE_API int module_init();

#ifdef __cplusplus
}
#endif

dans la DLL source:

#define MODULE_API_EXPORTS
#include "module.h"

MODULE_API int module_init()
{
    /* do something useful */
    return 0;
}

Votre source d'application est correcte.

en utilisant le modèle ci-dessus, sur Windows la DLL exportera L'API tandis que l'application l'importera. Si ce N'est pas sur Win32, la décoration __declspec est retirée.

puisque l'en-tête enveloppe toute l'interface en extern "C" , en utilisant la macro EXTERN_C sur chaque interface n'est pas nécessaire. extern "C" est utilisé pour dire au linker d'utiliser C linkage au lieu de C++ . C linkage est standard pour tous les compilateurs, alors que C++ ne l'est pas, limitant l'utilisation d'une DLL à une application construite avec le même compilateur.

il n'est pas nécessaire d'intégrer le type de retour dans la macro API.

20
répondu Mark Tolonen 2013-10-23 16:46:29

extern "C" signifie essentiellement que vous dites au compilateur de ne pas marquer votre nom de fonction. Mangling est le processus de "codage" des noms de fonction pour une exécution ultérieure et est très différent en C et c++ car C++ peut avoir différentes fonctions ayant le même nom (via la surcharge etc...).

dans C++ source, Quel est l'effet de "C"externe?

une fois compilées, ces fonctions peuvent être appelées de n'importe où mais vous vous pourriez vouloir être sûr du type de bibliothèque que vous créez (statique ou dynamique) avant de commencer.

aussi, je vous recommande de ne pas utiliser des définitions comme vous le faites dans le même fichier à des fins de portabilité en raison de la maintenance ou des problèmes de lisibilité que vous pourriez rencontrer plus tard dans le développement. Je voudrais créer un fichier de base définissant une interface qui est entièrement portable pour WIN et UNIX puis créer deux autres bibliothèques mettant en œuvre l'interface, mais pour des plates-formes différentes.

par exemple, vous pouvez avoir: AbstractInterface.H, WinInterface.H, UnixInterface.h

compilez seulement ceux dont vous avez besoin en fonction de la plate-forme.

13
répondu aout 2017-05-23 11:54:19

pour Linux, gcc without-fvisibility=hidden exportera les fonctions par défaut, à l'exception des fonctions statiques.

With-fvisibility=hidden, gcc ne fera aucune fonction exportée par défaut, sauf que les fonctions décorées par

__attribute__ ((visibility ("default")))

pour fenêtres, fonctions exportées décorées par

__attribute__ ((dllexport))

lors de l'utilisation des fonctions exportées, elles doivent être décorées par

__attribute__ ((dllimport))

Les macros dans vos messages

__declspec(dllexport)

sont pris en charge par MSVC.

donc les Macro croisées linux et windows sont comme suit:

#if defined _WIN32 || defined __CYGWIN__ || defined __MINGW32__
  #ifdef BUILDING_DLL
    #ifdef __GNUC__
      #define DLL_PUBLIC __attribute__ ((dllexport))
    #else
      #define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
    #endif
  #else
    #ifdef __GNUC__
      #define DLL_PUBLIC __attribute__ ((dllimport))
    #else
      #define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
    #endif
  #endif
  #define DLL_LOCAL
#else
  #if __GNUC__ >= 4
    #define DLL_PUBLIC __attribute__ ((visibility ("default")))
    #define DLL_LOCAL  __attribute__ ((visibility ("hidden")))
  #else
    #define DLL_PUBLIC
    #define DLL_LOCAL
  #endif
#endif
  • assurez-vous que l'objet partagé ou les projets DLL doivent être compilés avec - DBUILDING_DLL.
  • le projet qui dépend de votre objet partagé ou DLL doit être compilé sans - DBUILDING_DLL

pour plus de détails, veuillez lire http://gcc.gnu.org/wiki/Visibility

10
répondu Like 2014-09-01 08:14:29

en raison du concept de polymorphisme propre au langage c++, Toutes les fonctions définies dans c++ sont altérées. c'est-à-dire, pour créer des noms uniques pour chaque fonction surchargée, le "compilateur" décore les noms de fonction.

comme le nom mangling est géré par" compilateur " et qu'il n'y a pas de spécification pour définir strictement les règles de mangling, chaque compilateur décore les noms de différentes façons. En termes simples, les compilateurs gcc et msvc créent une fonction différente signatures pour le même code. vous pouvez lire plus au sujet de nom mangling à l'article de wiki ici .

votre module.le fichier h indique simplement au compilateur d'utiliser le nom de style C mangling ou pas de mangling du tout. grâce à cette directive, la bibliothèque compilée par gcc peut être utilisée pour créer un lien vers un binaire écrit dans visual studio. Cela vous aidera à distribuer les binaires de votre bibliothèque au lieu du code source.

sur l'autre hand, si vous n'utilisez pas la directive EXTERN_C, la bibliothèque et le projet qui renvoie à la bibliothèque doivent être compilés avec le même compilateur. par exemple, vous devez utiliser gcc pour la compilation linux et msvc pour la compilation windows pour la bibliothèque et le lien du projet vers cette bibliothèque.

3
répondu madrag 2013-10-23 10:38:31

au lieu d'écrire vous-même un fichier d'en-tête, vous pouvez aussi laisser CMake en générer un pour le compilateur de bâtiment en utilisant generate_export_header de CMake comme ceci (exemples tirés de la page liée):

add_library(libfoo foo.cpp)
generate_export_header(libfoo)
#include "libfoo_export.h"
class LIBFOO_EXPORT FooClass {
    int bar;
};
2
répondu tstenner 2017-06-29 17:00:30