Exporting Symbols in a Windows Environment
In a Microsoft Windows environment, the dynamic libraries require a special inline syntax to declare a symbol as exported. The classic mechanism for exporting a specific symbol from a library and importing it into a program that uses that library is a conditionally defined macro which expands to the appropriate storage-class attributes. This macro will expand one way in the library and another way in the program. For example:
// library internal header
// library.h
#ifdef LIBRARY_SOURCE
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __declspec(dllimport)
#endif // LIBRARY_SOURCE
// library header, declaring exported type
// A.h
#include <library.h>
struct EXPORT A
{
// ...
};
// library source file
// A.cpp
#define LIBRARY_SOURCE
#include <A.h>
//...
// program using the above library
#include <A.h>
int main ()
{
A a;
}
From this code example, you can see how the EXPORT macro is expanded in the library code different from the way it is expanded in the program code.
The Essential Tools Module serialization macros use a similar mechanism. To properly export the serialization symbols:
1. In one of the internal headers of the library, define a macro such as MODULE_FUNCTION which will expand to either dllexport or dllimport.
// user library internal header
// library.h
#ifdef LIBRARY_SOURCE
# define MODULE_FUNCTION __declspec(dllexport)
# define EXPORT __declspec(dllexport)
#else
# define MODULE_FUNCTION __declspec(dllimport)
# define EXPORT __declspec(dllimport)
#endif // LIBRARY_SOURCE
2. The prefix of the MODULE_FUNCTION macro is then used consistently across the library as the first parameter of the serialization macros.
// user library header
// A.h
class EXPORT A : public RWCollectable
{
// use serialization macros; pass as first parameter the
// prefix of the MODULE_FUNCTION macro above,
// i.e. "MODULE"
RW_DECLARE_COLLECTABLE_CLASS(MODULE, A)
// ...
};
// user library source files
// A.cpp
#define LIBRARY_SOURCE
#include <A.h>
// use serialization macros; first parameter same as above;
// use the name "MODULE" consistently across your whole
// library
For example, in a user application called “BusSchedule” you might choose a prefix such as BUS_SCHEDULE and compose the support macro as:
// ...
#define BUS_SCHEDULE_FUNCTION
// ...
For a static library on a Windows platform, a static or dynamic library on any other platform, or for your application, simply define MODULE_FUNCTION with no body such as:
// user header
// my_header.h
#define MODULE_FUNCTION
// program source
#include <my_header.h>
class A : public RWCollectable
{
RW_DECLARE_COLLECTABLE_CLASS(MODULE, A)
// ...
};
For more information, refer to rw/rwwind.h.