[config] Request for BOOST_SYMBOL_IMPORT_VISIBLE ?

Hi, I propose the introduction of BOOST_SYMBOL_IMPORT_VISIBLE to Boost.Config that behaves like BOOST_SYMBOL_IMPORT in all cases except gcc (and like compilers?) where it expands to "__attribute__((visibility("default")))". I believe this is need to address the following two scenarios: (For gcc, assume all libraries are built with the following option: -fvisibility=hidden) ********** Scenario 1 ********** Export class MyException from Library A. Catch MyException in Library B, and be able to throw or rethrow it from Library B. Catch MyException in Library C. To be able to do this with gcc, MyException has to be visible from Library B since the exception handler in Library C will look for the class definition of MyException in Library B [1]. I don't believe it's possible to do this "out of the box" with Boost.Config and still support gcc and msvc libs. Conventionally, one would do the following: //--------------- //Start Library A //--------------- #ifdef MYLIB_BUILD #define MYLIB_API BOOST_SYMBOL_EXPORT #else #define MYLIB_API_BOOST_SYMBOL_IMPORT #endif class MYLIB_API MyException ... { ... }; //------------- //End Library A //------------- But this technique fails to make MyException visible from Library B with gcc. And where I to use BOOST_SYMBOL_VISIBLE instead, it would fail to export MyException from Library A with msvc. ********** Scenario 2 ********** Export class MyShape from Library A. Import class MyShape from Library A into Library B and have Library B export the following the function: MyShape & foo(); Import MyShape and foo into Library C, and Library C export the function: MyShape & bar(); To be able to do this with gcc, MyShape has to be visible from Library B and Library C [2]. Conventionally, one would do the following: //--------------- //Start Library A //--------------- #ifdef LIB_A_BUILD #define LIB_A_API BOOST_SYMBOL_EXPORT #else #define LIB_A_API_BOOST_SYMBOL_IMPORT #endif class LIB_A_API MyShape ... { ... }; //--------------- //Start Library B //--------------- #ifdef LIB_B_BUILD #define LIB_B_API BOOST_SYMBOL_EXPORT #else #define LIB_B_API_BOOST_SYMBOL_IMPORT #endif LIB_B_API MyShape & foo(); //--------------- //Start Library C //--------------- #ifdef LIB_C_BUILD #define LIB_C_API BOOST_SYMBOL_EXPORT #else #define LIB_C_API_BOOST_SYMBOL_IMPORT #endif LIB_C_API MyShape & bar(); But this leads back to the same problem/proposed solution as Scenario 1. Thanks in advance, Mostafa [1] http://gcc.gnu.org/wiki/Visibility: "Problems with C++ exceptions (please read!)", 2nd Paragraph. [2] http://gcc.gnu.org/wiki/Visibility: "Problems with C++ exceptions (please read!)", 3rd Paragraph.

Mostafa wrote:
Hi,
I propose the introduction of BOOST_SYMBOL_IMPORT_VISIBLE to Boost.Config that behaves like BOOST_SYMBOL_IMPORT in all cases except gcc (and like compilers?) where it expands to "__attribute__((visibility("default")))". I believe this is need to address the following two scenarios:
You might want to look at boost/serialization/force_include.hpp for inspiration here Robert Ramey

I propose the introduction of BOOST_SYMBOL_IMPORT_VISIBLE to Boost.Config that behaves like BOOST_SYMBOL_IMPORT in all cases except gcc (and like compilers?) where it expands to "__attribute__((visibility("default")))". I believe this is need to address the following two scenarios:
(For gcc, assume all libraries are built with the following ption: -fvisibility=hidden)
********** Scenario 1 ********** Export class MyException from Library A. Catch MyException in Library B, and be able to throw or rethrow it from Library B. Catch MyException in Library C.
I think this is a real problem, but the solution is rather cumbersome - a Boost library header would then have to support: 1) Exporting from dll. 2) Importing to executable. 3) Importing to dll and re-exporting. 4) None of the above (static lib). Looking at http://gcc.gnu.org/wiki/Visibility they suggest that 2 & 3 are the same, and both are __attribute__ ((visibility("default"))) on gcc. Sp my suggestion is that we fix the existing macros to do the right thing and change GCC's BOOST_SYMBOL_IMPORT to __attribute__ ((visibility("default"))). Thoughts? Thanks for raising this, John.

