Free Electron
Exposing Classes, Global Functions, and Static Variables

All references to Win32 presumably apply to Win64 as well.

# Imports and Exports

Due to unfortunate limitations of the Win32 in its DLL design, it is necessary to follow several deviations from conventional C++ syntax in order to align static variables and global functions across dynamic libraries.

All classes which might have cross-library exposure require an additional specification. For classes without static variables, it should be sufficient to use a general specifier of the following form in the class definition.

class FE_DL_EXPORT MyClass

This leverages an unwritten lenience in the past and current implementions of Win32. Apparently, the exported classes can be implicitly interpreted as imported in modules that link to the first DLL. Officially, the more detailed procedure that follows should be used for all classes, but it appears to be sufficient to only require it in limited cases.

For global functions, global static variables, or classes with static variables, you must use a form that takes into account whether you are compiling the object into a dynamic library or just using it from another dynamic library.

Using the module "core" as an example, forge will automatically define MODULE_core and the following is featured in the master header core.h:

#ifdef MODULE_core
#define FE_CORE_PORT FE_DL_EXPORT
#else
#define FE_CORE_PORT FE_DL_IMPORT
#endif

The class Counted in the module core is defined as:

class FE_CORE_PORT Counted

This causes the symbols of the class to be exported from the "core" dynamic library and imported from any code that just uses the "core" dynamic library.

The same procedure works for global functions and global static variables.

Classes defined within other classes are not automatically exposed and should carry the additional specification themselves, if exposure is desired.

If this procedure is not followed, it is very easy to generate duplicate symbols that quietly operate in complete ignorance of each other.

The macro FE_DL_IMPORT is available for direct use, but no known scenario requires it to be specified explicitly. Using FE_DL_IMPORT directly will likely cause eventual errors.

# Visibility

GCC 4.0 introduces the concept of visibility that is similar in some respects to the Win32 mechanism. Unlike the Win32 platform, the Gnu mechanism is completely optional. But since the Win32 scheme is already supported, visibility support is easily implemented using some of the same macros. The macros are inserted in the same way at class and variable declaration (and sometimes definition), so all currently known use cases are compatible with Win32.

By applying visibility, there can potentially be a substantial reduction in binary size, as well as improvements to code optimization.

Visibility is currently automatically selected by forge when gcc 4.0 or higher is detected for FE_CC. Specifically, both inline visibility and general visibilty are set to hidden. When visibility is activated, the following macros are defined as follows.

- FE_DL_EXPORT The class or variable is exposed for use outside of
the dynamic library.

- FE_DL_IMPORT This macro has no effect under Gnu.
As mentioned previously, explicit use of FE_DL_IMPORT is not advised.

- FE_DL_PUBLIC This has the same effect as FE_DL_EXPORT under Gnu
and no effect under Win32.
Declarations and definitions of static member variables have to be
individually exposed under Gnu, but not under Win32
(where class export implies full member export).
Also, classes defined inside other classes may require this macro,
depending on whether a FE_DL_EXPORT is already needed for Win32.


Without visibility, all these macros are defined empty.

It is valid to use a module "PORT", like FE_CORE_PORT demonstrated above, with FE_DL_PUBLIC on the same symbol. An example would be a global function where Win32 requires an import/export scheme and GNU requires exposure for both the library and any code linking to the library. The only time both macros are non-empty is for a Gnu dynamic library, in which case they are both an export, and the redundancy is silently ignored.

# Static Variable Access

FE does not have a solution to allow accessing static variables in a header. No export or import directives under Win32 appear to make this work. You can declare static variables in the header, but like the definition, you can not read or write their values in the header.

Either make the static variables const and define the value in the header, or access them only in the cc file.

It has not been determined if it is safe to directly access static variables outside the library in which they are declared and defined. It seems unwise, so access to static variables should be wrapped appropriately if the use of a static variable can not be avoided altoegther.