324 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
<?xml version="1.0" encoding="UTF-8"?>
 | 
						|
<!DOCTYPE chapter [
 | 
						|
  <!ENTITY ndash "–"> <!-- @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>
 | 
						|
  <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>
 | 
						|
  <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>
 | 
						|
  <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>
 | 
						|
  <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
 | 
						|
   <<filename>nixpkgs/pkgs/build-support/setup-hooks/multiple-outputs.sh</filename>>;
 | 
						|
   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 – 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>
 | 
						|
   <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>
 |