On Sat, Jan 29, 2011 at 6:47 PM, John Maddock <boost.regex@virgin.net> wrote:
[snip]
I think this is a real problem, but the solution is rather cumbersome - a Boost library header would then have to support:
1) Exporting from dll. 2) Importing to executable. 3) Importing to dll and re-exporting. 4) None of the above (static lib).
Looking at http://gcc.gnu.org/wiki/Visibility they suggest that 2 & 3 are the same, and both are __attribute__ ((visibility("default"))) on gcc. Sp my suggestion is that we fix the existing macros to do the right thing and change GCC's BOOST_SYMBOL_IMPORT to __attribute__ ((visibility("default"))).
Thoughts?
Thanks for raising this, John.
Hi, Please, read this message in discussion of symbol visibility macro: http://lists.boost.org/Archives/boost/2010/05/166764.php. It tries to explain why it's not desireable to re-export all the symbols from DSO by default. In short, the problem is a) binary compatibility, b) exaggerated symbols table. I guess it's clear what is b) bullet about. Some explanation about a) you can find in the message mentioned above. Regards

On Sat, 29 Jan 2011 08:47:46 -0800, John Maddock <boost.regex@virgin.net> wrote:
I think this is a real problem, but the solution is rather cumbersome - a Boost library header would then have to support:
1) Exporting from dll. 2) Importing to executable. 3) Importing to dll and re-exporting. 4) None of the above (static lib).
I agree, for the sake of completeness, I would expand the above list to: 1) Export from dll. 2) Import to dll. 3) Export from static lib. 4) Import to static lib. 5) Import to executable. I believe that the above covers the set of all possible imports/exports for all binary entities that Boost would be interested in. As an aside, even though I don't know of any compiler that requires 4) and 5), I included it just in case. The 5 requirements will then need to be replicated for cases where compilers differ in their handling of symbols, for example, in the case of exceptions and gcc. This may at first seem like a lot of macros, but they are rather fine grained, more coarser helper macros along the lines of the following could be provided: //Pseudo-code #define BOOST_IMPORT_EXPORT(client_api_name) \ #ifdef client_api_name ## EXPORT_FROM_DLL \ #define client_api_name BOOST_EXPORT_FROM_DLL \ #elif defined client_api_name ## IMPORT_TO_DLL \ #define client_api_name BOOST_IMPORT_TO_DLL \ #elif defined client_api_name ## EXPORT_FROM_STATIC \ #define client_api_name BOOST_EXPORT_FROM_STATIC \ #elif defined client_api_name ## IMPORT_TO_STATIC \ #define client_api_name BOOST_IMPORT_TO_STATIC \ #elif defined client_api_name ## IMPORT_TO_EXE \ #define client_api_name BOOST_IMPORT_TO_EXE \ #else \ #error No appropriate client_api_name macro defined! \ #endif Analogously, BOOST_IMPORT_EXPORT_EXCEPTION(client_api_name) would be defined in the same manner. And their usage would look like: BOOST_IMPORT_EXPORT(MY_API) BOOST_IMPORT_EXPORT_EXCEPTION(MY_API) class MY_API Shape {}; MY_API void foo(); class MY_API_EXCEPTION GeoEx {}; etc... Thoughts? Would anybody be interested in something like this? Mostafa

On Mon, 07 Feb 2011 04:34:32 -0800, John Maddock <boost.regex@virgin.net> wrote:
Thoughts? Would anybody be interested in something like this?
No, IMO unless this is obvious and easy to use then no-one will use it. My point is we need more simplicity, not more complexity.
John.
Heh, heh, heh, and I thought I was simplifying things. I'm confused, how is this: BOOST_IMPORT_EXPORT(MY_API) class MY_API Shape {}; MY_API void foo(); class MY_API_EXCEPTION GeoEx {}; (more) complex for clients? Mostafa

On Mon, Feb 7, 2011 at 7:34 AM, John Maddock <boost.regex@virgin.net> wrote:
Thoughts? Would anybody be interested in something like this?
No, IMO unless this is obvious and easy to use then no-one will use it. My point is we need more simplicity, not more complexity.
+1 --Beman

Thoughts? Would anybody be interested in something like this?
No, IMO unless this is obvious and easy to use then no-one will use it. My point is we need more simplicity, not more complexity.
And another thing... ;-) Can someone please explain what's wrong with changing BOOST_SYMBOL_IMPORT to __attribute__((visibility("default"))) ? Surely the only things that GCC can re-export in that case is RTTI info and class vtables (it doesn't have access to member function definitions after all only declarations) - and that's exactly what we want to happen right? For sure we may re-export some symbols that end up not being used, but in principle a shared library cannot know in advance what it's clients will use / need anyway? Sorry if I'm being dense. Cheers, John.

