Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2007-01-03 11:32:47

"Robert Ramey" <ramey_at_[hidden]> writes:

> David Abrahams wrote:
>> "Robert Ramey" <ramey_at_[hidden]> writes:
>>> David Abrahams wrote:
>>>> "Emil Dotchevski" <emildotchevski_at_[hidden]> writes:
>>>>> Or did I completely misunderstand the documentation? Robert, was
>>>>> the intended meaning that *if* you explicitly call a function from
>>>>> foo.cpp, then using the class export macro guarantees that class
>>>>> foo is properly registered with the serialization library?
>>> My intention is and was that proper registration will occur whether
>>> or not the type is explicitly referred to.
>> "Whether the type is explicitly referred to" is completely irrelevant.
>> The question is whether any objects or functions from the translation
>> unit containing the EXPORT are used.
>> Did you intend that proper registration occur even if no objects or
>> functions from the translation unit containing the EXPORT are used?
> I don't see how one can determine at compile time whether or not an
> object of a particular type is going to be used.

It has nothing to do with whether an object "of a particular type" is
going to be used; it has to do with whether objects **defined in the
translation unit** are used.

> In fact, it may
> well vary from one exectution run to the next.

So what? The compiler/linker make that determination, and for code to
be stripped they don't need to determine precisely whether all objects
are used or not it's sufficient for them to be able to prove that
certain objects *won't* be used. That is sometimes provable, so
initialization code is sometimes skipped and/or stripped.

Can you answer the question?

   Did you intend that proper registration occur even if no objects or
   functions from the translation unit containing the EXPORT are used?

> suppose one is going to load an archive. The sequence of events is
> very roughly:
> a) read the export tag
> b) look it up in the extended type info table
> c) using this pointer, lookup the deserializer function
> d) and invoke them
> So the extended type info table has to be initialized with all the
> types that might be in the archive. This is what export attempts
> to do.

It doesn't do enough, and there is no portable thing it can do that
would be enough.

> But when compiled for release mode, some compilers
> drop the deseralization code. The results in a run time error
> "unregistered type". I always interpreted this as the
> compilers droping code that was never explicitly called.

That's a very imprecise way to put it. The compilers are legally
optimizing out the initialization of objects in translation units that
define no functions or objects used outside the TU. Whether or not
code is actually removed from the executable image is another matter.

> This is what occurs when we have an executable or dll which contains
> entry points never called. Some compilers provide the keyword
> "__export" to tell the compilers that such functions shouldn't be
> dropped even though they don't seem to be called. So I used these
> to be sure the the specified code didn't get dropped. Perhaps I
> should have described this but

The documentation should describe the limitations on portability of
relying on the export code being registered even if nothing else in
the TU is used, and should describe how to ensure that it does get
registered (just call a little stub function in the TU from main()).

>>> That was my goal and I believe it has been achieved for all
>>> compilers that boost supports.
>> I would be very surprised if that were the case for Metrowerks; as
>> pointed out by Emil, that compiler is very good at optimizing out
>> unused translation units.
> Well, that would explain one reason we've had so much problem
> with this comipiler - its too conforming!!!

You clearly forgot the smiley.

>> No, I don't think that is the question at all, at least, not mine. My
>> question is what promises you can legitimately make to users about
>> what will happen, and whether you have made your promises sufficiently
>> explicit.
>> ...
>> That's a legitimate thing to do, but I think you need to be very
>> explicit about what you're doing.
> Well, that's easy to fix. I guess that all we need to say is:
> a) functionality of export cannot be guarenteed to be made to work
> on all compilers.

I think that's too broad. It will work as long as you ensure
something in the TU is used.

> b) If you want your code to be guarenteed to be portable to other
> compilers, don't use export - use explicit registration instead.

Again, too broad. It's much less work to ensure the TU is used (one
stub function call) than to replace all the uses of EXPORT with
explicit registrations.

>>Do any of your tests actually exercise the
>> case where the EXPORT is in a TU with no used functions or objects?
> Well, I thought demo_pimpl did this - but I looked at it and it doesn't
> use export.
> So I checked test_exported. Its only one translation unit so it doesn't
> explicitly test this situation - the derived class constructor is called
> explicitly. this could easily be moved to another *.cpp file to test
> this.

Not a bad idea.

> I did find one thing that was new to me and very interesting:
> BOOST_CLASS_EXPORT(polymorphic_derived1)
> // MWerks users can do this to make their code work
> polymorphic_derived1)
> which I had never seen before.

Sure you have. I told you about it and asked you to look it over when
I checked in the EXPORT ordering fixes.

> I don't know if this is related in some way.

No, it's a completely separate issue.

Dave Abrahams
Boost Consulting

Boost list run by bdawes at, gregod at, cpdaniel at, john at