Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT sourceware DOT cygnus DOT com Delivered-To: mailing list cygwin AT sourceware DOT cygnus DOT com Message-ID: <3846779F.803F83C4@kapp-coburg.de> Date: Thu, 02 Dec 1999 14:43:59 +0100 From: Alexander Mader Organization: NILES Werkzeugmaschinenfabrik GmbH X-Mailer: Mozilla 4.6 [de] (WinNT; I) X-Accept-Language: de MIME-Version: 1.0 To: cygwin AT sourceware DOT cygnus DOT com Subject: [Fwd: SUMMARY: Dynamic linking] Content-Type: multipart/mixed; boundary="------------ACEA8F140A6A40C27EA48D4D" --------------ACEA8F140A6A40C27EA48D4D Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Hallo, some time ago James Stern posted this summary. Alexander. -- Alexander Mader Fon: +49-30-92797-556 NILES Werkzeugmaschinenfabrik GmbH --------------ACEA8F140A6A40C27EA48D4D Content-Type: message/rfc822 Content-Transfer-Encoding: 7bit Content-Disposition: inline Received: from kappusa.kapptech.com (root AT kappusa DOT kapptech DOT com [208.193.134.65]) by kappco.kapp-coburg.de with ESMTP (8.8.6 (PHNE_14041)/8.7.1) id TAA11117 for ; Thu, 26 Aug 1999 19:58:24 +0200 (METDST) Received: from egcs.cygnus.com (egcs.cygnus.com [205.180.83.80]) by kappusa.kapptech.com (8.9.3/8.9.3) with SMTP id LAA03702 for ; Thu, 26 Aug 1999 11:58:18 -0600 (MDT) Received: (qmail 29626 invoked by alias); 26 Aug 1999 17:56:43 -0000 Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT sourceware DOT cygnus DOT com Delivered-To: mailing list cygwin AT sourceware DOT cygnus DOT com Received: (qmail 29607 invoked from network); 26 Aug 1999 17:56:34 -0000 Received: from web1404.mail.yahoo.com (128.11.23.168) by egcs.cygnus.com with SMTP; 26 Aug 1999 17:56:34 -0000 Message-ID: <19990826180701 DOT 28986 DOT rocketmail AT web1404 DOT mail DOT yahoo DOT com> Received: from [199.35.46.12] by web1404.mail.yahoo.com; Thu, 26 Aug 1999 11:07:01 PDT Date: Thu, 26 Aug 1999 11:07:01 -0700 (PDT) From: James Stern Reply-To: stern AT itginc DOT com Subject: SUMMARY: Dynamic linking To: cygwin AT sourceware DOT cygnus DOT com MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii I've posted several questions to this group recently about Cygwin dynamic linking. My problems arose in an attempt to port an application from Solaris to Cygwin on NT. The application links dynamically on Solaris and runs with no problems so I naively expected a smooth NT port. However, Windows's dynamic linking works differently from Solaris's and Cygwin had to adopt the Windows rules. I haven't finished the port but I've been able to solve all the errors I've seen for the last few days. That's thanks to this list, especially to Mumit Khan and Paul Sokolovsky. Clark Sims, John R. Hanson and Chris Faylor provided some good background information. I thought now would be a good time to post a summary. I am writing this for Unix folk who are as clueless about Windows "Dynamic Link Libraries (DLLs)" as I was. I.e., completely. :-) That's why this "summary" is so long. The easiest way I know to build a DLL is via Mumit Khan's dllwrap command. But however you do it, three files are produced in a library's march toward DLL-hood: ================================================= 1. A DEF file, dll.def, which lists the exported symbols. The Windows linker requires this. The DEF file can be discarded after you've built the other two files. You can build the DEF file yourself or let dllwrap build it for you. I prefer the latter. I couldn't get dllwrap's --export-all-symbols to export everything for me from my original module but the solution was easy. I wrote a few lines of bash + gawk to generate: // export_everything.cc -- Generated file extern "C" { __declspec (dllexport) int f(); __declspec (dllexport) int g(); __declspec (dllexport) extern char v; } void never_called (void) { // Use everything to force the compiler to // generate references f(); g(); v = 'a'; } Compile this and feed export_everything.o to dllwrap along with the DLL's other object modules. The __declspec (dllexport) tag tells dllwrap to put the symbol in its generated DEF file. I use extern "C" above because the output of nm lists the mangled names and I don't want them mangled again. This would not be necessary for a C application. I had to compile a call to every function and an assignment to every variable to persuade the compiler to generate the desired external references. Also, I give every function a void argument list and declare every extern as char but that doesn't matter since the statements in never_called don't get executed. 2. The DLL proper, dll.dll. This contains the actual code and data you are linking to. dllwrap creates this. 3. An "import library," libdll.a, used to link clients. The import library contains two stubs for every function f(): _f and __imp__f. The real code for f() is in dll.dll. As I understand it, a call to f() branches to the _f stub, which then calls __imp__f. __imp__f branches to the real f(), which is in dll.dll. Someone (I'm not sure who -- This may happen at program startup), ensures that dll.dll is loaded before the first call to it is made. If you declare f(): __declspec (dllimport) TYPE f(arguments); a call to f() will go directly to __imp__f, thus saving a few machine instructions. However, function calls work even without the __declspec (dllimport) tag. The situation is sadly different for variables. An extern variable, v, used in a client and defined in a DLL must be declared like this in every client source file that uses it: __declspec (dllimport) extern int v; Every DLL source file that uses it must declare it as: extern int v; And of course, one DLL source file must define the variable, e.g., as: int v = 42; An "extern" declarations usually appears in a header file, say v.h. Generally, client and DLL source files both #include "v.h" to get the declaration of v. You end up coding something like this inside v.h: VISIBILITY int v; A client source file does this: #define VISIBILITY __declspec (dllimport) #include "v.h" A DLL source file does this: #define VISIBILITY #include "v.h" If your application has a lot of extern variables, this can mean a lot of source changes. Sadly, my application does. Mumit noted that applications should avoid extern variables wherever possible. I heartily agree but I have to port the code as it is. ================================================== Summary: * Declare every exported symbol __declspec (dllexport) in at least one DLL source file. * Declare every imported variable __declspec (dllimport) in every client source file that uses it. * __declspec (dllimport) is optional for functions. If used, it will save a few machine instructions per call. * Say you have a client, main.exe, that uses dll1a.dll and dllb.dll. If you move function f() from dlla to dllb, it appears you have to: * Regenerate dlla and dllb via dllwrap. * Relink main.exe with the new libdlla.a and libdllb.a files. Otherwise, main.exe will try to get f() from dlla. * Don't do it yourself. Use dllwrap. I welcome any corrections to the above. === -- Opinions expressed above are not necessarily my employer's. James M. Stern ITG Inc. Culver City, CA (213) 270-7955 __________________________________________________ Do You Yahoo!? Bid and sell for free at http://auctions.yahoo.com -- Want to unsubscribe from this list? Send a message to cygwin-unsubscribe AT sourceware DOT cygnus DOT com --------------ACEA8F140A6A40C27EA48D4D Content-Type: text/plain; charset=us-ascii -- Want to unsubscribe from this list? Send a message to cygwin-unsubscribe AT sourceware DOT cygnus DOT com --------------ACEA8F140A6A40C27EA48D4D--