On Mon, Feb 7, 2011 at 6:46 PM, John Maddock <boost.regex@virgin.net> wrote:
And another thing... ;-)
Can someone please explain what's wrong with changing BOOST_SYMBOL_IMPORT to __attribute__((visibility("default"))) ?
Hi John, One question: what is wrong with having BOOST_SYMBOL_IMPORT defined as it is? The only issues we can have is the "malfunctioning exceptions" and "mulfunctioning dynamic_cast" operator. To overcome these, symbols should be re-exported. Could you please provide some motivation to changing BOOST_SYMBOL_IMPORT? I have 2 objections to changing BOOST_SYMBOL_IMPORT macro definition. But these are my own assumptions and I don't insist on it being 100% correct. The first objection is related to ABI. Assume following case: I have shared library A build with hidden visibility. This library uses almost all of boost dsos: filesystem, system, regex, datetime etc (this could be real-life scenario). These libraries are used as implementation detail. Assume boost version is 1.46. Assume we are changing BOOST_SYMBOL_IMPORT to "default" visibility in 1.47. After I recompile library A with boost 1.47 I have myriads of new symbols in library A binary interface. For someone it will be significant drawback. Ok, library A (built with boost 1.47) was used in different "production" projects. After that, in the new release of library A: some critical bug-fixes were implemented; dependency on boost.regex was removed. But the binary compatibility was lost at this point. It was lost because I simply changed implementation detail. Another significant drawback. The second objection is performance. The more symbol dso exports (and the higher average symbol length is) the more time is spent during library startup. Imagine example described above. I'm sure it will be noticeable to users that library A built with latest boost version (that is assumed to change BOOST_SYMBOL_EXPORT macro), loads significantly longer. You can also refer to dsohowto document by Ulrich Drepper. There is a nice example about OpenOffice.org software package. This example shows how decreasing exported symbol count could lead to improvement in startup times.
Surely the only things that GCC can re-export in that case is RTTI info and class vtables (it doesn't have access to member function definitions after all only declarations) - and that's exactly what we want to happen right? For sure we may re-export some symbols that end up not being used, but in principle a shared library cannot know in advance what it's clients will use / need anyway?
Sorry if I'm being dense.
Cheers, John.
Regards and good luck

On Tue, 08 Feb 2011 15:22:53 +0500, Alexander Arhipenko <arhipjan@gmail.com> wrote:
On Mon, Feb 7, 2011 at 6:46 PM, John Maddock <boost.regex@virgin.net> wrote:
And another thing... ;-)
Can someone please explain what's wrong with changing BOOST_SYMBOL_IMPORT to __attribute__((visibility("default"))) ?
Hi John,
One question: what is wrong with having BOOST_SYMBOL_IMPORT defined as it is? The only issues we can have is the "malfunctioning exceptions" and "mulfunctioning dynamic_cast" operator. To overcome these, symbols should be re-exported. Could you please provide some motivation to changing BOOST_SYMBOL_IMPORT?
I have 2 objections to changing BOOST_SYMBOL_IMPORT macro definition. But these are my own assumptions and I don't insist on it being 100% correct.
The first objection is related to ABI. Assume following case: I have shared library A build with hidden visibility. This library uses almost all of boost dsos: filesystem, system, regex, datetime etc (this could be real-life scenario). These libraries are used as implementation detail. Assume boost version is 1.46. Assume we are changing BOOST_SYMBOL_IMPORT to "default" visibility in 1.47. After I recompile library A with boost 1.47 I have myriads of new symbols in library A binary interface. For someone it will be significant drawback. Ok, library A (built with boost 1.47) was used in different "production" projects. After that, in the new release of library A: some critical bug-fixes were implemented; dependency on boost.regex was removed. But the binary compatibility was lost at this point. It was lost because I simply changed implementation detail. Another significant drawback.
The second objection is performance. The more symbol dso exports (and the higher average symbol length is) the more time is spent during library startup. Imagine example described above. I'm sure it will be noticeable to users that library A built with latest boost version (that is assumed to change BOOST_SYMBOL_EXPORT macro), loads significantly longer. You can also refer to dsohowto document by Ulrich Drepper. There is a nice example about OpenOffice.org software package. This example shows how decreasing exported symbol count could lead to improvement in startup times.
Could you compile with -fvisibility-ms-compat and what problems does it have?

On Tue, Feb 8, 2011 at 12:42 PM, Ilya Sokolov <ilyasokol@gmail.com> wrote: [snip]
Could you compile with -fvisibility-ms-compat and what problems does it have?
Sorry, I haven't understood your question completely. What problems are you refering to: exception/dynamic_cast malfunctioning or any other? Regards

