Vraag Een draagbare bibliotheek maken om op zowel linux als windows te draaien


gcc (GCC) 4.7.2

Hallo,

Ik maak een gedeelde bibliotheek die compileert op Linux en een dll die compileert op vensters met dezelfde broncode. Dus ik ben bezig met het maken van een draagbare bibliotheek voor zowel Linux als Windows.

In mijn header-bestand voor de bibliotheek is dit d.w.z. 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 de bron heb ik het volgende, d.w.z. module.c

#include "module.h"

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

En in mijn testapplicatie die deze module zal koppelen en gebruiken. Dus ik heb dit:

#include "module.h"

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

1) Is wat ik hierboven heb gedaan een correcte implementatie van het maken van een draagbare bibliotheek voor linux en windows?

2) Ik vraag me alleen af ​​hoe ik de functies heb ingepakt extern "C" zodat deze bibliotheek kan worden aangeroepen vanuit een programma dat is gecompileerd in C ++. Heb ik dit nog steeds nodig? EXTERN_C in de volgende:

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

3) Wat is het doel van de EXTERN_C?

Bij voorbaat hartelijk dank,


26
2017-10-17 05:29


oorsprong


antwoorden:


Dit is een standaardmanier om een ​​DLL-API voor Windows te exporteren en nog steeds Linux te ondersteunen:

#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 de DLL-bron:

#define MODULE_API_EXPORTS
#include "module.h"

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

Uw toepassingsbron is correct.

Met behulp van het bovenstaande model zal de DLL op Windows de API exporteren terwijl de toepassing deze zal importeren. Als niet op Win32, de __declspec decoratie is verwijderd.

Omdat de header de volledige interface omsluit extern "C", de ... gebruiken EXTERN_C macro op elke interface is niet vereist. extern "C" wordt gebruikt om de linker te vertellen om te gebruiken C koppeling in plaats van C++. C-koppeling is standaard voor compilers, terwijl C ++ dat niet is, waardoor het gebruik van een DLL wordt beperkt tot applicaties die met dezelfde compiler zijn gebouwd.

Het retourneertype hoeft niet in de API-macro te worden geïntegreerd.


20
2017-10-23 16:46



externe "C" betekent in feite dat je de compiler zegt om je functienaam niet te verwarren. Mangling is het proces van het "coderen" van functienamen voor latere uitvoering en is behoorlijk verschillend in C en C ++ omdat C ++ verschillende functies kan hebben met dezelfde naam (via overbelasting enz ...).

Wat is in C ++ - bron het effect van externe "C"?

Eenmaal gecompileerd kunnen deze functies overal worden opgeroepen, maar u kunt er zeker van zijn welk type bibliotheek u aan het maken bent (statisch of dynamisch) voordat u begint.

Ik raad u ook aan DEFINES niet te gebruiken zoals in hetzelfde bestand voor portabiliteitsdoeleinden vanwege de onderhouds- of leesbaarheidsproblemen die u later in de ontwikkeling kunt tegenkomen. Ik zou een basisbestand maken dat een interface definieert die volledig draagbaar is voor WIN en UNIX en vervolgens twee andere bibliotheken maken die de interface implementeren, maar voor verschillende platforms.

U kunt bijvoorbeeld: SamenvattingInterface.h, WinInterface.h, UnixInterface.h

Stel vervolgens alleen de bestanden samen die u nodig hebt, afhankelijk van het platform.


13
2017-10-18 13:23



Voor Linux gebruikt gcc without -fvisibility = hidden om functies standaard te exporteren, behalve voor statische functies.

Met -fvisibility = hidden, gcc maakt standaard geen functies geëxporteerd, behalve de functies die zijn gedecoreerd met

__attribute__ ((visibility ("default")))

Voor Windows, geëxporteerde functies ingericht door

__attribute__ ((dllexport))

wanneer u de geëxporteerde functies gebruikt, moeten ze worden gedecoreerd door

__attribute__ ((dllimport))

De macro's in je berichten

__declspec(dllexport)

worden ondersteund door MSVC.

Dus de gekruiste linux en windows macro's zijn als volgt:

#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
  • Zorg ervoor dat het gedeelde object of DLL-projecten moeten worden gecompileerd met -DBUILDING_DLL.
  • Het project dat afhankelijk is van uw gedeelde object of DLL moet worden gecompileerd zonder -DBUILDING_DLL

Lees voor meer informatie http://gcc.gnu.org/wiki/Visibility


10
2017-10-29 18:51



Vanwege het concept van polymorfisme dat specifiek is voor de taal c ++, zijn alle functies die in c ++ zijn gedefinieerd verminkt. d.w.z. om unieke namen te creëren voor elke overschreven functie, versiert de "compiler" de functienamen.

Omdat mangling wordt beheerd door "compiler" en er geen specificatie is om de naammanglingregels strikt te definiëren, versiert elke compiler de namen op verschillende manieren. Simpel gezegd, gcc en msvc compilers creëren verschillende functiehandtekeningen voor dezelfde code. je kunt meer lezen over het verminken van namen in het wiki-artikel hier.

Uw module.h-bestand vertelt de compiler eenvoudigweg c-mangling of helemaal geen mangling te gebruiken. dankzij deze richtlijn kan de bibliotheek die is gecompileerd door gcc worden gebruikt om te linken naar een binair bestand dat is geschreven in de visuele studio. Dit zal u helpen om de binaire bestanden van uw bibliotheek te verspreiden in plaats van de broncode.

Aan de andere kant, als u de EXTERN_C-richtlijn niet gebruikt, moeten de bibliotheek en het project dat naar de bibliotheek linkt met dezelfde compiler worden gecompileerd. U moet bijvoorbeeld gcc gebruiken voor linux-compilatie en msvc voor windows-compilatie voor zowel de bibliotheek als het project dat naar die bibliotheek linkt.


3
2017-10-23 10:38



In plaats van zelf een headerbestand te schrijven, kun je CMake ook een headerbestand laten genereren voor de gebouwcompiler CMake's generate_export_header zoals dit (voorbeelden van de gekoppelde pagina):

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

2
2018-06-29 17:00