X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=docs%2Fusers_guide%2Fwin32-dlls.xml;h=703bb1877dd636a7ef49e8d03a351b06e314068f;hp=959f7ce1b65f67a1c9690343c1e5c8d45e95682f;hb=dcf739bd7fb7de140be3bafb4ce211e2e5c7bba9;hpb=0065d5ab628975892cea1ec7303f968c3338cbe1 diff --git a/docs/users_guide/win32-dlls.xml b/docs/users_guide/win32-dlls.xml index 959f7ce..703bb18 100644 --- a/docs/users_guide/win32-dlls.xml +++ b/docs/users_guide/win32-dlls.xml @@ -2,9 +2,9 @@ Running GHC on Win32 systems - + -Starting GHC on Win32 platforms +Starting GHC on Windows platforms The installer that installs GHC on Win32 also sets up the file-suffix associations @@ -36,7 +36,46 @@ Notice how the "%1" argument is quoted (or not). - + +Running GHCi on Windows + + We recommend running GHCi in a standard Windows console: + select the GHCi option from the start menu item + added by the GHC installer, or use + Start->Run->cmd to get a Windows console and + invoke ghci from there (as long as it's in your + PATH). + + If you run GHCi in a Cygwin or MSYS shell, then the Control-C + behaviour is adversely affected. In one of these environments you + should use the ghcii.sh script to start GHCi, + otherwise when you hit Control-C you'll be returned to the shell + prompt but the GHCi process will still be running. However, even + using the ghcii.sh script, if you hit Control-C + then the GHCi process will be killed immediately, rather than + letting you interrupt a running program inside GHCi as it should. + This problem is caused by the fact that the Cygwin and MSYS shell + environments don't pass Control-C events to non-Cygwin child + processes, because in order to do that there needs to be a Windows + console. + + There's an exception: you can use a Cygwin shell if the + CYGWIN environment variable does + not contain tty. In this + mode, the Cygwin shell behaves like a Windows console shell and + console events are propagated to child processes. Note that the + CYGWIN environment variable must be set + before starting the Cygwin shell; changing it + afterwards has no effect on the shell. + + This problem doesn't just affect GHCi, it affects any + GHC-compiled program that wants to catch console events. See the + GHC.ConsoleHandler + module. + + + Interacting with the terminal @@ -63,7 +102,7 @@ You can get a close simulation by using an emacs shell buffer! - + Differences in library behaviour @@ -86,7 +125,7 @@ binary mode using IOExts.hSetBinaryMode. The - + Using GHC (and other GHC-compiled executables) with cygwin @@ -171,8 +210,7 @@ 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. 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. @@ -256,7 +294,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: @@ -264,12 +302,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. @@ -309,12 +347,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 @@ -333,22 +371,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. @@ -364,13 +402,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: @@ -412,7 +447,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 */ @@ -450,7 +485,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 @@ -482,6 +517,114 @@ 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). + + +