DLL examples for Cygwin gcc-2.95.3 and binutils-20011002 (or later)
See also binutils.README
===============================================================

Original Author:
Mumit Khan <URL:mailto:khan@xraylith.wisc.edu>
<URL:http://www.xraylith.wisc.edu/~khan/>

Current Author:
Charles Wilson <URL:mailto:cwilson@ece.gatech.edu>
<URL:http://www.neuro.gatech.edu/users/cwilson/cygutils/>

Last Change: Sat 03 Aug 2002
An up-to-date version of this document can be found at:
  <URL:http://www.neuro.gatech.edu/users/cwilson/cygutils/dll-stuff/

===============================================================

TOC:
  - INTRO
  - CHANGES 0.4.0 --> 0.4.1
  - CHANGES 0.2.9 --> 0.4.0
  - CHANGES 0.2.8 --> 0.2.9
  - CHANGES FROM 0.2.7
  - CHANGES FROM 0.2.6
  - CHANGES FROM 0.2.5
  - CHANGES FROM 0.2.4
  - CHANGES FROM 0.2.1
  - CHANGES FROM 0.2
  - CHANGES FROM 0.1
  - DLLWRAP DOCS
  - DLLTOOL ENHANCEMENTS
  - WRAP UP
  - EXAMPLES

INTRO:
======

Here're some examples on how to build C, C++ and F77 DLL's and client 
programs that use these DLLs. These have been tested under gcc-2.95.3-5
and binutils-20011002 on cygwin-1.3.12.  They have also been tested with
gcc2-2.95.3-8 and gcc-3.1.1-4, which are in test phase right now and have
not been officially released by the cygwin team.  Dllhelpers may also 
work with a recent mingw compiler system.  They will NOT work 
as is, with MSVC. Go back to dll-helpers-0.2.5 for a version that 
will work with MSVC.

These examples assume you have the following at the very least:
  
  - compilers  : gcc-2.95.3
                 (also gcc-3.x.x cygwin release, and gcc2-2.95.3 cygwin release
					  should work.  Currently, these are in test phase and have
					  not been officially released.)
  - binutils   : binutils-20011002
  - dllhelpers : dllhelpers-0.4.1

Very early versions of dllhelpers provided enhanced versions of dlltool
and dllwrap. These were integrated in Mingw and Cygwin distributions 
in 1998.  However, more recent mingw and Cygwin distributions wrapped 
that functionality directly into the compiler and linker, so really,
there is no need of special dll tools.

CHANGES FROM 0.4.0 to 0.4.1:
============================

