libtool
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC] w32 and Libtool.


From: Peter Rosin
Subject: Re: [RFC] w32 and Libtool.
Date: Wed, 13 Oct 2010 23:53:55 +0200
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.9) Gecko/20100915 Thunderbird/3.1.4

Den 2010-10-13 20:50 skrev Ralf Wildenhues:
> Hi Peter,
> 
> * Peter Rosin wrote on Wed, Oct 13, 2010 at 08:19:27PM CEST:
>> Can you spot any errors?
> 
> See below.  I've only checked for things obvious to me; I hope somebody
> else verifies the w32 semantics and details.  ;-)

I have snipped the hunks where I agree with you review and have nothing
of value to add. I have also taken case of the nit mentioned by Vincent.

> Two spaces after period.

I consider that part of texification.

>> int one (void)
>> {
>>   return 1;
>> }
>>
>> int two (void)
>> {
>>   return 2;
>> }
>>
>> int three = 3;
> 
> Isn't this less-than fully general, in the sense that having in addition
> references to one and three from within two would possibly be more
> complex to handle?

I don't remember ever having problems with that, but I suppose two () could
be written as { return three - one (); } if that makes you sleep better.

>> an explicit __declspec(dllexport) is seen. The GNU tools is doing this
>> to not make more symbols visible for projects that have already taken
>> the trouble to decorate all symbols. There is no similar way to limit
> 
> s/all// ?  (because how can you know that it did do so for all symbols,
> when parts of the project may come from third parties?)

You have to decorate all symbols you wish to export, because if you miss
some, auto-export will have been disabled by the symbols that was indeed
decorated.  I'll still remove "all" though, because you really only need
to decorate the symbols that you wish to export, and that is typically
not *all* symbols.

>> No matching help with auto-import is provided by Libtool for neither
>> proprietary tools nor older GNU tools, so symbols *must* be decorated in
>> order to import them from a DLL for everything but contemporary GNU
>> tools on Windows.
> 
> But can we not assume that older GNU tools are irrelevant?  What would
> keep people from updating them?

I don't know. I felt that a bit of history wouldn't hurt here. Maybe I'm
just muddying the waters?

>> When the objects that form the library are built, there are generally
>> two copies built for each object. One copy is used when linking the DLL
>> and one copy is used for the static library. On Windows systems, the
>> copy used when creating the DLL is compiled with the flag -DDLL_EXPORT.
> 
>> It is common practice to also add a flag that is only present when the
>> library is built, but that will not be present when it is consumed, such
>> as -DBUILDING_LIBFOO. These defines are then used to discriminate how
>> the interface symbols should be decorated.
> 
> This seems to be a bit reversed.  From a narrative standpoint, the
> "common practice" only appears out of necessity, and the necessity has
> not been explained yet.  Right?

Right. I'll rephrase.

>> With
>> Microsoft tools you typically get away with always compiling the code as
>> if it is going to be linked with a DLL. There are cases when this does
>> not work, such as when only variables and no functions are imported from
>> the library. There is also a price connected to this liberal use of
>> imports in that an extra indirection is introduced when you are
>> consuming the static version of the library. That extra indirection is
>> always present when the DLL is consumed, but it is not needed when
>> consuming the static library.
> 
> This paragraph is fairly vague.  I understand if you don't want to tell
> all the gory details about this, but in that case maybe a pointer to
> more detailed documentation would be good here.

I don't know where this is spelled out, and it is intentionally vague as
I don't know all the answers.

>> For older GNU tools and other proprietary tools there is no generic way
>> to make it possible to consume either of the DLL or the static library
>> without user intervention, the tools needs to be told what is intended.
>> Or, to be exact, the author are not aware of any generic way. One
> 
> s/are/is/  This sounds a bit awkward still.

Don't know what to do about that.

>> assumption that has been used is that if a DLL is being built
> 
> that is commonly used?

I rephrased it differently.

>> It should be noted that there are various projects that attempt to relax
>> these requirements by various low level tricks, but they are not
>> discussed here.
> 
> Pointers?

Added.

Here's an update:


Windows DLLs.
-------------

This topic describes a couple of ways to portably create Windows Dynamic
Link Libraries (DLLs).  Libtool knows how to create DLLs using GNU tools
and using Microsoft tools.

A typical library has a "hidden" implementation with an interface
described in a header file.  On just about every system, the interface
could be something like this:

