Visibility in Shared Library

static in C++

static has three usages in C++:

  • the legacy C one when used at the top-level: a static symbol is visible only in the file it is used (by default top-level symbols are global). It is recommended to use anonymous namespace in place of this legacy form of static. Note a symbol from such anonymous namespace will be in the symbol table.
  • the C one when used for a variable inside a block: the extend of the variable value begins at the first entry in the block and never ends.
  • class (vs instance) variable or method when used inside a class declaration.

extern in C++

extern has three usages in C++:

  • extern "C" to introduce C external language linkage with the nice side effect to remove the C++ symbol name mangling.
  • extern const to make a constant global (by default constant are local). This is required for declaration and (should be) optional for definition.
  • extern for shared explicit template instantiation (c++11 but commonly supported as really useful).

Windows dllimport/dllexport

A Windows Dynamic-Link Library doesn't make symbols implicitly global, i.e., externally visible. Instead, exported symbols must be either in a .def file or decorated with __declspec(dllexport). At the other side, a code using a DLL symbol should decorate it with __declspec(dllimport)). This leads to a pretty standard macro <DLL_NAME>_API with a <DLL_NAME>>_EXPORT define to switch between import and export.

Visibility in Unix/Linux

At the cost of some decorations to limit the default visibility of symbols in a shared library has many advantages:

  • it allows a natural compatibility with Windows DLLs
  • it reduces the probability of name conflicts (not for us as the visibility stuff is an option)
  • it makes dynamic linking faster
  • it opens new opportunity for optimization
  • it makes shared library objects far smaller (10 times smaller after stripping).

Of course the last point was the reason to make the visibility effort.

Each symbol has a visibility, -fvisibility=hidden makes the default hidden, the attribute __attribute__((visibility("default"))) restores the visibility to the built-in default which is public.


Kea implementation

For all shared libraries (not hooks DSO) add in its directory (there is currently no directory shared between two shared libraries):

  • if there is a .mes file, add the .api and .include files
  • ( add $(SHLIB_CXXFLAGS) in the CXXFLAGS used to build the shared library
  • add an api.h include with the API macro
  • ( add api.h in the shared library sources
  • (*.h) include api.h in all other includes before any library includes
  • (*.cc) add a <LIB_NAME>_EXPORT after the copyright comment and before includes
  • (*.h) decorate with <LIB-NAME>_API:
    • all top-level class/struct declarations (but not the templates)
    • extern const declarations
    • global functions
    • in some cases embedded class/struct declarations
  • (*.cc) decorate with <LIB_NAME>_API:
    • extern const definitions
    • global functions
  • in some cases a class is defined only in an include and needs to be instantiated. util/ is the canonical example.

Note to fail to export a type (i.e., class or struct) can have bad side effects when it is an exception or the object of a dynamic class.

Last modified 4 years ago Last modified on May 18, 2015, 3:14:06 PM