-
Notifications
You must be signed in to change notification settings - Fork 124
Exporting Symbols of Shared Libraries in Mantid
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.
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.
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.
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:
- The template instantiation is pushed into the
Kernel
namespace since this is where theSingletonHolder
template is declared. See here - It is not any longer restricted to Windows
- 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.
Mantid had several cases of typedef
s 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>
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>;