summaryrefslogtreecommitdiff
path: root/docs/users_guide/shared_libs.xml
blob: 7d2b635d7e52945f604ead1fc06a625112459ac3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
<?xml version="1.0" encoding="iso-8859-1"?>
<sect1 id="using-shared-libs">
  <title>Using shared libraries</title>
  <indexterm><primary>Shared libraries</primary><secondary>using</secondary></indexterm>
  <indexterm><primary>Dynamic libraries</primary><secondary>using</secondary></indexterm>

  <para>
    On some platforms GHC supports building Haskell code into shared
    libraries. Shared libraries are also sometimes known as dynamic
    libraries, in particular on Windows they are referred to as dynamic link
    libraries (DLLs).
  </para>

  <para>
    Shared libraries allow a single instance of some pre-compiled code to be
    shared between several programs. In contrast, with static linking the
    code is copied into each program. Using shared libraries can thus save
    disk space. They also allow a single copy of code to be shared in memory
    between several programs that use it. Shared libraries are often used as
    a way of structuring large projects, especially where different parts are
    written in different programming languages. Shared libraries are also
    commonly used as a plugin mechanism by various applications. This is
    particularly common on Windows using COM.
  </para>

  <para>
    In GHC version 6.12 building shared libraries is supported for Linux (on
    x86 and x86-64 architectures). GHC version 7.0 adds support on Windows
    (see <xref linkend="win32-dlls"/>), FreeBSD and OpenBSD (x86 and x86-64),
    Solaris (x86) and Mac OS X (x86 and PowerPC).
  </para>

  <para>
    Building and using shared libraries is slightly more complicated than
    building and using static libraries. When using Cabal much of the detail
    is hidden, just use <literal>--enable-shared</literal> when configuring a
    package to build it into a shared library, or to link it against other
    packages built as shared libraries. The additional complexity when
    building code is to distinguish whether the code will be used in a shared
    library or will use shared library versions of other packages it depends
    on. There is additional complexity when installing and distributing
    shared libraries or programs that use shared libraries, to ensure that
    all shared libraries that are required at runtime are present in suitable
    locations.
  </para>

  <sect2>
    <title>Building programs that use shared libraries</title>
    <para>
      To build a simple program and have it use shared libraries for the
      runtime system and the base libraries use the
      <literal>-dynamic</literal> flag:
<programlisting>
ghc --make -dynamic Main.hs
</programlisting>
      This has two effects. The first is to compile the code in such a way
      that it can be linked against shared library versions of Haskell
      packages (such as base). The second is when linking, to link against
      the shared versions of the packages' libraries rather than the static
      versions. Obviously this requires that the packages were built with
      shared libraries. On supported platforms GHC comes with shared
      libraries for all the core packages, but if you install extra packages
      (e.g. with Cabal) then they would also have to be built with shared
      libraries (<literal>--enable-shared</literal> for Cabal).
    </para>
  </sect2>

  <sect2>
    <title>Shared libraries for Haskell packages</title>
    <para>
      You can build Haskell code into a shared library and make a package to be
      used by other Haskell programs. The easiest way is using Cabal, simply
      configure the Cabal package with the <literal>--enable-shared</literal>
      flag.
    </para>
    <para>
      If you want to do the steps manually or are writing your own build
      system then there are certain conventions that must be followed. Building
      a shared library that exports Haskell code, to be used by other Haskell
      code is a bit more complicated than it is for one that exports a C API
      and will be used by C code. If you get it wrong you will usually end up
      with linker errors.
    </para>
    <para>
      In particular Haskell shared libraries <emphasis>must</emphasis> be
      made into packages. You cannot freely assign which modules go in which
      shared libraries. The Haskell shared libraries must match the package
      boundaries. The reason for this is that
      GHC handles references to symbols <emphasis>within</emphasis> the same
      shared library (or main executable binary) differently from references
      to symbols <emphasis>between</emphasis> different shared libraries. GHC
      needs to know for each imported module if that module lives locally in
      the same shared lib or in a separate shared lib. The way it does this
      is by using packages. When using <literal>-dynamic</literal>, a module
      from a separate package is assumed to come from a separate shared lib,
      while modules from the same package (or the default "main" package) are
      assumed to be within the same shared lib (or main executable binary).
   </para>
    <para>
      Most of the conventions GHC expects when using packages are described
      in <xref linkend="building-packages"/>. In addition note that GHC
      expects the <literal>.hi</literal> files to use the extension
      <literal>.dyn_hi</literal>. The other requirements are the same as for
      C libraries and are described below, in particular the use of the flags
      <literal>-dynamic</literal>, <literal>-fPIC</literal> and
      <literal>-shared</literal>.
    </para>
  </sect2>

  <sect2>
    <title>Shared libraries that export a C API</title>
    <para>
      Building Haskell code into a shared library is a good way to include
      Haskell code in a larger mixed-language project. While with static
      linking it is recommended to use GHC to perform the final link step,
      with shared libraries a Haskell library can be treated just like any
      other shared library. The linking can be done using the normal system C
      compiler or linker.
    </para>
    <para>
      It is possible to load shared libraries generated by GHC in other
      programs not written in Haskell, so they are suitable for using as
      plugins. Of course to construct a plugin you will have to use the FFI
      to export C functions and follow the rules about initialising the RTS.
      See <xref linkend="ffi-library"/>. In particular you will probably want
      to export a C function from your shared library to initialise the
      plugin before any Haskell functions are called.
    </para>
    <para>
      To build Haskell modules that export a C API into a shared library use
      the <literal>-dynamic</literal>, <literal>-fPIC</literal> and
      <literal>-shared</literal> flags:
