This is the mail archive of the cygwin@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: dll vs static importing on cygwin


Please don't send cygwin related questions to me personal.  This belongs 
on the cygwin list. I have copied the list and reset the Reply-To: 
appropriately.

prapp wrote:

> I was just reading this:
> 
> http://www.cygwin.com/ml/cygwin/2001-06/msg00447.html


The libtool macros referred to in that message are for the old-style 
libtool (called "libtool-stable" and based on libtool-1.4.2 -- see 
http://sources.redhat.com/ml/cygwin-apps/2001-12/msg00179.html for more 
info)

New-style libtool (not even in official libtool CVS yet, but Gary 
Vaughan has promised to include them "eventually"; called 
"libtool-devel" in msg00179 above) doesn't need special -Ddefines...


> 
> and follow up articles.
> 
> I'm trying to figure out how to fix a makefile
> for a unix program (lifelines.sourceforge.net, not that it
> matters) which uses ncurses, and I'm hitting what is probably
> a standard problem -- it is not linking to the dll version of
> ncurses, and therefore it fails linking. 


How do you know this?  What *exactly* is the error message?

> I don't actually
> understand why it fails linking -- (if libncurses.a is the static
> library, it should contain full code, and it ought to have all
> the symbols the dll exports too, I'd think).


Nope, you're wrong.  The static lib contains only "_foo" representing 
the foo "export".  You CAN'T link directly to the DLL -- you must use an 
import lib (GNU ld provides a mechanism where you can list the DLL on 
the link line, but you STILL aren't linking directly to the DLL; ld 
creates a virtual import lib on-the-fly and actually links your code to 
THAT.  This only works with functions, not variables)

The import lib provides a symbol "__imp__foo" (leaving questions of 
auto-import and auto-export for later; back in August there were some 
changes that simplify this whole nightmare.  I'll get to that)

OLD-STYLE
-------------------------

If your object file was compiled with a header that declared "foo" thusly:

extern __declspec(dllimport) int foo(.....)

Then the object file will attempt to link to the symbol "__imp__foo". 
OTOH, if your object file was compiled with a header that declared "foo" 
thus:

extern int foo(.....)

Then the object file will attempt to link to the symbol "_foo".  In the 
past (and present, for many packages) the header files themselves had a 
tricky set of #defines to control how symbols are declared, so that "The 
Right Thing" happens. But, it means you have to do BOTH of the following;

set the correct -Ddefines when COMPILING your object code
use the correct options when LINKING your code to the library

e.g.  for cygwin's version of libjpeg, the header files assume you want 
to link to the dll, and ensures that the symbols are declared with the 
__declspec(dllimport) modifier.   Also, GNU's ld has been modified so 
that it searches for "lib????.dll.a" BEFORE "lib????.a" in ordinary 
circumstances (although if .dll.a is not found, it will still link to .a 
-- which can be a source of problems. Unfortunately, we cannot eliminate 
this behavior because of backward compatibility issues)  Therefore, to 
build and link against the libjpeg DLL, you do this:

gcc -c myfile.c -o myfile.o
gcc -o myfile myfile.o -ljpeg

This actually links myfile.o with libjpeg.dll.a (but the RUNTIME 
dependency is satisfied by cygjpeg6b.dll).  This should be the default 
case for most client packages...

However, if you want to link statically to libjpeg, then you must do this:

gcc -DJPEG_STATIC -c myfile.c -o myfile.o
gcc -static -o myfile myfile.o -ljpeg

The -DJPEG_STATIC insures that when myfile.c includes jpeg.h, jpeg.h 
will declare the functions WITHOUT the __declspec(dllimport) modifier. 
The '-static' flag to gcc tells it (to tell ld) to search for 
"lib????.a" and NOT for "lib????.dll.a".

However, you could get undefined symbol problems if your .o was compiled 
with -DJPEG_STATIC but you linked against the .dll.a, or if your .o was 
compiled "normally" but you linked against the .a.

There are also #defines that are used to make jpeg.h declare the symbols 
with __declspec(dllexport) -- that's DLLEXPORT, not dllimport -- but 
this is only used when actually building the DLL itself.

NEW STYLE
------------------------
Back in August, Paul Sokolovsky's auto-import/auto-export functionality 
was added to GNU ld.  By cleverly adding some extra symbols to the DLL 
and to the import lib, Paul found a way to make the whole 
declspec(dllimport) thing unneccessary.  Note that ncurses as of version 
5.2-7 was built "new style".

The import lib now contains __imp__foo as well as __nm__foo.  If your 
object file "wants" __imp__foo (that is, it was compiled with 
__declspec(dllimport) modifiers on the imported symbols) then no 
problems -- everything works as before.  However, if your object file 
was compiled WITHOUT those modifiers, then it wants "_foo". That's where 
Paul's auto-import magic happens:

The __nm__* symbols contain the "devectorized" address of the import 
symbols.  If _foo isn't found, then ld adds __nm_ and links against 
THAT.  Then, during runtime, the windows PE loader will rewrite the 
address with the correct offsets so that the references to _foo become 
pointers to __imp__foo and then everything works.  (Obvious question: 
why don't you add "__imp_" and then link, instead of the "extra" step 
with __nm_?  Because it won't work.  The Windows PE loader will screw 
things up)

Okay, so what does all that mean?  For NEW STYLE dlls and import libs, 
it means the following will work:

1) header files NEVER declare symbols with __declspec(dllimport) [or 
even __declspec(dllexport)].  Symbols are always declared the same way. 
  No need for ugly -DJPEG_STATIC or -DJPEG_I_AM_BUILDING_THE_DLL or 
whatever.

2) client object files can be compiled once and then linked with either 
the import lib or the static lib.  (And when building libraries, you can 
build the object files once and then 'ar' them into a static lib or 'gcc 
-shared' them into a dll/import libpair.)

3) Just use 'gcc ...' to link with the implib or 'gcc -static ...' to 
link with the static lib.