Added two new (failing) examples:

  f77/attribute_testing/
  f77/auto_import_testing/

    These do not work, but if the requisite features are ever 
	 added to the g77 frontend (__attribute((  )) tagging for
	 common block variables will allow the attribute_testing
	 example to succeed.  Later, if auto_import support is 
	 added to g77, the the auto_import_testing example will
	 succeed.  auto_import depends on attribute tagging.

Modified most of the Makefiles to allow the user to override
$(CC), $(CXX), and $(FC) -- this will help when cygwin releases
the gcc-3.x package and the gcc2-2.95.3 package.  It also helps 
if you wish to use "gcc -mno-cygwin" to build these examples 
in a "mingw" way:

  First, create scripts like this:

    ---- begin mgcc ----
	 gcc -mno-cygwin $*
	 ---- end mgcc ------

    ---- begin mg++ ----
	 g++ -mno-cygwin $*
	 ---- end mgcc ------

    ---- begin mg77 ----
	 g77 -mno-cygwin $*
	 ---- end mgcc ------

  Then, set 'CC=mgcc', 'CXX=mg++', and 'FC=mg77', and run the 
  examples.

  NOTE: there are number of OTHER things you must do to 
  your environment to get 'g++ -mno-cygwin' and 'g77 -mno-cygwin' 
  to work properly -- far to many to describe here.  However,
  Once gcc2-2.95.3 and gcc-3.x.x are officially released by 
  the cygwin team, the above procedure should work out of box.

CHANGES FROM 0.2.9 to 0.4.0:
============================

Added four new examples:

  c_autotools:
  cxx_autotools:

    These require the new, auto-import-capable autotools:
    autoconf-2.52, automake-1.5, libtool-devel-20020202

  c_autotools_old:
  cxx_autotools_old:

    These can be used with old-style autotools -- but by
	 doing so, they don't use auto-import at all.  So, the 
	 dreaded __declspec() macros return...

CHANGES FROM 0.2.8 to 0.2.9:
============================

Removed the '-Wl,--enable-auto-import' option, because newer 
  (post 20010924 *cygwin*) versions of binutils turn on 
  auto-import by default.  The official binutils CVS has not
  yet accepted this change; therefore mingw users may need to
  continue to follow the pattern shown in version 0.2.8.  
  However, we hope that --enable-auto-import will be made
  default even in the official binutils CVS by November 2001.

Added a 'when_auto_import_fails' directory, showing one technique
  for working around the problem, without resorting to __declspec
  or other horrendous devices.

CHANGES FROM 0.2.7 to 0.2.8:
============================

Removed the '-Wl,--enable-auto-image-base' option.  This sometimes
  causes problems with the heap-replication-in-child function of
  cygwin1.dll; cygwin expects that cygwin1.dll will be at the same
  address in both parent and child.  With auto-image-base, it is
  possible that the auto-generated base address will conflict with
  the cygwin1.dll, and the loader will either relocate your DLL or
  the cygwin1.dll in the child's address space.  Often, it will choose
  to relocate cygwin1.dll === then things go boom.
  Therefore, you should choose:
  1) just let ld use the default base address of 0x10000000 for 
     your DLLs. This means that all of your DLL's will conflict 
	  with each other, and the windows runtime loader will have to 
	  relocate them.  However, this operation is relatively 
	  inexpensive on windows, and I don't *think* the windows 
	  runtime loader will EVER "bump" a DLL with a different desired
	  base address, when trying to load other DLLs that share 
	  a common desired base address.  That is:
	     cygwin1.dll  : desired BA = 0x61000000
		  my_dll1.dll  : desired BA = 0x10000000
		  my_dll2.dll  : desired BA = 0x10000000
     So, my_dll1 and/or my_dll2 will have to be relocated.  But,
	  I posit that the windows loader will NOT choose an address
	  that conflicts with the range desired by cygwin1.dll -- because
	  cygwin1.dll has a different desired BA than (my_dll1 & my_dll2).
	    This is the option I chose to use.
  2) Explicitly specify a base address for every DLL you build:
     -Wl,--base-address=0xXXXXXXXX.  Be careful!

Added the c_and_c++ example.  This shows that as long as you obey the
  ordinary C/C++ mixing rules ('extern "C" {...}' in C headers used by
  C++ source code), you can freely call DLL's of both C and C++ origin 
  from C code.  Also, it demonstrates that the "identical base address" 
  thing works.  Here, cygcdll.dll and cygcxxdll.dll both have a 
  'desired BA' of 0x10000000.  In my tests, on my system, cygcdll.dll 
  was loaded (first) into 0x10000000, and cygcxxdll.dll was loaded 
  (second) into 0x00330000.

CHANGES FROM 0.2.6 to 0.2.7:
============================

The 0.2.7 release has the following changes from 0.2.6:

Compiler version:
  - Require binutils at least as recent as 20010802

No longer necessary to explicitly mark dllexports or dllimports.
The new auto-import feature of binutils takes care of this.
Therefore, all special *compile* time flags (as distinguished
from *link* time flags) have been removed, as have the 
DLLIMPORT #defines and declarations.

CHANGES FROM 0.2.5 to 0.2.6:
============================

The 0.2.6 release has the following changes from 0.2.5:

Compiler version:
  - Remove support for old egcs versions.  Since the egcs-gcc
    merge, we now require gcc-2.95.2 or later.
  - Require binutils at least as recent as 20000722.

No longer use dlltool or dllwrap; directly invoke 'gcc -shared'

CHANGES FROM 0.2.4 TO 0.2.5:
============================

The 0.2.5 release has the following changes from 0.2.4:

Compiler version:
  - Remove support for egcs version < 1.1.1. Need 1.1.1 or newer. May
    still work for 1.1, but only for C and C++ and not for f77.

Packaging changes:
  - no more binaries for dlltool and dllwrap. These are now part of the
    standard compiler distributions (as of egcs-1.1.1).

Cygwin changes:
  - No more special cases for Cygwin as of b20.1.

CHANGES FROM 0.2.1 TO 0.2.4:
============================

The 0.2.4 release has the following changes from 0.2.1:

DLLWRAP changes:
  - New or dlltool options that are handled specially:
    --implib or --output-lib: This will create an import library.
    --add-stdcall-alias: See dlltool enhancement below.
    --output-def: Save the <DEF> file. Useful when no <DEF> is provided.
    --image-base: Specify an image base.
  - one stop DLL building. Now dllwrap will automatically create the DEF
    file if none is provided on the command line. Beware however that this 
    may not be what you expect (you can save the auto-generated DEF file
    by providing a --output-def <DEF> option). You can also create the
    import library in this one step by using --implib or --output-lib
    option.
  - new option "--image-base <BASEADDR>" to change the DLL image base. If
    this is not specified, then dllwrap automatically supplies an image
    base address based on the output file name. This avoids the time spent
    in relocating the DLLs. ``objdump -p <DLL> | grep ImageBase'' or
    ``dumpbin /headers <DLL> | grep "image base"'' will print the image 
    base address for the <DLL>.
  - create temporary .exp file in the current directory to avoid Borland
    IMPLIB confusion.

DLLTOOL changes:

  - new option --add-stdcall-alias: This adds aliases without @<n> for
    stdcall symbols. Useful when using LoadLibrary/GetProcAddress API.
  - the LIBRARY or NAME in DEF file is now treated properly and supplied
    as the DLL name in the import library. Command line --dllname <NAME>
    overrides it of course.
  - bug fix in LIBRARY or NAME handling in DEF files. Now can have an
    extension.

DLL example changes:
  
  - Added DOS .bat files to build the examples.
  - Remove the need for separately running dlltool to create DEF file and
    IMPORT library. Now dllwrap can do that in one shot.

CHANGES FROM 0.2 TO 0.2.1:
==========================

A memory allocation bug fix in dllwrap.

CHANGES FROM 0.1 TO 0.2:
========================

The 0.2 release has the following changes from 0.1:

DLLWRAP changes:
  - new option "--entry <ENTRY>" to change the entry point. This overrides
    the built-in defaults for various platforms and should be used only if
    you know what you're doing. DLLWRAP also tells dlltool to exclude these
    entry points from the export list.
  - The temporary filenames are created with the expected extensions (such
    as .exp, .base); this helps with --nodelete option, which also forces
    the temporary files to be created in the current directory.

DLL example changes:

  - Cygwin32 DLL initialization now uses DECLARE_CYGWIN_DLL macro defined
    in <cygwin32/cygwin_dll.h> and works without any hacks. Thanks to Stan
    Cox for his cygshared script where I found the use of this macro. 
  - Rewrite the DLL initialization code, dllinit.c, to get rid of all the
    hacks to get C++ global static initializers to run. Enhance the
    documentation in the file. The DLL initialization code is now very 
    clean and portable between EGCS (cygwin32/mingw32) and MSVC.

DLLWRAP:
========

I wrote dllwrap to replace the shell scripts that I had been using, and 
so far I'm quite happy with it. In the long run, dlltool should be folded
into the linker, and all this will become obsolete.