One question: what is wrong with having BOOST_SYMBOL_IMPORT defined as it is? The only issues we can have is the "malfunctioning exceptions" and "mulfunctioning dynamic_cast" operator. To overcome these, symbols should be re-exported. Could you please provide some motivation to changing BOOST_SYMBOL_IMPORT?
It's to fix those two issue. Note that as library authors *we have no way of knowing when re-export is required*, but re-export requires a change to *our headers*. That's the fundamental issue we're trying to solve.
I have 2 objections to changing BOOST_SYMBOL_IMPORT macro definition. But these are my own assumptions and I don't insist on it being 100% correct.
The first objection is related to ABI. Assume following case: I have shared library A build with hidden visibility. This library uses almost all of boost dsos: filesystem, system, regex, datetime etc (this could be real-life scenario). These libraries are used as implementation detail. Assume boost version is 1.46. Assume we are changing BOOST_SYMBOL_IMPORT to "default" visibility in 1.47. After I recompile library A with boost 1.47 I have myriads of new symbols in library A binary interface. For someone it will be significant drawback. Ok, library A (built with boost 1.47) was used in different "production" projects. After that, in the new release of library A: some critical bug-fixes were implemented; dependency on boost.regex was removed. But the binary compatibility was lost at this point. It was lost because I simply changed implementation detail. Another significant drawback.
Nod, good points, I think that's a real drawback.
The second objection is performance. The more symbol dso exports (and the higher average symbol length is) the more time is spent during library startup. Imagine example described above. I'm sure it will be noticeable to users that library A built with latest boost version (that is assumed to change BOOST_SYMBOL_EXPORT macro), loads significantly longer. You can also refer to dsohowto document by Ulrich Drepper. There is a nice example about OpenOffice.org software package. This example shows how decreasing exported symbol count could lead to improvement in startup times.
Sure, the question I'm still looking for someone to answer, is "what does re-exporting actually do to increase startup bloat"? Remember the .so that's doing the re-exporting doesn't have access to the definitions of re-exported classes, only the declaration. So presumably (based on no evidence at all!) only RTTI info for polymorphic classes will be re-exported, which is pretty much what we want to have happen anyway? OK, I see these options: 1) Do nothing, have the user set whatever macro is used to control *exporting* symbols from a Boost .so when they want to re-export that lib. 2) Do almost nothing, but have a Boost-wide macro that changes dll-import to default visibility, and re-export all Boost symbols. 3) Re-export all imported symbols by default, but have a way to turn that off. What I'm trying to avoid is: 4) Fine grained macros that give different visibility to different symbols - we have enough trouble keeping this all working as it is! Thoughts? John.

On Tue, Feb 8, 2011 at 3:15 PM, John Maddock <boost.regex@virgin.net> wrote:
One question: what is wrong with having BOOST_SYMBOL_IMPORT defined as it is? The only issues we can have is the "malfunctioning exceptions" and "mulfunctioning dynamic_cast" operator. To overcome these, symbols should be re-exported. Could you please provide some motivation to changing BOOST_SYMBOL_IMPORT?
It's to fix those two issue.
Note that as library authors *we have no way of knowing when re-export is required*, but re-export requires a change to *our headers*.
That's the fundamental issue we're trying to solve.
I agree with you that re-export requires a change to headers. I can't fully agree on *we have no way of knowing when re-export is required*. If you export concrete class it's for sure does not require re-export. If the library has an exception class that could leave library's boundary - it should be re-exported.
[snip]
Sure, the question I'm still looking for someone to answer, is "what does re-exporting actually do to increase startup bloat"? Remember the .so that's doing the re-exporting doesn't have access to the definitions of re-exported classes, only the declaration. So presumably (based on no evidence at all!) only RTTI info for polymorphic classes will be re-exported, which is pretty much what we want to have happen anyway?
OK, I see these options:
1) Do nothing, have the user set whatever macro is used to control *exporting* symbols from a Boost .so when they want to re-export that lib. 2) Do almost nothing, but have a Boost-wide macro that changes dll-import to default visibility, and re-export all Boost symbols. 3) Re-export all imported symbols by default, but have a way to turn that off.
What I'm trying to avoid is:
4) Fine grained macros that give different visibility to different symbols - we have enough trouble keeping this all working as it is!
Thoughts?
John.
I aggree on the bullets above but have some comments. As you mentioned, boost should provide the most simplest solution. But it should also leave an option to boost user's and boost libraries maintainers on how to export/import/re-export symbols from dso. The ideal solution for me would be to have following default behavior: 1) regular symbols are exported as they are now (without re-export) 2) public exceptions are re-exported For this, boost.config should have additional macro: BOOST_SYMBOL_IMPORT_REEXPORT. It unrolls to BOOST_SYMBOL_IMPORT on platforms that provide "declspec" macros set. It unrolls to following on platforms that have "visibility" stuff: #define BOOST_SYMBOL_IMPORT_REEXPORT \ __attribute__((visibility("default")) It will be up to library's maintener to decide what symbols to export, reexport, what hide. Having current set of BOOST_SYMBOL_* macros + BOOST_SYMBOL_IMPORT_REEXPORT it's possible to implement default functionality (mentioned above) and also some more sophisticated stuff. Consider example below on how "default" export/import could be implemented. (Assume library name is A). #if defined BOOST_A_BUILD_SHLIB # define BOOST_A_DECL BOOST_SYMBOL_EXPORT # define BOOST_A_DECL_VISIBLE BOOST_A_DECL #elif defined BOOST_A_USE_SHLIB # define BOOST_A_DECL BOOST_SYMBOL_IMPORT # define BOOST_A_DECL_VISIBLE BOOST_SYMBOL_IMPORT_REEXPORT #endif namespace boost { namespace alib { class BOOST_A_DECL myclass {/*...*/}; class BOOST_A_DECL_VISIBLE myerror {/*...*/}; }} Consider more sophisticated example. A's library author could give an option to the users not to re-export any classes. If someone builds library B and links library A and defines BOOST_A_IMPORT_PRIVATE macro, no symbols will be re-exported from A library. #if defined BOOST_A_IMPORT_PRIVATE # define BOOST_A_IMPORT BOOST_SYMBOL_IMPORT #else # define BOOST_A_IMPORT BOOST_SYMBOL_IMPORT_REEXPORT #endif #if defined BOOST_A_BUILD_SHLIB # define BOOST_A_DECL BOOST_SYMBOL_EXPORT # define BOOST_A_DECL_VISIBLE BOOST_A_DECL #elif defined BOOST_A_USE_SHLIB # define BOOST_A_DECL BOOST_SYMBOL_IMPORT # define BOOST_A_DECL_VISIBLE BOOST_A_IMPORT #endif namespace boost { namespace alib { class BOOST_A_DECL myclass {/*...*/}; class BOOST_A_DECL_VISIBLE myerror {/*...*/}; }} Thoughts? Regards

