X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=docs%2Fusers_guide%2Fwin32-dlls.xml;h=7b0e726b529c8a77ee7cb1f15b40b6e6e26e6d95;hb=1c1ed8694bdd24b003fa5935d001a1835e9b0f4e;hp=22a77deef8ebf5d7cbf83521c9d6c2f0ae41c687;hpb=a8e681c1e8aa4bc602714ff61583cd4e969d7187;p=ghc-hetmet.git
diff --git a/docs/users_guide/win32-dlls.xml b/docs/users_guide/win32-dlls.xml
index 22a77de..7b0e726 100644
--- a/docs/users_guide/win32-dlls.xml
+++ b/docs/users_guide/win32-dlls.xml
@@ -71,7 +71,7 @@ Notice how the "%1" argument is quoted (or not).
This problem doesn't just affect GHCi, it affects any
GHC-compiled program that wants to catch console events. See the
GHC.ConsoleHandler
+ url="&libraryBaseLocation;/GHC-ConsoleHandler.html">GHC.ConsoleHandler
module.
@@ -210,8 +210,8 @@ make-sessions running under cygwin.
Making Haskell libraries into DLLs doesn't work on Windows at the
-moment; however, all the machinery is
-still there. If you're interested, contact the GHC team. Note that
+moment; we hope to re-instate this facility in the future
+(see ). Note that
building an entire Haskell application as a single DLL is still supported: it's
just multi-DLL Haskell programs that don't work. The Windows
distribution of GHC contains static libraries only.
@@ -295,7 +295,7 @@ option on all the Haskell modules that make up your application.
Creating a Win32 DLL
-––mk-dll
+–shared
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 a command of the form:
@@ -303,12 +303,12 @@ the DLL by issuing a command of the form:
-ghc ––mk-dll -o foo.dll bar.o baz.o wibble.a -lfooble
+ghc –shared -o foo.dll bar.o baz.o wibble.a -lfooble
-By feeding the ghc compiler driver the option , it
+By feeding the ghc compiler driver the 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.
@@ -348,12 +348,12 @@ you compile into a DLL must have a common root.
By default, the entry points of all the object files will be exported from
-the DLL when using . Should you want to constrain
+the DLL when using . Should you want to constrain
this, you can specify the module definition file to use
on the command line as follows:
-ghc ––mk-dll -o .... -optdll––def -optdllMyDef.def
+ghc –shared -o .... MyDef.def
See Microsoft documentation for details, but a module definition file
@@ -372,22 +372,22 @@ EXPORTS
-In addition to creating a DLL, the option also
+In addition to creating a DLL, the option also
creates an import library. The import library name is derived from the
name of the DLL, as follows:
-DLL: HScool.dll ==> import lib: libHScool_imp.a
+DLL: HScool.dll ==> import lib: libHScool.dll.a
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.,
libHSfoo.a and
-libHSfoo_imp.a.
+libHSfoo.dll.a.
Additionally, when the compiler driver is linking in non-static mode, it
will rewrite occurrence of on the command line to
-. By doing this for you, switching from
+. By doing this for you, switching from
non-static to static linking is simply a question of adding
to your command line.
@@ -403,13 +403,10 @@ non-static to static linking is simply a question of adding
Making DLLs to be called from other languages
-
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 Foreign Function
-Interface definition, but it can be tricky to work out how to
-combine this with DLL building, so here's an example:
-
+know. This is a special case of ; we'll deal with
+ the DLL-specific issues that arise below. Here's an example:
@@ -451,7 +448,7 @@ RTS-––a possible implementation is:
#include <windows.h>
#include <Rts.h>
-extern void__stginit_Adder(void);
+extern void __stginit_Adder(void);
static char* args[] = { "ghcDll", NULL };
/* N.B. argv arrays must end with NULL */
@@ -489,7 +486,7 @@ ghc -c dllMain.c
Construct the DLL:
-ghc ––mk-dll -o adder.dll adder.o adder_stub.o dllMain.o
+ghc –shared -o adder.dll adder.o adder_stub.o dllMain.o
@@ -521,12 +518,119 @@ the Haskell source and build the DLL.
+
+Beware of DllMain()!
+
+The body of a DllMain() function is an
+extremely dangerous place! This is because the order in which DLLs are
+unloaded when a process is terminating is unspecified. This means that
+the DllMain() for your DLL may be called when other DLLs containing
+functions that you call when de-initializing your DLL have already
+been unloaded. In other words, you can't put shutdown code inside
+DllMain(), unless your shutdown code only requires use of certain
+functions which are guaranteed to be available (see the Platform SDK
+docs for more info).
+
+In particular, if you are writing a DLL that's statically
+linked with Haskell, it is not safe to call
+hs_exit() from DllMain(), since
+hs_exit() may make use of other DLLs (see also ). What's more, if you
+wait until program shutdown to execute your deinitialisation code, Windows will have
+terminated all the threads in your program except the one calling
+DllMain(), which can cause even more
+problems.
+
+A solution is to always export Begin() and End() functions from your
+DLL, and call these from the application that uses the DLL, so that
+you can be sure that all DLLs needed by any shutdown code in your
+End() function are available when it is called.
+
+The following example is untested but illustrates the idea (please let us
+ know if you find problems with this example or have a better one). Suppose we have a DLL called Lewis which makes use of 2
+Haskell modules Bar and Zap,
+where Bar imports Zap and is
+therefore the root module in the sense of . Then the main C++ unit for the DLL would
+look something like:
+
+
+ // Lewis.cpp -- compiled using GCC
+ #include <Windows.h>
+ #include "HsFFI.h"
+
+ #define __LEWIS_DLL_EXPORT
+ #include "Lewis.h"
+
+ #include "Bar_stub.h" // generated by GHC
+ #include "Zap_stub.h"
+
+ BOOL APIENTRY DllMain( HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ ){
+ return TRUE;
+ }
+
+ extern "C"{
+
+ LEWIS_API HsBool lewis_Begin(){
+ int argc = ...
+ char *argv[] = ...
+
+ // Initialize Haskell runtime
+ hs_init(&argc, &argv);
+
+ // Tell Haskell about all root modules
+ hs_add_root(__stginit_Bar);
+
+ // do any other initialization here and
+ // return false if there was a problem
+ return HS_BOOL_TRUE;
+ }
+
+ LEWIS_API void lewis_End(){
+ hs_exit();
+ }
+
+ LEWIS_API HsInt lewis_Test(HsInt x){
+ // use Haskell functions exported by
+ // modules Bar and/or Zap
+
+ return ...
+ }
+
+ } // extern "C"
+
+and some application which used the functions in the DLL would have a main() function like:
+
+ // MyApp.cpp
+ #include "stdafx.h"
+ #include "Lewis.h"
+
+ int main(int argc, char *argv[]){
+ if (lewis_Begin()){
+ // can now safely call other functions
+ // exported by Lewis DLL
+
+ }
+ lewis_End();
+ return 0;
+ }
+
+
+Lewis.h would have to have some appropriate #ifndef to ensure that the
+Haskell FFI types were defined for external users of the DLL (who
+wouldn't necessarily have GHC installed and therefore wouldn't have
+the include files like HsFFI.h etc).
+
+
+