gcc -o myfile.o myfile.c
gcc -o myfile myfile.o -ljpeg

gcc -static -o myfile-static myfile.o -ljpeg

> Maybe my problem
> is that I'm not linking to either library at link time!
> (I thought of this after typing out the rest of this email.)


Yeah, if you had provided the actual error message that gcc/ld reported, 
then we could figure that out...

REALLY OLD SUBTHREAD:
-------------------------

> re:
>  >The problem is, I really don't know how to look at a given
>  >executable, say foo.exe, which depends on bar.dll and baz.dll, and say:
>  >  Ah, yes, foo is linked by name to bar.dll, but its linked by ordinal
>  >to baz.dll.
>  >So, how can you test anything if you don't know how to 'evaluate' the
>  >results?
> 
> 
> This ought to be answerable by looking at in the PE (portable executable)
> file in the imports section. I had somewhere around a utility by Matt
> Pietrick I think that read PE format & printed out info -- I mean, with
> source code. Unfortunately I lost it. If you still have this need, I'd
> be willing to try to find it again, and see if I can look into this
> (can I tell from the imports table which way it is importing -- I think
> answer must be yes -- revise program to do so, and send you).


That would be useful.  Actually, adding this functionality to objdump 
would be better, instead of a whole new utility.  objdump is part of the 
binutils distribution.  (While you're mucking with the objdump source 
code, there's a core dump that happens in certain cases when objdumping 
new-style dll's -- search the list for more info.  Fixing that problem 
would be nice, too...)

 
> It was a sample distributed by Microsoft, and had some GPF that I had to
> fix (twice, because I lost the source & got it again before), and the fix
> is not obvious, so if I do this again, it is definitely going onto the
> development code CDs I burn & keep regularly now!


But MS copyright code is not allowed in binutils...so objdump changes 
must be "original" code, not cut-n-paste from MS samples.

  
> Anyway, I'd be grateful if you might pass on (to me) any urls or
> notes you happen to have laying about, about how to link to dll import
> libs (.dll.a), or if not, suggestions on keywords I might try in web
> searching :)


Check the cygwin-apps archive, keyword "shared static" (May 2000). 
Keyword "auto-import" (July 2001).  That's all I can think of, right now.

> $ ld --version
> GNU ld version 2.11.92 20011001
> 
> (I think that is both linker & loader, right ?)


Nope.  We use the MS Windows builtin runtime loader for both implicit 
dependencies and explicit dependencies.  (implicit: foo.exe was linked 
against "bar.dll".  explicit: foo.exe dlopen()'s "baz.dll" in order to 
access symbol "grue")  However, there is no libdl library.  Explicit 
dlopen and dlsymbol function calls are handled by cygwin1.dll -- which 
then relies on the windows runtime loader to actually load the dlopen'ed 
DLL into memory.

Also, there is no "ld.so.conf" or whatnot -- the Windows loader uses the 
executable PATH to find shared libraries (DLLs); there is no "builtin" 
shared lib search path, and LD_LIBRARY_PATH has no effect.


--Chuck


--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]