Alexander Arhipenko wrote:
I agree with you that re-export requires a change to headers. I can't fully agree on *we have no way of knowing when re-export is required*. If you export concrete class it's for sure does not require re-export. If the library has an exception class that could leave library's boundary -> it should be re-exported.
Is there consensus of an unambiguous, categorical list of types that require visibility attributes and which of those must be marked with default visibility (to re-export them)? So far, I think there's only limited documentation and a good deal of conjecture. I don't think "re-export" is the right term since this only applies to types that are marked with "default" visibility when the compiler's default is set to "hidden," right? That is, those compilers that use import/export needn't export something again to work, so this really hasn't anything to do with export. Thus, "re-expose" would be a more accurate term.
The ideal solution for me would be to have following default behavior:
1) regular symbols are exported as they are now (without re-export) 2) public exceptions are re-exported
For this, boost.config should have additional macro: BOOST_SYMBOL_IMPORT_REEXPORT.
That name is much too verbose. Assuming "re-export" is the accepted term, then "BOOST_SYMBOL_REEXPORT" will be sufficient.
Consider example below on how "default" export/import could be implemented. (Assume library name is A).
#if defined BOOST_A_BUILD_SHLIB # define BOOST_A_DECL BOOST_SYMBOL_EXPORT # define BOOST_A_DECL_VISIBLE BOOST_A_DECL
This has no bearing on the resulting code, but I'd s/BOOST_A_DECL/BOOST_SYMBOL_EXPORT/ because that's what's really meant as the definition of BOOST_A_DECL_VISIBLE.
#elif defined BOOST_A_USE_SHLIB # define BOOST_A_DECL BOOST_SYMBOL_IMPORT # define BOOST_A_DECL_VISIBLE BOOST_SYMBOL_IMPORT_REEXPORT #endif
namespace boost { namespace alib {
class BOOST_A_DECL myclass {/*...*/}; class BOOST_A_DECL_VISIBLE myerror {/*...*/};
}}
Assuming the right types are so marked, that certainly looks easy enough.
Consider more sophisticated example. A's library author could give an option to the users not to re-export any classes. If someone builds library B and links library A and defines BOOST_A_IMPORT_PRIVATE macro, no symbols will be re-exported from A library.
#if defined BOOST_A_IMPORT_PRIVATE # define BOOST_A_IMPORT BOOST_SYMBOL_IMPORT #else # define BOOST_A_IMPORT BOOST_SYMBOL_IMPORT_REEXPORT #endif
Are there going to be enough symbols in any Boost library to make that important? I suppose it gives some means to hide Boost as an implementation detail, but this may well be undue complication. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On Sat, Jan 29, 2011 at 2:37 AM, Mostafa <mostafa_working_away@yahoo.com> wrote:
Hi,
I propose the introduction of BOOST_SYMBOL_IMPORT_VISIBLE to Boost.Config that behaves like BOOST_SYMBOL_IMPORT in all cases except gcc (and like compilers?) where it expands to "__attribute__((visibility("default")))". [snip]...
Hi Mostafa, I completely understood your motivation and use case of scenario A). You need to re-export exception in order to catch it in the others dsos. More precisely, Lib A can throw exception a_error. Lib B uses Lib A's functions that potentially can throw a_error. Lib C uses Lib B's functionality and know that it can throw a_error among the others. Lib C want to catch a_error and make something about it (e.g., log a message). For this you need to reexport a_error from Lib B. (I wrote down the above in order to be sure that we are talking about the same things, please correct me if I'm wrong). For such case you should have separate macro for a_error class, e.g.: LIB_A_EXCEPTION. I would implement it using current boost.config like this: //library's A pseudo config.hpp file //when we are building shared library A #if defined LIB_A_BUILD_SHLIB # if defined __GNUC___ || defined __INTEL_COMPILER //etc # define LIB_A_EXCEPTION BOOST_SYMBOL_VISIBLE # else # define LIB_A_EXCEPTION BOOST_SYMBOL_EXPORT # endif # define LIB_A_DECL BOOST_SYMBOL_EXPORT #endif //when we are using shared library A #if defined LIB_A_USE_SHLIB # if defined __GNUC__ || defined __INTEL_COMPILER //etc... # define LIB_A_EXCEPTION BOOST_SYMBOL_VISIBLE # else # define LIB_A_EXCEPTION BOOST_SYMBOL_IMPORT # endif # define LIB_A_DECL BOOST_SYMBOL_IMPORT #endif The problem about this solution is that it is: 1) Low-level (refers directly to compiler macros) 2) Contains a lot of boilerplate code that could be eliminted The more elegant solution would be to have (as you are proposing) special macroses in boost.config. BOOST_SYMBOL_VISIBLE is okay but it does nothing on msvc. So, I propose to have 2 new macroses: BOOST_SYMBOL_VISIBLE_EXPORT//export "always" visible symbol from the library BOOST_SYMBOL_VISIBLE_IMPORT//import "always" visible symbol to the library They will be implemented like following: #if defined _MSC_VER //|| defined the others that uses declspec macro family # define BOOST_SYMBOL_VISIBLE_EXPORT BOOST_SYMBOL_EXPORT # define BOOST_SYMBOL_VISIBLE_IMPORT BOOST_SYMBOL_IMPORT #else # define BOOST_SYMBOL_VISIBLE_EXPORT BOOST_SYMBOL_EXPORT # define BOOST_SYMBOL_VISIBLE_IMPORT BOOST_SYMBOL_EXPORT #endif Having such macroses in boost.config we could significantly simplify the example above: //library's A pseudo config.hpp file //when we are building shared library A #if defined LIB_A_BUILD_SHLIB # define LIB_A_EXCEPTION BOOST_SYMBOL_VISIBLE_EXPORT # define LIB_A_DECL BOOST_SYMBOL_EXPORT #endif //when we are using shared library A #if defined LIB_A_USE_SHLIB # define LIB_A_EXCEPTION BOOST_SYMBOL_VISIBLE_IMPORT # define LIB_A_DECL BOOST_SYMBOL_IMPORT #endif Boosters, what do you think? Mostafa, unfortunately I did not completely understand scenario 2). Am I correct that you want to export function foo from B library, function bar from C library? All of them return reference to MyShape that resides in library A. Why not require B's, C's users to link library A? I guess it's possible to re-export MyShape from B and C library on gcc platform but can't be easily achived on msvc. Regards

On Mon, 31 Jan 2011 07:00:50 -0800, Alexander Arhipenko <arhipjan@gmail.com> wrote:
Mostafa, unfortunately I did not completely understand scenario 2). Am I correct that you want to export function foo from B library, function bar from C library? All of them return reference to MyShape that resides in library A. Why not require B's, C's users to link library A? I guess it's possible to re-export MyShape from B and C library on gcc platform but can't be easily achived on msvc.
You're right, the correct solution is to have users of Library C link to both Library B and Library A. (I had an incorrect fear that depending on the order of linking, Library B would somehow hide Library A's symbols when they linked to Library C.) Mostafa

