diff options
author | Ben Gamari <ben@smart-cactus.org> | 2015-10-01 01:08:41 +0200 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2015-10-03 09:44:48 +0200 |
commit | 4fd6207ec6960c429e6a1bcbe0282f625010f52a (patch) | |
tree | 26e1f43199fbde80f26225f7409b5c00ce8792a9 /docs/users_guide/win32-dlls.rst | |
parent | 9ed700bb4128b1cbf59d99d725c44d7a0bfb1de6 (diff) | |
download | haskell-4fd6207ec6960c429e6a1bcbe0282f625010f52a.tar.gz |
Move user's guide to ReStructuredText
Diffstat (limited to 'docs/users_guide/win32-dlls.rst')
-rw-r--r-- | docs/users_guide/win32-dlls.rst | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/docs/users_guide/win32-dlls.rst b/docs/users_guide/win32-dlls.rst new file mode 100644 index 0000000000..b1495d9503 --- /dev/null +++ b/docs/users_guide/win32-dlls.rst @@ -0,0 +1,388 @@ +.. _win32: + +Running GHC on Win32 systems +============================ + +.. _ghc-windows: + +Starting GHC on Windows platforms +--------------------------------- + +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 ``ghci``. + +Be aware of that ``ghc`` and ``ghci`` do require filenames containing +spaces to be escaped using quotes: + +:: + + c:\ghc\bin\ghci "c:\\Program Files\\Haskell\\Project.hs" + +If the quotes are left off in the above command, ``ghci`` will interpret +the filename as two, ``c:\\\\Program`` and +``Files\\\\Haskell\\\\Project.hs``. + +.. _ghci-windows: + +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 +:base-ref:`GHC.ConsoleHandler <GHC-ConsoleHandler.html>` +module. + +.. _terminal-interaction: + +Interacting with the terminal +----------------------------- + +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 ``-optl-mwindows`` in the link step. + +.. warning:: + 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: + + :: + + Fail: <stdout>: hPutChar: failed (Bad file descriptor) + + However using Debug.Trace.trace is alright because it uses Windows + debugging output support rather than ``stderr``. + +For some reason, Mingw ships with the ``readline`` library, but not with +the ``readline`` headers. As a result, GHC (like Hugs) does not use +``readline`` for interactive input on Windows. You can get a close +simulation by using an emacs shell buffer! + +.. _library-differences: + +Differences in library behaviour +-------------------------------- + +Some of the standard Haskell libraries behave slightly differently on +Windows. + +- On Windows, the ``^Z`` 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 + ``IOExts.openFileEx`` to open a file in binary (untranslated) mode or + change an already opened file handle into binary mode using + ``IOExts.hSetBinaryMode``. The ``IOExts`` module is part of the + ``lang`` package. + +.. _ghci-cygwin: + +Using GHC (and other GHC-compiled executables) with Cygwin +---------------------------------------------------------- + +Background +~~~~~~~~~~ + +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 ``/`` is ``C:\cygwin\``). 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 ``/bin`` and ``/usr/include`` without ever explicitly +bothering with their actual location on the windows system (probably +``C:\cygwin\bin`` and ``C:\cygwin\usr\include``). + +The problem +~~~~~~~~~~~ + +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 ``/home/joe/Main.hs`` +or ``/bin/bash`` 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. + +Things to do +~~~~~~~~~~~~ + +- 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. + +- If you have to use absolute paths (beware of the innocent-looking + ``ROOT=$(pwd)`` in makefile hierarchies or configure scripts), Cygwin + provides a tool called ``cygpath`` 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 ``cygpath`` + just before they are passed to GHC and friends. + +- If you don't have ``cygpath``, 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: + + :: + + $ echo "Directory.getCurrentDirectory >>= putStrLn . init . tail . show " | ghci + +.. _win32-dlls: + +Building and using Win32 DLLs +----------------------------- + +Dynamic link libraries, Win32 DLLs, Win32 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. + +There are two distinct ways in which DLLs can be used: + +- You can turn each Haskell package into a DLL, so that multiple + Haskell executables using the same packages can share the DLL files. + (As opposed to linking the libraries statically, which in effect + creates a new copy of the RTS and all libraries for each executable + produced.) + + That is the same as the dynamic linking on other platforms, and it is + described in :ref:`using-shared-libs`. + +- You can package up a complete Haskell program as a DLL, to be called + by some external (usually non-Haskell) program. This is usually used + to implement plugins and the like, and is described below. + +.. _win32-dlls-create: + +Creating a DLL +~~~~~~~~~~~~~~ + +Creating a Win32 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: + +:: + + ghc -shared -o foo.dll bar.o baz.o wibble.a -lfooble + +By feeding the ghc compiler driver the option ``-shared``, 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. + +A couple of things to notice: + +- By default, the entry points of all the object files will be exported + from the DLL when using ``-shared``. Should you want to constrain + this, you can specify the *module definition file* to use on the + command line as follows: + + :: + + ghc -shared -o .... MyDef.def + + 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: + + :: + + EXPORTS + DllCanUnloadNow = DllCanUnloadNow@0 + DllGetClassObject = DllGetClassObject@12 + DllRegisterServer = DllRegisterServer@0 + DllUnregisterServer = DllUnregisterServer@0 + +- In addition to creating a DLL, the ``-shared`` 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.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.dll.a``. Additionally, + when the compiler driver is linking in non-static mode, it will + rewrite occurrence of ``-lHSfoo`` on the command line to + ``-lHSfoo.dll``. By doing this for you, switching from non-static to + static linking is simply a question of adding ``-static`` to your + command line. + +.. _win32-dlls-foreign: + +Making DLLs to be called from other languages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section describes how to create DLLs to be called from other +languages, such as Visual Basic or C++. This is a special case of +:ref:`ffi-library`; we'll deal with the DLL-specific issues that arise +below. Here's an example: + +Use foreign export declarations to export the Haskell functions you want +to call from the outside. For example: + +:: + + -- Adder.hs + {-# LANGUAGE ForeignFunctionInterface #-} + 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 + +Add some helper code that starts up and shuts down the Haskell RTS: + +:: + + // StartEnd.c + #include <Rts.h> + + void HsStart() + { + int argc = 1; + char* argv[] = {"ghcDll", NULL}; // argv must end with NULL + + // Initialize Haskell runtime + char** args = argv; + hs_init(&argc, &args); + } + + void HsEnd() + { + hs_exit(); + } + +Here, ``Adder`` 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 everything up: + +:: + + ghc -c Adder.hs + ghc -c StartEnd.c + ghc -shared -o Adder.dll Adder.o Adder_stub.o StartEnd.o + +Now the file ``Adder.dll`` can be used from other programming languages. +Before calling any functions in Adder it is necessary to call +``HsStart``, and at the very end call ``HsEnd``. + +.. warning:: + It may appear tempting to use ``DllMain`` to call + ``hs_init``/``hs_exit``, but this won't work (particularly if you + compile with ``-threaded``). There are severe restrictions on which + actions can be performed during ``DllMain``, and ``hs_init`` violates + these restrictions, which can lead to your DLL freezing during startup + (see :ghc-ticket:`3605`). + +.. _win32-dlls-vba: + +Using from VBA +^^^^^^^^^^^^^^ + +An example of using ``Adder.dll`` from VBA is: + +:: + + Private Declare Function Adder Lib "Adder.dll" Alias "adder@8" _ + (ByVal x As Long, ByVal y As Long) As Long + + Private Declare Sub HsStart Lib "Adder.dll" () + Private Declare Sub HsEnd Lib "Adder.dll" () + + Private Sub Document_Close() + HsEnd + End Sub + + Private Sub Document_Open() + HsStart + End Sub + + Public Sub Test() + MsgBox "12 + 5 = " & Adder(12, 5) + End Sub + +This example uses the ``Document_Open``/``Close`` functions of Microsoft +Word, but provided ``HsStart`` is called before the first function, and +``HsEnd`` after the last, then it will work fine. + +.. _win32-dlls-c++: + +Using from C++ +^^^^^^^^^^^^^^ + +An example of using ``Adder.dll`` from C++ is: + +:: + + // Tester.cpp + #include "HsFFI.h" + #include "Adder_stub.h" + #include <stdio.h> + + extern "C" { + void HsStart(); + void HsEnd(); + } + + int main() + { + HsStart(); + // can now safely call functions from the DLL + printf("12 + 5 = %i\n", adder(12,5)) ; + HsEnd(); + return 0; + } + +This can be compiled and run with: + +:: + + $ ghc -o tester Tester.cpp Adder.dll.a + $ tester + 12 + 5 = 17 |