<programlisting>
ghc --make -dynamic -shared -fPIC Foo.hs -o libfoo.so
</programlisting>
      As before, the <literal>-dynamic</literal> flag specifies that this
      library links against the shared library versions of the rts and base
      package. The <literal>-fPIC</literal> flag is required for all code
      that will end up in a shared library. The <literal>-shared</literal>
      flag specifies to make a shared library rather than a program. To make
      this clearer we can break this down into separate compilation and link
      steps:
<programlisting>
ghc -dynamic -fPIC -c Foo.hs
ghc -dynamic -shared Foo.o -o libfoo.so
</programlisting>
      In principle you can use <literal>-shared</literal> without
      <literal>-dynamic</literal> in the link step. That means to
      statically link the rts all the base libraries into your new shared
      library. This would make a very big, but standalone shared library.
      On most platforms however that would require all the static libraries
      to have been built with <literal>-fPIC</literal> so that the code is
      suitable to include into a shared library and we do not do that at the
      moment.
    </para>
    <para>
      <emphasis>Warning:</emphasis> if your shared library exports a Haskell
      API then you cannot directly link it into another Haskell program and
      use that Haskell API. You will get linker errors. You must instead make
      it into a package as described in the section above.
    </para>
  </sect2>

  <sect2 id="finding-shared-libs">
    <title>Finding shared libraries at runtime</title>
    <para>
      The primary difficulty with managing shared libraries is arranging
      things such that programs can find the libraries they need at runtime.
      The details of how this works varies between platforms, in particular
      the three major systems: Unix ELF platforms, Windows and Mac OS X.
    </para>
    <sect3 id="finding-shared-libs-unix">
    <title>Unix</title>
    <para>
      On Unix there are two mechanisms. Shared libraries can be installed
      into standard locations that the dynamic linker knows about. For
      example <literal>/usr/lib</literal> or
      <literal>/usr/local/lib</literal> on most systems. The other mechanism
      is to use a "runtime path" or "rpath" embedded into programs and
      libraries themselves. These paths can either be absolute paths or on at
      least Linux and Solaris they can be paths relative to the program or
      library itself. In principle this makes it possible to construct fully
      relocatable sets of programs and libraries.
    </para>
    <para>
      GHC has a <literal>-dynload</literal> linking flag to select the method
      that is used to find shared libraries at runtime. There are currently
      two modes:
      <variablelist>
	<varlistentry>
	  <term>sysdep</term>
	  <listitem>
	    <para>
	      A system-dependent mode. This is also the default mode. On Unix
	      ELF systems this embeds
        <literal>RPATH</literal>/<literal>RUNPATH</literal> entries into the
        shared library or executable. In particular it uses absolute paths to
        where the shared libraries for the rts and each package can be found.
	      This means the program can immediately be run and it will be able to
        find the libraries it needs. However it may not be suitable for
        deployment if the libraries are installed in a different location on
        another machine.
	    </para>
	  </listitem>
	</varlistentry>
	<varlistentry>
	  <term>deploy</term>
	  <listitem>
	    <para>
	      This does not embed any runtime paths. It relies on the shared
	      libraries being available in a standard location or in a
	      directory given by the <literal>LD_LIBRARY_PATH</literal>
	      environment variable.
	    </para>
	  </listitem>
	</varlistentry>
      </variablelist>
      To use relative paths for dependent libraries on Linux and Solaris you
      can pass a suitable <literal>-rpath</literal> flag to the linker:
<programlisting>
ghc -dynamic Main.hs -o main -lfoo -L. -optl-Wl,-rpath,'$ORIGIN'
</programlisting>
      This assumes that the library <literal>libfoo.so</literal> is in the
      current directory and will be able to be found in the same directory as
      the executable <literal>main</literal> once the program is deployed.
      Similarly it would be possible to use a subdirectory relative to the
      executable e.g. <literal>-optl-Wl,-rpath,'$ORIGIN/lib'</literal>.
    </para>
    <para>
      This relative path technique can be used with either of the two
      <literal>-dynload</literal> modes, though it makes most sense with the
      <literal>deploy</literal> mode. The difference is that with the
      <literal>deploy</literal> mode, the above example will end up with an ELF
      <literal>RUNPATH</literal> of just <literal>$ORIGIN</literal> while with
      the <literal>sysdep</literal> mode the <literal>RUNPATH</literal> will be
      <literal>$ORIGIN</literal> followed by all the library directories of all
      the packages that the program depends on (e.g. <literal>base</literal>
      and <literal>rts</literal> packages etc.) which are typically absolute
      paths. The unix tool <literal>readelf --dynamic</literal> is handy for
      inspecting the <literal>RPATH</literal>/<literal>RUNPATH</literal>
      entries in ELF shared libraries and executables.
    </para>
    </sect3>
    <sect3 id="finding-shared-libs-mac">
    <title>Mac OS X</title>
    <para>
      The standard assumption on Darwin/Mac OS X is that dynamic libraries will
      be stamped at build time with an "install name", which is the full
      ultimate install path of the library file. Any libraries or executables
      that subsequently link against it (even if it hasn't been installed yet)
      will pick up that path as their runtime search location for it. When
      compiling with ghc directly, the install name is set by default to the
      location where it is built. You can override this with the
      <literal>-dylib-install-name</literal> option (which passes
      <literal>-install_name</literal> to the Apple linker). Cabal does this
      for you. It automatically sets the install name for dynamic libraries to
      the absolute path of the ultimate install location.
    </para>
    </sect3>
  </sect2>

</sect1>

<!-- Emacs stuff:
     ;;; Local Variables: ***
     ;;; sgml-parent-document: ("users_guide.xml" "book" "chapter" "sect1") ***
     ;;; ispell-local-dictionary: "british" ***
     ;;; End: ***
 -->