[project @ 2001-09-04 18:29:20 by ken]
[ghc-hetmet.git] / ghc / docs / users_guide / win32-dlls.sgml
index 8c3090b..488f5bd 100644 (file)
@@ -1,31 +1,36 @@
-%************************************************************************
-%*                                                                      *
-<sect>Building and using Win32 DLLs
-<label id="win32-dlls">
-<p>
-<nidx>Dynamic link libraries, Win32</nidx>
-<nidx>DLLs, Win32</nidx>
-%*                                                                      *
-%************************************************************************
+<Chapter id="win32-dlls">
+<Title>Building and using Win32 DLLs
+</Title>
 
+<Para>
+<IndexTerm><Primary>Dynamic link libraries, Win32</Primary></IndexTerm>
+<IndexTerm><Primary>DLLs, Win32</Primary></IndexTerm>
 On Win32 platforms, the compiler is capable of both producing and using
 dynamic link libraries (DLLs) containing ghc-compiled code. This
 section shows you how to make use of this facility.
+</Para>
 
-%************************************************************************
-%*                                                                      *
-<sect1>Linking with DLLs
-<label id="win32-dlls:link">
-<p>
-%*                                                                      *
-%************************************************************************
+<Para>
+Until recently, <Command>strip</Command> didn't work reliably on DLLs, so you
+should test your version with care, or make sure you have the latest
+binutils. Unfortunately, we don't know exactly which version of binutils
+cured the problem (it was supposedly fixed some years ago).
+</Para>
 
+
+<Sect1 id="win32-dlls-link">
+<Title>Linking with DLLs
+</Title>
+
+<Para>
 The default on Win32 platforms is to link applications in such a way
 that the executables will use the Prelude and system libraries DLLs,
 rather than contain (large chunks of) them. This is transparent at the
 command-line, so 
+</Para>
 
-<tscreen><verb>
+<Para>
+<Screen>
 sh$ cat main.hs
 module Main where
 main = putStrLn "hello, world!"
@@ -33,137 +38,281 @@ sh$ ghc -o main main.hs
 ghc: module version changed to 1; reason: no old .hi file
 sh$ strip main.exe
 sh$ ls -l main.exe
--rwxr-xr-x   1 544      everyone     6144 May  3 17:11 main.exe*
+-rwxr-xr-x   1 544      everyone     4608 May  3 17:11 main.exe*
 sh$ ./main
 hello, world!
 sh$ 
-</verb></tscreen>
+</Screen>
+</Para>
+
+<Para>
+will give you a binary as before, but the <Filename>main.exe</Filename>
+generated will use the Prelude and RTS DLLs instead of linking them in
+statically.
+</Para>
 
-will give you a binary as before, but the <tt>main.exe</tt> generated
-will use the Prelude and RTS DLLs instead.
+<Para>
+4K for a <Literal>"hello, world"</Literal> application---not bad, huh? :-)
+</Para>
 
-6K for a <tt>"hello, world"</tt> application - not bad, huh? :-)
+</Sect1>
 
-%************************************************************************
-%*                                                                      *
-<sect1>Not linking with DLLs
-<label id="win32-dlls:linking-static">
-<nidx>-static option (Win32)</nidx>
-<p>
-%*                                                                      *
-%************************************************************************
+<Sect1 id="win32-dlls-linking-static">
+<Title>Not linking with DLLs
+<IndexTerm><Primary>-static option (Win32)</Primary></IndexTerm></Title>
 
+<Para>
 If you want to build an executable that doesn't depend on any
-ghc-compiled DLLs, use the <tt>-static</tt> option to link in
+ghc-compiled DLLs, use the <Option>-static</Option> option to link in
 the code statically.
+</Para>
 
+<Para>
 Notice that you cannot mix code that has been compiled with
-<tt>-static</tt> and not, so you have to use the <tt>-static</tt>
+<Option>-static</Option> and not, so you have to use the <Option>-static</Option>
 option on all the Haskell modules that make up your application.
+</Para>
 
-%************************************************************************
-%*                                                                      *
-<sect1>Creating a DLL
-<label id="win32-dlls:create">
-<p>
-<nidx>Creating a Win32 DLL</nidx>
-<nidx>--mk-dll</nidx>
-%*                                                                      *
-%************************************************************************
-
-Sealing up your Haskell library inside a DLL is quite straightforward;
+</Sect1>
+
+<Sect1 id="win32-dlls-create">
+<Title>Creating a DLL
+</Title>
+
+<Para>
+<emphasis>Making libraries into DLLs doesn't work on Windows at the
+moment (and is no longer supported); however, all the machinery is
+still there. If you're interested, contact the GHC team. Note that
+building an entire Haskell application as a DLL is still supported
+(it's just inter-DLL Haskell calls that don't work).</emphasis>
+<IndexTerm><Primary>Creating a Win32 DLL</Primary></IndexTerm>
+<IndexTerm><Primary>--mk-dll</Primary></IndexTerm>
+Sealing up your Haskell library inside a DLL is straightforward;
 compile up the object files that make up the library, and then build