On Mon, 31 Jan 2011 07:00:50 -0800, Alexander Arhipenko <arhipjan@gmail.com> wrote:
On Sat, Jan 29, 2011 at 2:37 AM, Mostafa <mostafa_working_away@yahoo.com> wrote:
Hi,
I propose the introduction of BOOST_SYMBOL_IMPORT_VISIBLE to Boost.Config that behaves like BOOST_SYMBOL_IMPORT in all cases except gcc (and like compilers?) where it expands to "__attribute__((visibility("default")))". [snip]...
[snip]
The more elegant solution would be to have (as you are proposing) special macroses in boost.config. BOOST_SYMBOL_VISIBLE is okay but it does nothing on msvc.
That's the problem I ran into. On msvc, it's ok if all you want to do is catch the exception outside of the defining dll, but if you want to export the said exception and throw outside of the dll, then you need to export/import from the dll. It seems to me, from having gone back and read the discussion threads on this topic, that BOOST_SYMBOL_VISIBLE was sort of a gcc specific addition to enable re-exporting exceptions from gcc dso's. In the least, I believe that your proposal below should completely replace BOOST_SYMBOL_VISIBLE, as it takes into account both gcc and msvc.
So, I propose to have 2 new macroses: BOOST_SYMBOL_VISIBLE_EXPORT//export "always" visible symbol from the library BOOST_SYMBOL_VISIBLE_IMPORT//import "always" visible symbol to the library
Mostafa

