diff options
Diffstat (limited to 'docs/users_guide/win32-dlls.xml')
-rw-r--r-- | docs/users_guide/win32-dlls.xml | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/docs/users_guide/win32-dlls.xml b/docs/users_guide/win32-dlls.xml new file mode 100644 index 0000000000..959f7ce1b6 --- /dev/null +++ b/docs/users_guide/win32-dlls.xml @@ -0,0 +1,493 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<chapter id="win32"> +<title>Running GHC on Win32 systems</title> + +<sect1> +<title> +Starting GHC on Win32 platforms</title> + +<para> +The installer that installs GHC on Win32 also sets up the file-suffix associations +for ".hs" and ".lhs" files so that double-clicking them starts <command>ghci</command>. +</para> +<para> +Be aware of that <command>ghc</command> and <command>ghci</command> do +require filenames containing spaces to be escaped using quotes: +<programlisting> + c:\ghc\bin\ghci "c:\\Program Files\\Haskell\\Project.hs" +</programlisting> +If the quotes are left off in the above command, <command>ghci</command> will +interpret the filename as two, "c:\\Program" and "Files\\Haskell\\Project.hs". +</para> + +<!-- not clear whether there are current editions of Win32 OSes that + doesn't do this by default. + +<para> Solution: don't use "Open With...", avoid spaces in file names, +or fiddle with the appropriate registry setting: +<programlisting> + HKEY_CLASSES_ROOT\Unknown\shell\openas\command +</programlisting> +Notice how the "%1" argument is quoted (or not). +</para> +<para> This problem doesn't occur when double-clicking. +</para> +--> + +</sect1> + +<sect1> +<title> +Interacting with the terminal</title> + +<para>By default GHC builds applications that open a console window when they start. +If you want to build a GUI-only application, with no console window, use the flag +<literal>-optl-mwindows</literal> in the link step. +</para> + +<para> <emphasis>Warning:</emphasis> Windows GUI-only programs have no + stdin, stdout or stderr so using the ordinary Haskell + input/output functions will cause your program to fail with an + IO exception, such as: +<screen> + Fail: <stdout>: hPutChar: failed (Bad file descriptor) +</screen> + However using Debug.Trace.trace is alright because it uses + Windows debugging output support rather than stderr.</para> + +<para>For some reason, Mingw ships with the <literal>readline</literal> library, +but not with the <literal>readline</literal> headers. As a result, GHC (like Hugs) does not +use <literal>readline</literal> for interactive input on Windows. +You can get a close simulation by using an emacs shell buffer! +</para> + +</sect1> + +<sect1> +<title> +Differences in library behaviour </title> + +<para> +Some of the standard Haskell libraries behave slightly differently on Windows. + +<itemizedlist> +<listitem> <para> +On Windows, the '<literal>^Z</literal>' character is interpreted as an +end-of-file character, so if you read a file containing this character +the file will appear to end just before it. To avoid this, +use <literal>IOExts.openFileEx</literal> to open a file in binary +(untranslated) mode or change an already opened file handle into +binary mode using <literal>IOExts.hSetBinaryMode</literal>. The +<literal>IOExts</literal> module is part of the +<literal>lang</literal> package. +</para> +</listitem> +</itemizedlist> +</para> +</sect1> + +<sect1> +<title> +Using GHC (and other GHC-compiled executables) with cygwin</title> + +<sect2> +<title>Background</title> <para>The cygwin tools aim to provide a +unix-style API on top of the windows libraries, to facilitate ports of +unix software to windows. To this end, they introduce a unix-style +directory hierarchy under some root directory (typically +<filename>/</filename> is <filename>C:\cygwin\</filename>). Moreover, +everything built against the cygwin API (including the cygwin tools +and programs compiled with cygwin's ghc) will see / as the root of +their file system, happily pretending to work in a typical unix +environment, and finding things like <filename>/bin</filename> and <filename>/usr/include</filename> without +ever explicitly bothering with their actual location on the windows +system (probably <filename>C:\cygwin\bin</filename> and <filename>C:\cygwin\usr\include</filename>). +</para> +</sect2> + +<sect2><title>The problem</title> +<para>GHC, by default, no longer depends on cygwin, but is a native +windows program. It is built using mingw, and it uses mingw's ghc +while compiling your Haskell sources (even if you call it from +cygwin's bash), but what matters here is that - just like any other +normal windows program - neither GHC nor the executables it produces +are aware of cygwin's pretended unix hierarchy. GHC will happily +accept either '/' or '\' as path separators, but it won't know where +to find <filename>/home/joe/Main.hs</filename> or <filename>/bin/bash</filename> +or the like. This causes all +kinds of fun when GHC is used from within cygwin's bash, or in +make-sessions running under cygwin. +</para> +</sect2> + +<sect2><title>Things to do</title> +<itemizedlist> +<listitem> +<para> Don't use absolute paths in make, configure & co if there is any chance + that those might be passed to GHC (or to GHC-compiled programs). Relative + paths are fine because cygwin tools are happy with them and GHC accepts + '/' as path-separator. And relative paths don't depend on where cygwin's + root directory is located, or on which partition or network drive your source + tree happens to reside, as long as you 'cd' there first. +</para></listitem> + +<listitem> +<para> If you have to use absolute paths (beware of the innocent-looking + <literal>ROOT=`pwd`</literal> in makefile hierarchies or configure scripts), cygwin provides + a tool called <command>cygpath</command> that can convert cygwin's unix-style paths to their + actual windows-style counterparts. Many cygwin tools actually accept + absolute windows-style paths (remember, though, that you either need + to escape '\' or convert '\' to '/'), so you should be fine just using those + everywhere. If you need to use tools that do some kind of path-mangling + that depends on unix-style paths (one fun example is trying to interpret ':' + as a separator in path lists..), you can still try to convert paths using + <command>cygpath</command> just before they are passed to GHC and friends. +</para></listitem> + +<listitem> +<para> If you don't have <command>cygpath</command>, you probably don't have cygwin and hence + no problems with it... unless you want to write one build process for several + platforms. Again, relative paths are your friend, but if you have to use + absolute paths, and don't want to use different tools on different platforms, + you can simply write a short Haskell program to print the current directory + (thanks to George Russell for this idea): compiled with GHC, this will give + you the view of the file system that GHC depends on (which will differ + depending on whether GHC is compiled with cygwin's gcc or mingw's + gcc or on a real unix system..) - that little program can also deal with + escaping '\' in paths. Apart from the banner and the startup time, + something like this would also do: +<programlisting> + $ echo "Directory.getCurrentDirectory >>= putStrLn . init . tail . show " | ghci +</programlisting> +</para></listitem> +</itemizedlist> +</sect2> +</sect1> + + +<sect1 id="win32-dlls"> +<title>Building and using Win32 DLLs +</title> + +<para> +<emphasis>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 +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.</emphasis></para> + +<!-- +<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> + +<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> + + +<sect2 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> + +<para> +<screen> +sh$ cat main.hs +module Main where +main = putStrLn "hello, world!" +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 4608 May 3 17:11 main.exe* +sh$ ./main +hello, world! +sh$ +</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> + +<para> +4K for a <literal>"hello, world"</literal> application—not bad, huh? :-) +</para> + +</sect2> + +<sect2 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 <option>-static</option> option to link in +the code statically. +</para> + +<para> +Notice that you cannot mix code that has been compiled with +<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> + +</sect2> +--> + +<sect2 id="win32-dlls-create"> +<title>Creating a DLL</title> + +<para> +<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 a command of the form: +</para> + +<para> +<screen> +ghc ––mk-dll -o foo.dll bar.o baz.o wibble.a -lfooble +</screen> +</para> + +<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> + +<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: + +<programlisting> +EXPORTS + DllCanUnloadNow = DllCanUnloadNow@0 + DllGetClassObject = DllGetClassObject@12 + DllRegisterServer = DllRegisterServer@0 + DllUnregisterServer = DllUnregisterServer@0 +</programlisting> +</para> +</listitem> + +<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: + +<programlisting> +DLL: HScool.dll ==> 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_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_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> + +</sect2> + + +<sect2 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 <windows.h> +#include <Rts.h> + +extern void__stginit_Adder(void); + +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> +ghc -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> + +</sect2> + +</sect1> +</chapter> + +<!-- Emacs stuff: + ;;; Local Variables: *** + ;;; mode: xml *** + ;;; sgml-parent-document: ("users_guide.xml" "book" "chapter") *** + ;;; End: *** + --> |