Skip to content

Exporting Symbols of Shared Libraries in Mantid

Anton Piccardo-Selg edited this page Jul 19, 2016 · 2 revisions

For a good introduction to exporting symbols and what the nuances of gcc and MSVC are, have a look here.

Mantid has been using the default symbol behaviour of MSVC and GCC up until now. By default everything is hidden for MSVC and everything is visible for gcc. Because of this difference in visibility, a development branch might pass on the RHEL X and Ubuntu builds, but can nevertheless fail on Windows. This leads to waisted time and effort in order find and understand the underlying issue. Hence, providing a common symbol visibility should streamline our development resources.

Exporting symbols

The specification of the exported symbols is achieved via an extended attribute syntax which is compiler-dependent. MSVC achieves this using __declspec(dllexport) and __declspec(dllimport)(see here). gcc makes use of __attribute__ ((visibility ("default"))) (see here) and compiler flags to set the visibility to hidden.

This attribute syntax is used in the library-specfic DllConfig.h file. In the case of the API library then contents of the file are essentially:

#ifdef IN_MANTID_API
#define MANTID_API_DLL DLLExport
#define EXTERN_MANTID_API
#else
#define MANTID_API_DLL DLLImport
#define EXTERN_MANTID_API EXTERN_IMPORT
#endif /* IN_MANTID_API*/

Developers will then use MANTID_API_DLL to specify which class/functions should be exported. (The use case of the extern macro is discussed below.) A typical use case would be:

\\ in foo.h which is part of the API shared library
namespace Mantid {
namespace API {

class MANTID_API_DLL Foo {
...
}; 
...
} // namespace API
} // namespace Mantid

Important: Each library will have its own DllConfig.h with its own export macro, i.e. exporting in Kernel requires the use of MANTID_KERNEL_DLL and so on.

GCC

Changes

The aim of issue 15283 was to make the symbol visibility consistent between gcc and MSVC. This required some modifications of the existing code. The vast majority of changes are related to explicit template instantiations. The main modifications are shown, via example, below.

Singletons

A typical singleton in Mantid used to look like this:

namespace Mantid {
namespace API{
...
/// Forward declaration of a specialisation of SingletonHolder for
/// AlgorithmManagerImpl (needed for dllexport/dllimport) and a typedef for it.
#ifdef _WIN32
// this breaks new namespace declaraion rules; need to find a better fix
template class MANTID_API_DLL
    Mantid::Kernel::SingletonHolder<AlgorithmManagerImpl>;
#endif /* _WIN32 */
typedef Mantid::Kernel::SingletonHolder<AlgorithmManagerImpl> AlgorithmManager;
...
} // namespace API
} // Namespace Mantid

This has changed to the following form:

namespace Mantid {
namespace API{
...
typedef Mantid::Kernel::SingletonHolder<AlgorithmManagerImpl> AlgorithmManager;
...
} // namespace API
} // Namespace Mantid

namespace Mantid {
namespace Kernel {
EXTERN_MANTID_API template class MANTID_API_DLL
    Mantid::Kernel::SingletonHolder<Mantid::API::AlgorithmManagerImpl>;
}
}

There are several things to consider here:

  1. The template instantiation is pushed into the Kernel namespace since this is where the SingletonHolder template is declared. See here
  2. It is not any longer restricted to Windows
  3. The macro EXTERN_MANTID_XXX (in this case EXTERN_MANTID_API) is placed at the beginning. This allows us to have an explicit instantiation declaration which ensures that the Singleton exists only once, even across library boundaries. See here and here.

typedefs

Mantid had several cases of typedefs of the form:

// in FileLoaderRegistry.h
typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<FileLoaderRegistryImpl>

It is not clear why the export macro was used on the typedef in the first place, but a warning-free version is:

// in FileLoaderRegistry.h
typedef Mantid::Kernel::SingletonHolder<FileLoaderRegistryImpl>

Location of export macro

It appears that MSVC is more forgiving with the location of the export macro than gcc.

Previously Mantid had:

\\ in WorkspaceProperty.cpp
template MANTID_API_DLL class Mantid::API::WorkspaceProperty<
    Mantid::API::Workspace>;

The order which removes gcc warnings is:

\\ in WorkspaceProperty.cpp
template class MANTID_API_DLL Mantid::API::WorkspaceProperty<
    Mantid::API::Workspace>;