On Mon, 07 Feb 2011 00:10:26 -0800, Mostafa <mostafa_working_away@yahoo.com> wrote:
On Mon, 31 Jan 2011 07:00:50 -0800, Alexander Arhipenko <arhipjan@gmail.com> wrote:
On Sat, Jan 29, 2011 at 2:37 AM, Mostafa <mostafa_working_away@yahoo.com> wrote:
Hi,
I propose the introduction of BOOST_SYMBOL_IMPORT_VISIBLE to Boost.Config that behaves like BOOST_SYMBOL_IMPORT in all cases except gcc (and like compilers?) where it expands to "__attribute__((visibility("default")))". [snip]...
[snip]
The more elegant solution would be to have (as you are proposing) special macroses in boost.config. BOOST_SYMBOL_VISIBLE is okay but it does nothing on msvc.
That's the problem I ran into. On msvc, it's ok if all you want to do is catch the exception outside of the defining dll, but if you want to export the said exception and throw outside of the dll, then you need to export/import from the dll. It seems to me, from having gone back and read the discussion threads on this topic, that BOOST_SYMBOL_VISIBLE was sort of a gcc specific addition to enable re-exporting exceptions from gcc dso's. In the least, I believe that your proposal below should completely replace BOOST_SYMBOL_VISIBLE, as it takes into account both gcc and msvc.
So, I propose to have 2 new macroses: BOOST_SYMBOL_VISIBLE_EXPORT//export "always" visible symbol from the library BOOST_SYMBOL_VISIBLE_IMPORT//import "always" visible symbol to the library
Mostafa
Though I suggest the names: BOOST_SYMBOL_EXCEPTION_EXPORT BOOST_SYMBOL_EXCEPTION_IMPORT to emphasize that this macros should be only used with exceptions. Having BOOST_SYMBOL_EXPORT and BOOST_SYMBOL_VISIBLE_EXPORT is kind of confusing, whereas the names BOOST_SYMBOL_EXPORT and BOOST_SYMBOL_EXCEPTION_EXPORT are self-explanatory, I don't need the look up reference manual to figure out what they do when I'm scanning code. Any thoughts? Regards, Mostafa

So, I propose to have 2 new macroses: BOOST_SYMBOL_VISIBLE_EXPORT//export "always" visible symbol from the library BOOST_SYMBOL_VISIBLE_IMPORT//import "always" visible symbol to the library
Mostafa
Though I suggest the names:
BOOST_SYMBOL_EXCEPTION_EXPORT BOOST_SYMBOL_EXCEPTION_IMPORT
to emphasize that this macros should be only used with exceptions. Having BOOST_SYMBOL_EXPORT and BOOST_SYMBOL_VISIBLE_EXPORT is kind of confusing, whereas the names BOOST_SYMBOL_EXPORT and BOOST_SYMBOL_EXCEPTION_EXPORT are self-explanatory, I don't need the look up reference manual to figure out what they do when I'm scanning code.
Any thoughts?
Is this really just limited to exception classes? I got the impression from the GCC docs that the issue might extend to: * Classes with vtables that are used in dynamic_cast's or with typeid. * Classes with static data members. I still think that re-exporting "just enough and no more" is error prone, and we should just follow the gcc guidelines and re-export everything that's imported - I rather got the impression that gcc will only actually generate re-export data for vtables anyway? John.

