export.h File Reference

Defines symbol visibility macros. More...

+ Include dependency graph for export.h:

Go to the source code of this file.


#define ARCH_EXPORT_TEMPLATE(type, ...)
#define ARCH_IMPORT_TEMPLATE(type, ...)   extern template type ARCH_IMPORT __VA_ARGS__

Detailed Description

Defines symbol visibility macros.

Defines ARCH_EXPORT to indicate a symbol should be exported from a library, ARCH_IMPORT to indicate an exported symbol should be imported (which only matters on Windows), and ARCH_HIDDEN to indicate that a symbol which would be exported should not be.

The correct way to use these macros is for each library to make a header that looks like this (for some hypothetical library named foo):

#ifndef FOO_API_H
#define FOO_API_H
#if defined(FOO_STATIC)
# define FOO_API
# define FOO_LOCAL
# if defined(FOO_EXPORTS)
# else
# endif

Note that every library has its own unique _API and _LOCAL macros and the expansion of these macros depends on whether the library is being built or used (indicated by the externally set macro FOO_EXPORTS).

Library headers then include this header and mark classes, methods, functions and variables as part of the API or local. Each case is described below.

A class is added to the API like this:

class FOO_API FooClass ...

This will add every member to the API, including implicitly created members like a default constructor, default assignment, the vtable and the type_info. The type_info is especially important. If you will dynamic_cast to the type or catch an exception using the type outside of the library, you must put its type_info into the API. To export the vtable & type_info specifically, use ARCH_EXPORT_TYPE. However, due to compiler limitations, ARCH_EXPORT_TYPE may put the whole class into the API as if ARCH_EXPORT were used.

Note that template classes do not get added to the API that way. Instead they are added when explicitly instantiated like so:

template class FOO_API FooTemplateClass<FooArgType>;

It's also sometimes necessary to indicate that an instantiation exists in the API and that a client should not do any of its own instantiation. This is necessary, for example, when the template has static data members and is done by using extern template in the header file that provides the type. Two of the macros above will do that:


Which you use depends on if FooTemplateClass is a class or struct. The macro is used because we don't want to always use extern template, but only when we're importing a dynamic library.

A template that is completely inlined does not need to be added to the API since it's simply instantiated where needed.

Functions, methods and variables can also be put into the API:

struct FooLocalClass {
FOO_API void MoveTheThing();
FOO_API FooLocalClass* FooNewThing();
FOO_API extern int doNotUseGlobalVariables;

Just because FooLocalClass is not in the API doesn't mean clients can't have pointers and references to instances. What they can't do is call member functions not in the API (or, as indicated above, use RTTI for it). So, for example:

FooLocalClass* thing = FooNewThing();
(void)dynamic_cast<FooLocalClass*>(thing); // Link error!
delete thing; // Link error!

Deleting the FooLocalClass instance attempts to use the (non-API) d'tor and fails to link. If we had an implicitly defined d'tor then the deletion would have worked, presuming FooLocalClass didn't have any data members with non-API d'tors.

A method of a class added to the API is itself in the API but on some platforms (i.e. not Windows) you can remove it from the API using FOO_LOCAL:

struct FOO_API FooSemiAPI {
void DoSomethingPublic();
FOO_LOCAL void _DoSomethingPrivate();

Clients of the library will fail to link if they use _DoSomethingPrivate() if FOO_LOCAL is supported. If not then the symbol will remain in the API.

Definition in file export.h.