Example foo.h:

#ifndef FOO_H
#define FOO_H

int one (void);
int two (void);
extern int three;

#endif /* FOO_H */

And the implementation could be something like this:

Example foo.c:

#include "foo.h"

int one (void)
{
  return 1;
}

int two (void)
{
  return three - one ();
}

int three = 3;


When using contemporary GNU tools to create the Windows DLL, the above
code will work there too, thanks to its auto-import/auto-export
features.  But that is not the case when using older GNU tools or perhaps
more interesting when using proprietary tools.  In those cases the code
will need additional decorations on the interface symbols with
__declspec(dllimport) and __declspec(dllexport) depending on if the
library is built or if it's consumed and how it's built and consumed.

With Microsoft tools, Libtool will dig through the object files that
make up the library, looking for non-static symbols to automatically
export.  I.e., Libtool with Microsoft tools is trying to mimic the auto-
export feature of the contemporary GNU tools.  It should be noted that
the GNU auto-export feature is turned off when an explicit
__declspec(dllexport) is seen.  The GNU tools do this to not make more
symbols visible for projects that have already taken the trouble to
decorate symbols.  There is no similar way to limit which symbols are
visible in the code when Libtool is using Microsoft tools.  In order to
limit symbol visibility in that case you need to use one of the
-export-symbols or -export-symbols-regex options.

No matching help with auto-import is provided by Libtool for neither
proprietary tools nor older GNU tools, so symbols *must* be decorated in
order to import them from a DLL for everything but contemporary GNU
tools on Windows.

When the objects that form the library are built, there are generally
two copies built for each object.  One copy is used when linking the DLL
and one copy is used for the static library.  On Windows systems, a pair
of defines are commonly used to discriminate how the interface symbols
should be decorated.  The first one is -DDLL_EXPORT which is used when
building the copy of the object that is destined for the DLL.  The
second is -DBUILDING_LIBFOO (or similar) which is used when building the
library, but not when consuming the library.

However, the matching double compile is not performed when consuming
libraries.  It is therefore not possible to reliably distinguish if the
consumer is importing from a DLL or if it is going to use a static
library.  With contemporary GNU tools, auto-import often saves the day,
but see the GNU ld documentation and its --enable-auto-import option for
some corner cases when it does not.  With Microsoft tools you typically
get away with always compiling the code as if it is going to be linked
with a DLL.  There are cases when this does not work, such as when only
variables and no functions are imported from the library.  There is also
a price connected to this liberal use of imports in that an extra
indirection is introduced when you are consuming the static version of
the library.  That extra indirection is always present when the DLL is
consumed, but it is not needed when consuming the static library.

For older GNU tools and other proprietary tools there is no generic way
to make it possible to consume either of the DLL or the static library
without user intervention, the tools needs to be told what is intended.
Or, to be exact, the author is not aware of any generic way.  One common
assumption is that if a DLL is being built (DLL_EXPORT is defined) then
that DLL is going to consume any dependent libraries as DLLs.  If that
assumption is made everywhere, it is possible to select how an end-user
application is consuming libraries by adding a single flag -DDLL_EXPORT
when a DLL build is required.  This is of course an all or nothing deal,
either everything as DLLs or everything as static libraries.

To sum up the above, the header file of the foo library needs to be
changed into something like this:

Modified foo.h:

#ifndef FOO_H
#define FOO_H

#if defined _WIN32 && !defined __GNUC__
# ifdef BUILDING_LIBFOO
#  ifdef DLL_EXPORT
#   define LIBFOO_SCOPE extern __declspec (dllexport)
#  endif
# elif defined _MSC_VER || defined DLL_EXPORT
#  define LIBFOO_SCOPE extern __declspec (dllimport)
# endif
#endif
#ifndef LIBFOO_SCOPE
# define LIBFOO_SCOPE extern
#endif

LIBFOO_SCOPE int one (void);
LIBFOO_SCOPE int two (void);
LIBFOO_SCOPE int three;

#endif /* FOO_H */

It should be noted that there are various projects that attempt to relax
these requirements by various low level tricks, but they are not
discussed here.  Examples are FlexDLL(1) and edll(2).

(1) http://alain.frisch.fr/flexdll.html
(2) http://edll.sourceforge.net/



reply via email to

[Prev in Thread] Current Thread [Next in Thread]