How does dllwrap work?
----------------------

  dllwrap, as the name suggests, is just a "wrapper" around the various
  existing tools needed to create a relocatable DLL in a single shot.
  You basically invoke it as something like the following:
    
    % dllwrap -o foo.dll --def app.def a.o b.o c.o dllinit.o
  
  And, dllwrap will run the following programs on i386-mingw32:

    gcc -Wl,--base-file,<base_file> -mdll -Wl,-e,_DllMainCRTStartup@12 \
	-o foo.dll a.o b.o c.o dllinit.o
    dlltool --base-file <base_file> --output-exp <exp_file> \
	--def app.def
    gcc -Wl,--base-file,<base_file> <exp_file> -mdll \
    	-Wl,-e,_DllMainCRTStartup@12 \
	-o foo.dll a.o b.o c.o dllinit.o
    dlltool --base-file <base_file> --output-exp <exp_file>  \
	--def app.def
    gcc <exp_file> -mdll -Wl,-e,_DllMainCRTStartup@12 \
	-o foo.dll a.o b.o c.o dllinit.o

  Where <base_file> and <exp_file> are temporary files that are deleted at
  exit unless you specify '--nodelete' option.

  Note the "-mdll" option for mingw32. This is expanded by mingw32 gcc and
  passed on to the linker as "--dll -e _DllMainCRTStartup@12" and also
  causes the linker to link in dllcrt1.o instead of the usual crt1.o.

  On i386-cygwin32, some of the linker flags are a bit different; eg.,
  cygwin32 doesn't have -mdll, so normally you'll have to explicitly 
  supply the correct flags. ``dllwrap'' tries to take care of those 
  little details for you.

  So, say you run the following on i386-cygwin32:

    % dllwrap -o foo.dll --def app.def a.o b.o c.o dllinit.o
  
  And, dllwrap will run the following programs on i386-cygwin32:

    gcc -Wl,--base-file,<base_file> -Wl,--dll -nostartfiles \
        -Wl,-e,__cygwin32_dll_entry@12 \
	-o foo.dll a.o b.o c.o dllinit.o
    dlltool --base-file <base_tmpfile> --output-exp <exp_file> \
	--def app.def
    gcc -Wl,--base-file,<base_tmpfile> <exp_file> -Wl,--dll \
        -Wl,-e,__cygwin32_dll_entry@12 \
	-o foo.dll a.o b.o c.o dllinit.o
    dlltool --base-file <base_tmpfile> --output-exp <exp_file>  \
	--def app.def
    gcc <exp_file> -Wl,--dll \
        -Wl,-e,__cygwin32_dll_entry@12 \
	-o foo.dll a.o b.o c.o dllinit.o

  To recap, the default "driver" flags for mingw32 and cygwin32:
    mingw32  : -mdll
    cygwin32 : -Wl,--dll -nostartfiles

  You can override both using --driver-flags <FLAGS> option to dllwrap.

  and, the default DLL user defined entry points and the callbacks are:

    mingw32  : 
      DLL entry point      : DllMainCRTStartup	(_DllMainCRTStartup@12)
      Entry point callback : DllMain		(_DllMain@12)

    cygwin32 : _cygwin32_dll_entry
      DLL entry point      : _cygwin32_dll_entry(__cygwin32_dll_entry@12)
      Entry point callback : DllMain		(_DllMain@12)

  The linker calls the entry point, which in turn calls your callback
  routine. See the dllinit.c for examples.

  You can override the entry point using the --entry <ENTRY> option to 
  dllwrap.
  
  The tricky part is to figure out what options from the command line
  dllwrap should pass on to dlltool and what to the language driver! 
  It's a mess, but seems to work so far. Note that I usually never use 
  "ld" to create dlls or anything else for that matter, but rather use 
  gcc, c++ or g77 as appropriate which avoids lots of hassle. dllwrap
  assumes that the language driver accepts "-Wl,opt,value" options 
  which are passed onto the real thing.

  The default language driver is "gcc", but you can change that with
  --driver-name; eg., to create a C++ DLL, you should use the following:

    % dllwrap --driver-name=c++ [rest of options]

  If you're not sure what dllwrap is going to do, check out the --dry-run
  option which simply tells what programs it's going to run and what
  the various parameters it's going to pass to these programs. The 
  --verbose (or -v) option to dllwrap will show the various programs as 
  it runs them.

  Make sure you supply a export definition file to dllwrap if you want 
  your DLL to export any symbols!

Command line options:
---------------------
  
  % dllwrap --help
    Usage ./dllwrap <options> <object-files>
      Generic options:
       --quiet, -q            Work quietly
       --verbose, -v          Verbose
       --version              Print dllwrap version
       --implib <outname>     Synonym for --output-lib
      Options for ./dllwrap:
       --driver-name <driver> Defaults to "gcc"
       --driver-flags <flags> Override default ld flags
       --dlltool-name <dlltool> Defaults to "dlltool"
       --entry <entry>        Specify alternate DLL entry point
       --image-base <base>    Specify image base address
       --target <machine>     i386-cygwin32 or i386-mingw32
       --dry-run              Show what needs to be run
      Options passed to DLLTOOL:
       --machine <machine>
       --output-exp <outname> Generate export file.
       --output-lib <outname> Generate input library.
       --add-indirect         Add dll indirects to export file.
       --dllname <name>       Name of input dll to put into output lib.
       --def <deffile>        Name input .def file
       --output-def <deffile> Name output .def file
       --export-all-symbols     Export all symbols to .def
       --no-export-all-symbols  Only export .drectve symbols
       --exclude-symbols <list> Exclude <list> from .def
       --no-default-excludes    Zap default exclude symbols
       --base-file <basefile> Read linker generated base file
       --no-idata4           Don't generate idata$4 section
       --no-idata5           Don't generate idata$5 section
       -U                     Add underscores to .lib
       -k                     Kill @<n> from exported names
       --add-stdcall-alias    Add aliases without @<n>
       --as <name>            Use <name> for assembler
       --nodelete             Keep temp files.
      Rest are passed unmodified to the language driver

  The --driver-name option is used to pass the language driver name
  to dllwrap. The default is "gcc". If you're building a C++ DLL, then
  you should use ``--driver-name c++''; for F77 DLL, --driver-name g77''.
  If you don't specify a alternate language driver, then you must
  explicitly specify the language run-time libraries that you may need;
  eg., if your code needs the C++ runtime library, and you don't specify
  the C++ language driver, then you must include ``-lstdc++'' on the
  command line.

  The --driver-flags override the built-in flags passed to the linker via
  the language driver to create a dll. Only use if you know what you're
  doing. See the default driver flags in previous section.

  The --dlltool-name option are rarely needed when working natively on 
  Win32; if you're working with a cross environment however, it's very 
  useful. For example, you can use the following if you're on a Unix host:
    
    % dllwrap --driver-name=i386-mingw32-gcc \
    	--dlltool-name=i386-mingw32-dlltool \
	[rest of options]
  
  The --target option is obsolescent and should be avoided. I will at some
  point take it out.

