Creating a portable library to run on both linux and windows

ant2009 picture ant2009 · Oct 17, 2013 · Viewed 13k times · Source
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 source code. So i am creating an portable library for both linux and windows.

In my header file for the library is this i.e. 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 the source I have the following i.e. module.c

#include "module.h"

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

And in my test application that will link and use this module.so I have this:

#include "module.h"

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

1) Is what I have done above is it a correct implementation of creating a portable library for linux and windows?

2) I am just wondering as I have wrapped the functions in extern "C" so that this library can been called from a program that has been compiled in C++. Do I still need this EXTERN_C in the following:

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

3) What is the purpose of the EXTERN_C?

Many thanks in advance,

Answer

Mark Tolonen picture Mark Tolonen · Oct 23, 2013

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.