Creating a portable library to run on both linux and windows

前端 未结 5 1719
野趣味
野趣味 2020-12-23 18:20
gcc (GCC) 4.7.2

Hello,

I am creating a shared library that will compile on linux and a dll that will compile on windows using the same sour

相关标签:
5条回答
  • 2020-12-23 18:21

    For Linux, gcc without -fvisibility=hidden will make functions exported by default, except for static functions.

    With -fvisibility=hidden, gcc will make no functions exported by default, except that functions decorated by

    __attribute__ ((visibility ("default")))
    

    For Windows, exported functions decorated by

    __attribute__ ((dllexport))
    

    when using the exported functions, they must be decorated by

    __attribute__ ((dllimport))
    

    The macros in your posts

    __declspec(dllexport)
    

    are supported by MSVC.

    So the crossed linux and windows macros are as following:

    #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
    
    • Make sure that shared object or DLL projects must be compiled with -DBUILDING_DLL.
    • The project that depends on your shared object or DLL must be compiled without -DBUILDING_DLL

    For the more details, please read http://gcc.gnu.org/wiki/Visibility

    0 讨论(0)
  • 2020-12-23 18:23

    Due to the concept of polymorphism which is specific to c++ language, All the functions defined in c++ are mangled. i.e., to create unique names for each overridden function, the "compiler" decorates the function names.

    Since name mangling is handled by "compiler" and there is no specification to strictly define the name mangling rules, each compiler decorates the names in different ways. Simply put, gcc and msvc compilers create different function signatures for the same code. you can read further about name mangling at the wiki article here.

    Your module.h file simply tells the compiler to use c style name mangling or no mangling at all. due to this directive, the library that is compiled by gcc can be used to link to a binary that is written in visual studio. This will help you to distribute the binaries of your library instead of source code.

    On the other hand, if you do not use the EXTERN_C directive, the library and the project that links to the library should be compiled using same compiler. for example, you have to use gcc for linux compilation and msvc for windows compilation for both the library and the project linking to that library.

    0 讨论(0)
  • 2020-12-23 18:30

    This is a typical way to export a DLL API for Windows and still support 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
    

    In the DLL source:

    #define MODULE_API_EXPORTS
    #include "module.h"
    
    MODULE_API int module_init()
    {
        /* do something useful */
        return 0;
    }
    

    Your application source is correct.

    Using the above model, on Windows the DLL will export the API while the application will import it. If not on Win32, the __declspec decoration is removed.

    Since the header wraps the entire interface in extern "C", using the EXTERN_C macro on each interface is not required. extern "C" is used to tell the linker to use C linkage instead of C++. C linkage is standard across compilers, whereas C++ is not, limiting the use of a DLL to application built with the same compiler.

    There is no need to integrate the return type into the API macro.

    0 讨论(0)
  • 2020-12-23 18:30

    extern "C" basically means that you are telling the compiler not to mangle your function name. Mangling is the process of "encoding" function names for later execution and is quite different in C and C++ as C++ can have different functions having the same name (via overloading etc...).

    In C++ source, what is the effect of extern "C"?

    Once compiled these functions can be called from anywhere but you might want to be sure what kind of library you are creating (static or dynamic) before you start.

    Also I recommend you not using DEFINES like you do in the same file for portability purposes because of the maintenance or readability problems you might encounter later in the development. I would create a basic file defining an interface which is fully portable to WIN and UNIX then create two other libraries implementing the interface but for different platforms.

    For example you can have: AbstractInterface.h, WinInterface.h, UnixInterface.h

    Then only compile the ones you need depending on the platform.

    0 讨论(0)
  • 2020-12-23 18:32

    Instead of writing a header file yourself, you can also let CMake generate one for the building compiler using CMake's generate_export_header like this (examples taken from the linked page):

    add_library(libfoo foo.cpp)
    generate_export_header(libfoo)
    #include "libfoo_export.h"
    class LIBFOO_EXPORT FooClass {
        int bar;
    };
    0 讨论(0)
提交回复
热议问题