On Mon, 07 Feb 2011 02:26:34 -0800, John Maddock <boost.regex@virgin.net> wrote:
So, I propose to have 2 new macroses: BOOST_SYMBOL_VISIBLE_EXPORT//export "always" visible symbol from the library BOOST_SYMBOL_VISIBLE_IMPORT//import "always" visible symbol to the library
Mostafa
Though I suggest the names:
BOOST_SYMBOL_EXCEPTION_EXPORT BOOST_SYMBOL_EXCEPTION_IMPORT
to emphasize that this macros should be only used with exceptions. Having BOOST_SYMBOL_EXPORT and BOOST_SYMBOL_VISIBLE_EXPORT is kind of confusing, whereas the names BOOST_SYMBOL_EXPORT and BOOST_SYMBOL_EXCEPTION_EXPORT are self-explanatory, I don't need the look up reference manual to figure out what they do when I'm scanning code.
Any thoughts?
Is this really just limited to exception classes? I got the impression from the GCC docs that the issue might extend to:
* Classes with vtables that are used in dynamic_cast's or with typeid. * Classes with static data members.
From my reading of it, the "re-exporting" is limited to exception classes; albeit, the article could be clearer. This is because (again, according to the article) the catch handler looks for the exception class typeinfo in the dso that threw it, and not in the dso that originally defined the exception, hence the need to "re-export" the exception from all dsos that potentially throw it. With respect to the category of classes that you mention the "re-exporting" issue might extend to, I think the article is just advising to just export these classes, or their static data members in the first place, not "re-export" them from every dso that they appear in. BUT ...., some simple tests I performed seem to only partially validate my claim (see attached for the tests). All tests run on: OSX 10.5, gcc version 4.0.1 With respect to the dynamic_cast/typeid category, my tests revealed no need for "re-exporting", even when I compiled with "-O3" flag. With respect to template classes with static data members, my tests did reveal a need for "re-exporting". Admittedly, it would be nice if we can get some clarification from the gcc team regarding this.
I still think that re-exporting "just enough and no more" is error prone, and we should just follow the gcc guidelines and re-export everything that's imported - I rather got the impression that gcc will only actually generate re-export data for vtables anyway?
True, it may be error prone. Sorry, I can't seem to find the gcc guideline you're referring to, can you point it out? Thanks, Mostafa

Is this really just limited to exception classes? I got the impression from the GCC docs that the issue might extend to:
* Classes with vtables that are used in dynamic_cast's or with typeid. * Classes with static data members.
From my reading of it, the "re-exporting" is limited to exception classes; albeit, the article could be clearer. This is because (again, according to the article) the catch handler looks for the exception class typeinfo in the dso that threw it, and not in the dso that originally defined the exception, hence the need to "re-export" the exception from all dsos that potentially throw it.
With respect to the category of classes that you mention the "re-exporting" issue might extend to, I think the article is just advising to just export these classes, or their static data members in the first place, not "re-export" them from every dso that they appear in.
Hmmm, it's a bit vague in it's wording isn't it?
BUT ...., some simple tests I performed seem to only partially validate my claim (see attached for the tests).
All tests run on: OSX 10.5, gcc version 4.0.1
With respect to the dynamic_cast/typeid category, my tests revealed no need for "re-exporting", even when I compiled with "-O3" flag.
With respect to template classes with static data members, my tests did reveal a need for "re-exporting".
Admittedly, it would be nice if we can get some clarification from the gcc team regarding this.
I still think that re-exporting "just enough and no more" is error prone, and we should just follow the gcc guidelines and re-export everything that's imported - I rather got the impression that gcc will only actually generate re-export data for vtables anyway?
True, it may be error prone. Sorry, I can't seem to find the gcc guideline you're referring to, can you point it out?
The usual http://gcc.gnu.org/wiki/Visibility article, under "Step by Step Guide", they recommend: #define FOX_HELPER_DLL_IMPORT __attribute__ ((visibility("default"))) HTH, John.

On Tue, 08 Feb 2011 00:45:28 -0800, John Maddock <boost.regex@virgin.net> wrote:
I still think that re-exporting "just enough and no more" is error prone, and we should just follow the gcc guidelines and re-export everything that's imported - I rather got the impression that gcc will only actually generate re-export data for vtables anyway?
True, it may be error prone. Sorry, I can't seem to find the gcc guideline you're referring to, can you point it out?
The usual http://gcc.gnu.org/wiki/Visibility article, under "Step by Step Guide", they recommend:
#define FOX_HELPER_DLL_IMPORT __attribute__ ((visibility("default")))
It might well be a recommendation, again, I wish they were a little more explicit. I took it as an example of one possible way of importing/exporting, not necessarily a recommendation, or even a guideline. The wording "Place something along the lines of the following code in your master header file" leaves some room for (mis)interpretation. Maybe someone should query the gcc folks for clarification on what they recommend? Mostafa
participants (7)
-
Alexander Arhipenko
-
Beman Dawes
-
Ilya Sokolov
-
John Maddock
-
Mostafa
-
Robert Ramey
-
Stewart, Robert