Erstellen einer portablen Bibliothek, die sowohl unter Linux als auch unter Windows ausgeführt werden kann

Lesezeit: 6 Minuten

Benutzer-Avatar
Ameise2009

gcc (GCC) 4.7.2

Hallo,

Ich erstelle eine gemeinsam genutzte Bibliothek, die unter Linux kompiliert wird, und eine DLL, die unter Windows mit demselben Quellcode kompiliert wird. Also erstelle ich eine portable Bibliothek für Linux und Windows.

In meiner Header-Datei für die Bibliothek steht das zB 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

In der Quelle habe ich folgendes dh module.c

#include "module.h"

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

Und in meiner Testanwendung, die dieses Modul verknüpft und verwendet, habe ich Folgendes:

#include "module.h"

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

1) Ist das, was ich oben getan habe, eine korrekte Implementierung der Erstellung einer portablen Bibliothek für Linux und Windows?

2) Ich frage mich nur, wie ich die Funktionen eingepackt habe extern "C" damit diese Bibliothek aus einem in C++ kompilierten Programm aufgerufen werden kann. Brauche ich das noch EXTERN_C im Folgenden:

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

3) Was ist der Zweck der EXTERN_C?

Vielen Dank im Voraus,

  • Es ist ein Makro, das auflöst extern "C" für die C++-Kompilierung und entweder extern oder nichts für die C-Kompilierung. (Ich kann mich ehrlich gesagt nicht erinnern, welche, aber markieren Sie es und drücken Sie F12, es sollte Sie zur eigentlichen Definition bringen). Es ist Zweck besteht darin, den Compiler anzuweisen, die C++-Namensverfälschung aus dem Symbol zu entfernen, das aus Ihrer Bibliothek exportiert wird. Und nein, wenn Sie bereits den gesamten Header eingepackt haben extern "C" { Sie können es eliminieren (vorausgesetzt, gcc versteht dasselbe block-extern-C, und ich erinnere mich ehrlich gesagt nicht daran, ob dies der Fall ist).

    – WhozCraig

    17. Oktober 2013 um 5:33 Uhr


  • Lesen Sie bitte Dies. Sie können diesen Mechanismus verwenden.

    – n. 1.8e9-wo-ist-meine-Aktie m.

    17. Oktober 2013 um 6:24 Uhr

  • @ant2009 Muss deine Bibliothek von C verwendet werden, oder kannst du sie auf C++11 beschränken?

    – John Bandela

    29. Oktober 2013 um 12:42 Uhr

  • Ansehen poko und Qt Quellcode. Beide bieten Bibliotheken mit gemeinsamer API für Windows und Linux.

    – Basile Starynkevitch

    1. September 2014 um 8:18 Uhr

Dies ist eine typische Methode, um eine DLL-API für Windows zu exportieren und dennoch Linux zu unterstützen:

#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

In der DLL-Quelle:

#define MODULE_API_EXPORTS
#include "module.h"

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

Ihre Anwendungsquelle ist korrekt.

Unter Verwendung des obigen Modells exportiert die DLL unter Windows die API, während die Anwendung sie importiert. Wenn nicht auf Win32, die __declspec Dekoration wird entfernt.

Da der Header die gesamte Schnittstelle umschließt extern "C"Verwendung der EXTERN_C Makro auf jeder Schnittstelle ist nicht erforderlich. extern "C" wird verwendet, um dem Linker mitzuteilen, dass er verwendet werden soll C Verknüpfung statt C++. Die C-Verknüpfung ist bei allen Compilern Standard, C++ nicht, wodurch die Verwendung einer DLL auf Anwendungen beschränkt wird, die mit demselben Compiler erstellt wurden.

Der Rückgabetyp muss nicht in das API-Makro integriert werden.

Benutzer-Avatar
aus

extern “C” bedeutet im Grunde, dass Sie dem Compiler mitteilen, Ihren Funktionsnamen nicht zu manipulieren. Mangling ist der Prozess des “Codierens” von Funktionsnamen für die spätere Ausführung und ist in C und C++ ziemlich unterschiedlich, da C++ verschiedene Funktionen mit demselben Namen haben kann (durch Überladen usw.).

Welche Auswirkung hat extern “C” in C++-Quellen?

Einmal kompiliert, können diese Funktionen von überall aus aufgerufen werden, aber Sie sollten sicher sein, welche Art von Bibliothek Sie erstellen (statisch oder dynamisch), bevor Sie beginnen.

Außerdem empfehle ich Ihnen, DEFINES nicht so zu verwenden, wie Sie es in derselben Datei für Portabilitätszwecke tun, wegen der Wartungs- oder Lesbarkeitsprobleme, auf die Sie später in der Entwicklung stoßen könnten. Ich würde eine grundlegende Datei erstellen, die eine Schnittstelle definiert, die vollständig auf WIN und UNIX portierbar ist, und dann zwei weitere Bibliotheken erstellen, die die Schnittstelle implementieren, jedoch für unterschiedliche Plattformen.

Zum Beispiel können Sie haben: AbstractInterface.h, WinInterface.h, UnixInterface.h

Stellen Sie dann nur die zusammen, die Sie je nach Plattform benötigen.

Benutzer-Avatar
Wie

Für Linux werden mit gcc ohne -fvisibility=hidden Funktionen standardmäßig exportiert, mit Ausnahme von statischen Funktionen.

Mit -fvisibility=hidden exportiert gcc standardmäßig keine Funktionen, außer den Funktionen, die von dekoriert wurden

__attribute__ ((visibility ("default")))

Für Windows exportierte Funktionen dekoriert mit

__attribute__ ((dllexport))

Wenn Sie die exportierten Funktionen verwenden, müssen sie dekoriert werden

__attribute__ ((dllimport))

Die Makros in deinen Beiträgen

__declspec(dllexport)

werden von MSVC unterstützt.

Die gekreuzten Linux- und Windows-Makros lauten also wie folgt:

#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
  • Stellen Sie sicher, dass Shared Object- oder DLL-Projekte kompiliert werden müssen
    mit -DBUILDING_DLL.
  • Das Projekt, das von Ihrem gemeinsam genutzten Objekt oder Ihrer DLL abhängt, muss kompiliert werden ohne -DBUILDING_DLL

Für weitere Details lesen Sie bitte http://gcc.gnu.org/wiki/Visibility

Aufgrund des Konzepts des Polymorphismus, das spezifisch für die Sprache c++ ist, werden alle in c++ definierten Funktionen entstellt. dh um eindeutige Namen für jede überschriebene Funktion zu erstellen, ergänzt der “Compiler” die Funktionsnamen.

Da die Namensverfälschung vom “Compiler” gehandhabt wird und es keine Spezifikation gibt, um die Namensverfälschungsregeln strikt zu definieren, schmückt jeder Compiler die Namen auf unterschiedliche Weise. Einfach ausgedrückt, gcc- und msvc-Compiler erstellen unterschiedliche Funktionssignaturen für denselben Code. Weitere Informationen zur Namensverfälschung finden Sie im Wiki-Artikel hier.

Ihre module.h-Datei weist den Compiler einfach an, Namensverstümmelung im C-Stil oder überhaupt keine Verstümmelung zu verwenden. Aufgrund dieser Anweisung kann die von gcc kompilierte Bibliothek verwendet werden, um eine Verknüpfung zu einer in Visual Studio geschriebenen Binärdatei herzustellen. Dies hilft Ihnen, die Binärdateien Ihrer Bibliothek anstelle des Quellcodes zu verteilen.

Wenn Sie andererseits die Direktive EXTERN_C nicht verwenden, sollten die Bibliothek und das Projekt, das mit der Bibliothek verknüpft ist, mit demselben Compiler kompiliert werden. Beispielsweise müssen Sie gcc für die Linux-Kompilierung und msvc für die Windows-Kompilierung sowohl für die Bibliothek als auch für das Projekt verwenden, das mit dieser Bibliothek verknüpft ist.

Anstatt selbst eine Header-Datei zu schreiben, können Sie CMake auch eine für den Bau-Compiler generieren lassen Generate_export_header von CMake so (Beispiele von der verlinkten Seite):

add_library(libfoo foo.cpp)
generate_export_header(libfoo)
#include "libfoo_export.h"
class LIBFOO_EXPORT FooClass {
    int bar;
};

1383470cookie-checkErstellen einer portablen Bibliothek, die sowohl unter Linux als auch unter Windows ausgeführt werden kann

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy