summary refs log tree commit diff
path: root/doc/multiple-output.xml
blob: e96e84bfe72fd259d8356f6767850c08ace8820c (plain) (blame)
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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter [
  <!ENTITY ndash "&#x2013;"> <!-- @vcunat likes to use this one ;-) -->
]>
<chapter xmlns="http://docbook.org/ns/docbook"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xml:id="chap-multiple-output">
 <title>Multiple-output packages</title>
 <section xml:id="sec-multiple-outputs-introduction">
  <title>Introduction</title>

  <para>
   The Nix language allows a derivation to produce multiple outputs, which is
   similar to what is utilized by other Linux distribution packaging systems.
   The outputs reside in separate nix store paths, so they can be mostly
   handled independently of each other, including passing to build inputs,
   garbage collection or binary substitution. The exception is that building
   from source always produces all the outputs.
  </para>

  <para>
   The main motivation is to save disk space by reducing runtime closure sizes;
   consequently also sizes of substituted binaries get reduced. Splitting can
   be used to have more granular runtime dependencies, for example the typical
   reduction is to split away development-only files, as those are typically
   not needed during runtime. As a result, closure sizes of many packages can
   get reduced to a half or even much less.
  </para>

  <note>
   <para>
    The reduction effects could be instead achieved by building the parts in
    completely separate derivations. That would often additionally reduce
    build-time closures, but it tends to be much harder to write such
    derivations, as build systems typically assume all parts are being built at
    once. This compromise approach of single source package producing multiple
    binary packages is also utilized often by rpm and deb.
   </para>
  </note>
 </section>
 <section xml:id="sec-multiple-outputs-installing">
  <title>Installing a split package</title>

  <para>
   When installing a package via <varname>systemPackages</varname> or
   <command>nix-env</command> you have several options:
  </para>

  <itemizedlist>
   <listitem>
    <para>
     You can install particular outputs explicitly, as each is available in the
     Nix language as an attribute of the package. The
     <varname>outputs</varname> attribute contains a list of output names.
    </para>
   </listitem>
   <listitem>
    <para>
     You can let it use the default outputs. These are handled by
     <varname>meta.outputsToInstall</varname> attribute that contains a list of
     output names.
    </para>
    <para>
     TODO: more about tweaking the attribute, etc.
    </para>
   </listitem>
   <listitem>
    <para>
     NixOS provides configuration option
     <varname>environment.extraOutputsToInstall</varname> that allows adding
     extra outputs of <varname>environment.systemPackages</varname> atop the
     default ones. It's mainly meant for documentation and debug symbols, and
     it's also modified by specific options.
    </para>
    <note>
     <para>
      At this moment there is no similar configurability for packages installed
      by <command>nix-env</command>. You can still use approach from
      <xref linkend="sec-modify-via-packageOverrides" /> to override
      <varname>meta.outputsToInstall</varname> attributes, but that's a rather
      inconvenient way.
     </para>
    </note>
   </listitem>
  </itemizedlist>
 </section>
 <section xml:id="sec-multiple-outputs-using-split-packages">
  <title>Using a split package</title>

  <para>
   In the Nix language the individual outputs can be reached explicitly as
   attributes, e.g. <varname>coreutils.info</varname>, but the typical case is
   just using packages as build inputs.
  </para>

  <para>
   When a multiple-output derivation gets into a build input of another
   derivation, the <varname>dev</varname> output is added if it exists,
   otherwise the first output is added. In addition to that,
   <varname>propagatedBuildOutputs</varname> of that package which by default
   contain <varname>$outputBin</varname> and <varname>$outputLib</varname> are
   also added. (See <xref linkend="multiple-output-file-type-groups" />.)
  </para>
 </section>
 <section xml:id="sec-multiple-outputs-">
  <title>Writing a split derivation</title>

  <para>
   Here you find how to write a derivation that produces multiple outputs.
  </para>

  <para>
   In nixpkgs there is a framework supporting multiple-output derivations. It
   tries to cover most cases by default behavior. You can find the source
   separated in
   &lt;<filename>nixpkgs/pkgs/build-support/setup-hooks/multiple-outputs.sh</filename>&gt;;
   it's relatively well-readable. The whole machinery is triggered by defining
   the <varname>outputs</varname> attribute to contain the list of desired
   output names (strings).
  </para>

<programlisting>outputs = [ "bin" "dev" "out" "doc" ];</programlisting>

  <para>
   Often such a single line is enough. For each output an equally named
   environment variable is passed to the builder and contains the path in nix
   store for that output. Typically you also want to have the main
   <varname>out</varname> output, as it catches any files that didn't get
   elsewhere.
  </para>

  <note>
   <para>
    There is a special handling of the <varname>debug</varname> output,
    described at <xref linkend="stdenv-separateDebugInfo" />.
   </para>
  </note>

  <section xml:id="multiple-output-file-binaries-first-convention">
   <title><quote>Binaries first</quote></title>

   <para>
    A commonly adopted convention in <literal>nixpkgs</literal> is that
    executables provided by the package are contained within its first output.
    This convention allows the dependent packages to reference the executables
    provided by packages in a uniform manner. For instance, provided with the
    knowledge that the <literal>perl</literal> package contains a
    <literal>perl</literal> executable it can be referenced as
    <literal>${pkgs.perl}/bin/perl</literal> within a Nix derivation that needs
    to execute a Perl script.
   </para>

   <para>
    The <literal>glibc</literal> package is a deliberate single exception to
    the <quote>binaries first</quote> convention. The <literal>glibc</literal>
    has <literal>libs</literal> as its first output allowing the libraries
    provided by <literal>glibc</literal> to be referenced directly (e.g.
    <literal>${stdenv.glibc}/lib/ld-linux-x86-64.so.2</literal>). The
    executables provided by <literal>glibc</literal> can be accessed via its
    <literal>bin</literal> attribute (e.g.
    <literal>${stdenv.glibc.bin}/bin/ldd</literal>).
   </para>

   <para>
    The reason for why <literal>glibc</literal> deviates from the convention is
    because referencing a library provided by <literal>glibc</literal> is a
    very common operation among Nix packages. For instance, third-party
    executables packaged by Nix are typically patched and relinked with the
    relevant version of <literal>glibc</literal> libraries from Nix packages
    (please see the documentation on
    <link xlink:href="https://nixos.org/patchelf.html">patchelf</link> for more
    details).
   </para>
  </section>

  <section xml:id="multiple-output-file-type-groups">
   <title>File type groups</title>

   <para>
    The support code currently recognizes some particular kinds of outputs and
    either instructs the build system of the package to put files into their
    desired outputs or it moves the files during the fixup phase. Each group of
    file types has an <varname>outputFoo</varname> variable specifying the
    output name where they should go. If that variable isn't defined by the
    derivation writer, it is guessed &ndash; a default output name is defined,
    falling back to other possibilities if the output isn't defined.
   </para>

   <variablelist>
    <varlistentry>
     <term>
      <varname> $outputDev</varname>
     </term>
     <listitem>
      <para>
       is for development-only files. These include C(++) headers, pkg-config,
       cmake and aclocal files. They go to <varname>dev</varname> or
       <varname>out</varname> by default.
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term>
      <varname> $outputBin</varname>
     </term>
     <listitem>
      <para>
       is meant for user-facing binaries, typically residing in bin/. They go
       to <varname>bin</varname> or <varname>out</varname> by default.
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term>
      <varname> $outputLib</varname>
     </term>
     <listitem>
      <para>
       is meant for libraries, typically residing in <filename>lib/</filename>
       and <filename>libexec/</filename>. They go to <varname>lib</varname> or
       <varname>out</varname> by default.
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term>
      <varname> $outputDoc</varname>
     </term>
     <listitem>
      <para>
       is for user documentation, typically residing in
       <filename>share/doc/</filename>. It goes to <varname>doc</varname> or
       <varname>out</varname> by default.
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term>
      <varname> $outputDevdoc</varname>
     </term>
     <listitem>
      <para>
       is for <emphasis>developer</emphasis> documentation. Currently we count
       gtk-doc and devhelp books in there. It goes to <varname>devdoc</varname>
       or is removed (!) by default. This is because e.g. gtk-doc tends to be
       rather large and completely unused by nixpkgs users.
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term>
      <varname> $outputMan</varname>
     </term>
     <listitem>
      <para>
       is for man pages (except for section 3). They go to
       <varname>man</varname> or <varname>$outputBin</varname> by default.
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term>
      <varname> $outputDevman</varname>
     </term>
     <listitem>
      <para>
       is for section 3 man pages. They go to <varname>devman</varname> or
       <varname>$outputMan</varname> by default.
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term>
      <varname> $outputInfo</varname>
     </term>
     <listitem>
      <para>
       is for info pages. They go to <varname>info</varname> or
       <varname>$outputBin</varname> by default.
      </para>
     </listitem>
    </varlistentry>
   </variablelist>
  </section>

  <section xml:id="sec-multiple-outputs-caveats">
   <title>Common caveats</title>

   <itemizedlist>
    <listitem>
     <para>
      Some configure scripts don't like some of the parameters passed by
      default by the framework, e.g. <literal>--docdir=/foo/bar</literal>. You
      can disable this by setting <literal>setOutputFlags = false;</literal>.
     </para>
    </listitem>
    <listitem>
     <para>
      The outputs of a single derivation can retain references to each other,
      but note that circular references are not allowed. (And each
      strongly-connected component would act as a single output anyway.)
     </para>
    </listitem>
    <listitem>
     <para>
      Most of split packages contain their core functionality in libraries.
      These libraries tend to refer to various kind of data that typically gets
      into <varname>out</varname>, e.g. locale strings, so there is often no
      advantage in separating the libraries into <varname>lib</varname>, as
      keeping them in <varname>out</varname> is easier.
     </para>
    </listitem>
    <listitem>
     <para>
      Some packages have hidden assumptions on install paths, which complicates
      splitting.
     </para>
    </listitem>
   </itemizedlist>
  </section>
 </section>
<!--Writing a split derivation-->
</chapter>