Subject: Re: [boost] [config] gcc,msvc,mingw visibility
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2015-04-23 03:55:51
On Thu, Apr 23, 2015 at 8:19 AM, Robert Ramey <ramey_at_[hidden]> wrote:
> I've been enabling limited gcc visibility so that it works similarly to msvc
> *_DECL attributes and will export from the DLL/DSO only those symbols which
> need to be exported.
> I've had a lot of difficulty with this.
> I followed the instructions
> which more or less boil down to using BOOST_SYMBOL_EXPORT when functions are
> exported, BOOST_SYMBOL_IMPORT when functions are imported, and
> BOOST_SYMBOL_VISIBLE on class declarations.
> I set my Jamfile.v2 in the library build to enable gcc visibility=hidden and
> let her rip.
> After the more or less normal back and forth it seemed that the library
> built and work on all platforms/compilers. .... EXCEPT Mingw. Hmmmm -
> this shouldn't be too tough, just look at how the other libraries did it.
> Turns out that it seems that no boost libraries actually enable gcc
> visibility in their builds - at least as far as I can tell. (I didn't dig
> into the depths of jam tools files).
I'm restricting visibility in Boost.Log. For now it's only in develop,
I'm planning to merge it to master for the next release. I didn't test
it personally with MinGW but the test matrix doesn't show failures.
> After a fair amount of research I
> concluded that for windows platforms - regardless of whether they are built
> with minnow (gcc) or mdvc, one needs to define BOOST_SYMBOL_VISIBLE as
> BOOST_SYMBOL_IMPORT or BOOST_SYMBOL_IMPORT which of course makes things more
No, I don't think this is right. BOOST_SYMBOL_VISIBLE has no effect
with MSVC, and probably even Windows in general, because AFAIK the
runtime linker there has no support for symbol relocation similar to
Linux. But the macro should still be used to mark types for
BOOST_SYMBOL_VISIBLE should be used on types which can be used as
exceptions or in dynamic_casts across dynamic library boundaries. The
net effect of such markup is to make the type info visible to the
linker so that it is able to relocate references to the type info from
different modules to a single instance. On Windows this is not needed
(and not performed) because the language runtime there works with type
info by value and not by address. This is true for both MSVC and GCC.
BOOST_SYMBOL_EXPORT/IMPORT are similar to BOOST_SYMBOL_VISIBLE on
UNIX-like systems in the sense that exporting a symbol (a function or
data) on those systems is just a matter of making it visible to the
runtime linker. So when you build your library and use
BOOST_SYMBOL_EXPORT, it expands to something similar to
BOOST_SYMBOL_VISIBLE. BOOST_SYMBOL_IMPORT can be empty because there
is nothing to do to "import" a symbol, but the macro is still needed
for compatibility with Windows.
On Windows though exported symbols are not simply made visible but
their name is mangled differently. This requires to mark the symbols
both when exported and imported (and for some reason the markup is
different, hence the two macros for that). So the general advice is to
have your own macro (say, MY_LIB_API), which is defined to
BOOST_SYMBOL_EXPORT when your library is built and BOOST_SYMBOL_IMPORT
Now, which symbols need to be marked. Basically, every symbol that can
be used across the library boundary needs to be marked with
MY_LIB_API. Primarily this means functions. You can also mark the
whole class with MY_LIB_API, and this would result in automatically
exporting all its functions, including the implicitly defined ones,
like constructors, destructor and assignment, as well as static data
members. See  for more details. Personally, I try to avoid that
because it makes the library interface less explicit and usually it
results in exporting more things than I want to. I usually export
class members individually. If the class also needs to be an exception
or participate in dynamic_casts you can mark it with MY_LIB_API (and
not mark any members). Although it's probably still better to mark the
class with BOOST_SYMBOL_VISIBLE (in addition to marking the exported
members with MY_LIB_API).
There are quirks with regard to where to use MY_LIB_API - in symbol
declaration, definition or both. At least some MSVC versions may
silently ignore the export attribute if it's not used where needed.
This may be a bug or there may be an explanation somewhere, I don't
know. From my practice you should mark both declaration and definition
of functions to work around that. When exporting a function template
specialization, you have to mark the declaration and explicit
instantiation of the template (but not the template definition). You
can find a few examples in Boost.Log .
Getting back to BOOST_SYMBOL_VISIBLE and MinGW, I'm not sure what
effect it has there, but I think it should be close to none. In any
case, it should not export anything because it is not needed in the
contexts where the macro should be used, and where exporting is needed
MY_LIB_API should be used instead. Then again, there are multiple
flavors of MinGW out there, including the legacy MinGW32 where some
GCC versions were broken wrt exceptions and dynamic_casts (which used
type info addresses, like on Linux). If you're having problems with
such broken MinGW then you have my condolences; I don't think you can
work around it without crippling the user's code (basically, you'll
have to reimplement part of the compiler runtime). I would recommend
using a more recent GCC and MinGW64 instead.
I hope it helps.