DLLTOOL ENHANCEMENTS:
=====================

The dlltool enhancement has to do with creating export definition files.
Currently, the popular method is to do something like the following :

  app.def: $(OBJS)
	echo 'EXPORTS' > tmp.def
	-for o in $(OBJS); do \
	  $(NM) --extern-only --defined-only $$o | \
	    sed -e 's/[^ ]* [^ ]* //' -e 's/^_//' | \
	    fgrep -v DllEntryPoint | fgrep -v DllMain | \
	    fgrep -v impure_ptr >> tmp.def; \
	done
	mv tmp.def $@

It works, but it's highly error-prone. I've enhanced dlltool to do the
same using the following command :

  app.def: $(OBJS)
	$(DLLTOOL) --export-all --output-def $@ $(OBJS)

Better, isn't it? This enhancement adds the following command line
options:
  
  --export-all		exports all external and defined symbols
  --no-export-all	current behaviour (default)
  --exclude-symbols	exclude a list of comma/colon separated symbols
			from the output def file. This is useful if you
			have a DLL entry point that is not called DllMain.
  --no-default-excludes Turn of internal set of default "exclude" list.
			Current list of built-in exclude list is:
			    DllMain@12,DllEntryPoint@0,impure_ptr
  --add-stdcall-alias	This adds aliases without @<n> for stdcall symbos.
  			Only relevant when creating DEF files from a list
			of object files/archives, and you don't want to
			use the decoration when using GetProcAddress API.

Default is "--no-export-all --no-default-excludes" which is the current
behaviour.


WRAP UP:
=======

So, with these two new tools, how do you create a relocatable DLL? Here's
a sample Makefile entry (more details in the examples provided):
  
  DLL_NAME = app.dll		# created by dllwrap
  DLL_EXP_DEF = app.def		# created by enhanced dlltool
  DLL_EXP_LIB = libapp.a	# created by any version of dlltool

  DLLWRAP_FLAGS = --driver-name $(CC) --def $(DLL_EXP_DEF)

  $(DLL_NAME): $(DLL_OBJS) $(DLL_EXP_DEF)
	  $(DLLWRAP) $(DLLWRAP_FLAGS) -o $(DLL_NAME) \
	      $(DLL_OBJS) $(DLL_LDFLAGS) $(DLL_LDLIBS)

  $(DLL_EXP_LIB): $(DLL_EXP_DEF)
	  $(DLLTOOL) --dllname $(DLL_NAME) --def $(DLL_EXP_DEF) \
	      --output-lib $(DLL_EXP_LIB)

  $(DLL_EXP_DEF): $(DLL_OBJS)
	  $(DLLTOOL) --export-all --output-def $@ $(DLL_OBJS)

When "ld" is fixed to obviate the need for dlltool and the multiple
passes, you can simply change that command to use "gcc -shared" instead of
dllwrap.

EXAMPLES:
=========

There are a total of 4 (hopefully) working examples using 3 of the 4
languages directly supported by gcc/win32: C, C++ and F77 (and a 
combined C and C++ example).  As modified
in the 0.2.9 release, they work only with gcc-2.95.3 or later, and
binutils at least as recent as 20010924.

See the c++/dllclass.h file for examples of how to write new C++ code 
for egcs-1.1 and newer where you don't have to worry about a compiler 
that does not support Microsoft-style dllimport/dllexport attributes.

The F77 DLL support only works for subroutines and functions, and WILL 
NOT work for common block variables; g77 front-end currently AFAIK
provides no facility for attaching attributes to common block variables,
and I have not had time to look at what needs to be done to support it
yet. Once the front-end parser supports GCC attributes, it should be 
straightforward to add DLL support for COMMON block variables. It is
unknown whether the auto-import support will "smoothly" extend to
cover f77 DLL's with DATA exports (that is, common block variables).

The new f77/attribute_testing/ and f77/auto_import_testing/ examples
show how it *would* work once those capabilities are added to g77. 
But, they do not yet work since f77 lacks the necessary features.

=================================== x ===================================