-the DLL by issuing the following command:
+the DLL by issuing a command of the form:
+</Para>
 
-<tscreen><verb>
-sh$ ghc --mk-dll -o HSsuper.dll A.o Super.o B.o libmine.a -lgdi32
-</verb></tscreen>
+<Para>
+<Screen>
+ghc --mk-dll -o foo.dll bar.o baz.o wibble.a -lfooble
+</Screen>
+</Para>
 
-By feeding the ghc compiler driver the option <tt>--mk-dll</tt>, it
+<Para>
+By feeding the ghc compiler driver the option <Option>--mk-dll</Option>, it
 will build a DLL rather than produce an executable. The DLL will
 consist of all the object files and archives given on the command
 line.
+</Para>
+
+<Para>
+To create a `static' DLL, i.e. one that does not depend on the GHC DLLs,
+use the <Option>-static</Option> when compiling up your Haskell code and
+building the DLL.
+</Para>
 
+<Para>
 A couple of things to notice:
+</Para>
 
-<itemize>
-<item>
-When compiling the module <tt>A</tt>, the code emitted by the compiler
-differs depending on whether or not the functions and data it is
-importing from other Haskell modules correspond to symbols that are
-packaged up in a ghc-compiled DLL. To resolve whether such imports are
-'DLL imports' or not, the following rules are used:
-
-<itemize>
-<item>
-If the compiler imports from a module that's in the same directory as
-the one being compiled, it is assumed to not belong to a different DLL
-(or executable) than the module being processed, so none of the
-same-directory imports are considered 'DLL imports'.
-
-<item>
-If a directory contains the (probably empty) file
-<tt>dLL_ifs.hi</tt>, the code corresponding to the interface
-files found in that directory are assumed to live in a DLL
-separate from the one being compiled. 
-
-Notice that the first rule takes precedence over this one, so if
-you're compiling a module that imports from a Haskell module whose
-interface file live in the same directory, <em>and</em> that directory
-also contains the file <tt>dLL_ifs.hi</tt>, the import is still not
-being considered to be a 'DLL import'.
-
-<item>
-If compiling with the option <tt>-static</tt>, the previous rule
-is disabled.
-</itemize>
-
-So, in short, after having built your Haskell DLL, make sure you
-create the file <tt>dLL_ifs.hi</tt> in the directory that contains
-its interface files. If you don't, Haskell code that calls upon entry
-points in that DLL, will do so incorrectly, and a crash will result.
-(it is unfortunate that this isn't currently caught at compile-time).
-
-<item>
-By default, the entry points of all the object files will
-be exported from the DLL when using <tt>--mk-dll</tt>. Should you want
-to constrain this, you can specify the <em>module definition file</em>
-to use on the command line as follows:
-
-<tscreen><verb>
-sh$ ghc --mk-dll -o .... -optdll--def -optdllMyDef.def
-</verb></tscreen>
+<Para>
+
+<ItemizedList>
+<ListItem>
+<Para>
+Since DLLs correspond to packages (see <XRef LinkEnd="packages">) you need
+to use <Option>-package-name dll-name</Option> when compiling modules that
+belong to a DLL if you're going to call them from Haskell. Otherwise, Haskell
+code that calls entry points in that DLL will do so incorrectly, and crash.
+For similar reasons, you can only compile a single module tree into a DLL,
+as <Function>startupHaskell</Function> needs to be able to call its
+initialisation function, and only takes one such argument (see <XRef
+LinkEnd="win32-dlls-foreign">). Hence the modules
+you compile into a DLL must have a common root.
+</Para>
+</ListItem>
+
+<ListItem>
+<Para>
+By default, the entry points of all the object files will be exported from
+the DLL when using <Option>--mk-dll</Option>. Should you want to constrain
+this, you can specify the <Emphasis>module definition file</Emphasis> to use
+on the command line as follows:
+
+<Screen>
+ghc --mk-dll -o .... -optdll--def -optdllMyDef.def
+</Screen>
 
 See Microsoft documentation for details, but a module definition file
 simply lists what entry points you want to export. Here's one that's
 suitable when building a Haskell COM server DLL:
 
-<tscreen><verb>
+<ProgramListing>
 EXPORTS
  DllCanUnloadNow     = DllCanUnloadNow@0
  DllGetClassObject   = DllGetClassObject@12
  DllRegisterServer   = DllRegisterServer@0
  DllUnregisterServer = DllUnregisterServer@0
+</ProgramListing>
+</Para>
+</ListItem>
 
-</verb></tscreen>
-
-<item>
-In addition to creating a DLL, the <tt>--mk-dll</tt> option will also
-create an import library. The import library name is derived from the
+<ListItem>
+<Para>
+In addition to creating a DLL, the <Option>--mk-dll</Option> option also
+creates an import library. The import library name is derived from the
 name of the DLL, as follows:
 
-<tscreen><verb>
-  DLL: HScool.dll  ==> import lib: libHScool_imp.a
-</verb></tscreen>
+<ProgramListing>
+DLL: HScool.dll  ==&#62; import lib: libHScool_imp.a
+</ProgramListing>
+
+The naming scheme may look a bit weird, but it has the purpose of allowing
+the co-existence of import libraries with ordinary static libraries (e.g.,
+<Filename>libHSfoo.a</Filename> and
+<Filename>libHSfoo&lowbar;imp.a</Filename>.
+
+Additionally, when the compiler driver is linking in non-static mode, it
+will rewrite occurrence of <Option>-lHSfoo</Option> on the command line to
+<Option>-lHSfoo&lowbar;imp</Option>. By doing this for you, switching from
+non-static to static linking is simply a question of adding
+<Option>-static</Option> to your command line.
+
+</Para>
+</ListItem>
+</ItemizedList>
+</Para>
+
+</Sect1>
+
+
+<Sect1 id="win32-dlls-foreign">
+<Title>Making DLLs to be called from other languages</Title>
+
+<Para>
+
+If you want to package up Haskell code to be called from other languages,
+such as Visual Basic or C++, there are some extra things it is useful to
+know. The dirty details are in the <Emphasis>Foreign Function
+Interface</Emphasis> definition, but it can be tricky to work out how to
+combine this with DLL building, so here's an example:
+
+</Para>
+
+<ItemizedList>
+
+<ListItem>
+<Para>
+Use <Literal>foreign export</Literal> declarations to export the Haskell
+functions you want to call from the outside. For example,
+
+<ProgramListing>
+module Adder where
+
+adder :: Int -> Int -> IO Int  -- gratuitous use of IO
+adder x y = return (x+y)
+
+foreign export stdcall adder :: Int -> Int -> IO Int
+</ProgramListing>
+</Para>
+</ListItem>
+
+<ListItem>
+<Para>
+Compile it up:
+
+<Screen>
+ghc -c adder.hs -fglasgow-exts
+</Screen>
+  
+This will produce two files, adder.o and adder_stub.o
+</Para>
+</ListItem>
+
+<ListItem>
+<Para>
+compile up a <Function>DllMain()</Function> that starts up the Haskell
+RTS---a possible implementation is:
+
+<ProgramListing>
+#include &lt;windows.h&gt;
+#include &lt;Rts.h&gt;
+
+EXTFUN(__stginit_Adder);
+
+static char* args[] = { "ghcDll", NULL };
+                       /* N.B. argv arrays must end with NULL */
+BOOL
+STDCALL
+DllMain
+   ( HANDLE hModule
+   , DWORD reason
+   , void* reserved
+   )
+{
+  if (reason == DLL_PROCESS_ATTACH) {
+      /* By now, the RTS DLL should have been hoisted in, but we need to start it up. */
+      startupHaskell(1, args, __stginit_Adder);
+      return TRUE;
+  }
+  return TRUE;
+}
+</ProgramListing>
+
+Here, <Literal>Adder</Literal> is the name of the root module in the module
+tree (as mentioned above, there must be a single root module, and hence a
+single module tree in the DLL).
+
+Compile this up:
+
+<Screen>
+gcc -c dllMain.c
+</Screen>
+</Para>
+</ListItem>
+
+<ListItem>
+<Para>
+Construct the DLL:
+
+<Screen>
+ghc --mk-dll -o adder.dll adder.o adder_stub.o dllMain.o
+</Screen>
+
+</Para>
+</ListItem>
+
+<ListItem>
+<Para>
+Start using <Function>adder</Function> from VBA---here's how I would
+<Constant>Declare</Constant> it:
+
+<ProgramListing>
+Private Declare Function adder Lib "adder.dll" Alias "adder@8"
+      (ByVal x As Long, ByVal y As Long) As Long
+</ProgramListing>
+
+Since this Haskell DLL depends on a couple of the DLLs that come with GHC,
+make sure that they are in scope/visible.
+</Para>
+
+<Para>
+Building statically linked DLLs is the same as in the previous section: it
+suffices to add <Option>-static</Option> to the commands used to compile up
+the Haskell source and build the DLL.
+</Para>
+
+</ListItem>
+
+</ItemizedList>
 
-The naming scheme may look a bit weird, but it has the purpose of
-allowing the co-existence of import libraries with ordinary static
-libraries (e.g., <tt>libHSfoo.a</tt> and <tt>libHSfoo_imp.a</tt>.
+</Sect1>
 
-Additionally, when the compiler driver is linking in non-static mode,
-it will rewrite occurrence of <tt>-lHSfoo</tt> on the command line to
-<tt>-lHSfoo_imp</tt>. By doing this for you, switching from non-static
-to static linking is simply a question of adding <tt>-static</tt> to
-your command line.
+</Chapter>
 
-</itemize>
+<!-- Emacs stuff:
+     ;;; Local Variables: ***
+     ;;; mode: sgml ***
+     ;;; sgml-parent-document: ("users_guide.sgml" "book" "chapter") ***
+     ;;; End: ***
+ -->