nixpkgs manual: move stdenv chapters into one folder
This commit is contained in:
@@ -0,0 +1,394 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:id="chap-cross">
|
||||
<title>Cross-compilation</title>
|
||||
<section xml:id="sec-cross-intro">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>
|
||||
"Cross-compilation" means compiling a program on one machine for another type of machine. For example, a typical use of cross-compilation is to compile programs for embedded devices. These devices often don't have the computing power and memory to compile their own programs. One might think that cross-compilation is a fairly niche concern. However, there are significant advantages to rigorously distinguishing between build-time and run-time environments! Significant, because the benefits apply even when one is developing and deploying on the same machine. Nixpkgs is increasingly adopting the opinion that packages should be written with cross-compilation in mind, and nixpkgs should evaluate in a similar way (by minimizing cross-compilation-specific special cases) whether or not one is cross-compiling.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This chapter will be organized in three parts. First, it will describe the basics of how to package software in a way that supports cross-compilation. Second, it will describe how to use Nixpkgs when cross-compiling. Third, it will describe the internal infrastructure supporting cross-compilation.
|
||||
</para>
|
||||
</section>
|
||||
<!--============================================================-->
|
||||
<section xml:id="sec-cross-packaging">
|
||||
<title>Packaging in a cross-friendly manner</title>
|
||||
|
||||
<section xml:id="ssec-cross-platform-parameters">
|
||||
<title>Platform parameters</title>
|
||||
|
||||
<para>
|
||||
Nixpkgs follows the <link
|
||||
xlink:href="https://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html">conventions of GNU autoconf</link>. We distinguish between 3 types of platforms when building a derivation: <wordasword>build</wordasword>, <wordasword>host</wordasword>, and <wordasword>target</wordasword>. In summary, <wordasword>build</wordasword> is the platform on which a package is being built, <wordasword>host</wordasword> is the platform on which it will run. The third attribute, <wordasword>target</wordasword>, is relevant only for certain specific compilers and build tools.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In Nixpkgs, these three platforms are defined as attribute sets under the names <literal>buildPlatform</literal>, <literal>hostPlatform</literal>, and <literal>targetPlatform</literal>. They are always defined as attributes in the standard environment. That means one can access them like:
|
||||
<programlisting>{ stdenv, fooDep, barDep, .. }: ...stdenv.buildPlatform...</programlisting>
|
||||
.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>buildPlatform</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The "build platform" is the platform on which a package is built. Once someone has a built package, or pre-built binary package, the build platform should not matter and can be ignored.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>hostPlatform</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The "host platform" is the platform on which a package will be run. This is the simplest platform to understand, but also the one with the worst name.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>targetPlatform</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The "target platform" attribute is, unlike the other two attributes, not actually fundamental to the process of building software. Instead, it is only relevant for compatibility with building certain specific compilers and build tools. It can be safely ignored for all other packages.
|
||||
</para>
|
||||
<para>
|
||||
The build process of certain compilers is written in such a way that the compiler resulting from a single build can itself only produce binaries for a single platform. The task of specifying this single "target platform" is thus pushed to build time of the compiler. The root cause of this is that the compiler (which will be run on the host) and the standard library/runtime (which will be run on the target) are built by a single build process.
|
||||
</para>
|
||||
<para>
|
||||
There is no fundamental need to think about a single target ahead of time like this. If the tool supports modular or pluggable backends, both the need to specify the target at build time and the constraint of having only a single target disappear. An example of such a tool is LLVM.
|
||||
</para>
|
||||
<para>
|
||||
Although the existence of a "target platfom" is arguably a historical mistake, it is a common one: examples of tools that suffer from it are GCC, Binutils, GHC and Autoconf. Nixpkgs tries to avoid sharing in the mistake where possible. Still, because the concept of a target platform is so ingrained, it is best to support it as is.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
The exact schema these fields follow is a bit ill-defined due to a long and convoluted evolution, but this is slowly being cleaned up. You can see examples of ones used in practice in <literal>lib.systems.examples</literal>; note how they are not all very consistent. For now, here are few fields can count on them containing:
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>system</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This is a two-component shorthand for the platform. Examples of this would be "x86_64-darwin" and "i686-linux"; see <literal>lib.systems.doubles</literal> for more. The first component corresponds to the CPU architecture of the platform and the second to the operating system of the platform (<literal>[cpu]-[os]</literal>). This format has built-in support in Nix, such as the <varname>builtins.currentSystem</varname> impure string.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>config</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This is a 3- or 4- component shorthand for the platform. Examples of this would be <literal>x86_64-unknown-linux-gnu</literal> and <literal>aarch64-apple-darwin14</literal>. This is a standard format called the "LLVM target triple", as they are pioneered by LLVM. In the 4-part form, this corresponds to <literal>[cpu]-[vendor]-[os]-[abi]</literal>. This format is strictly more informative than the "Nix host double", as the previous format could analogously be termed. This needs a better name than <varname>config</varname>!
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>parsed</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This is a Nix representation of a parsed LLVM target triple with white-listed components. This can be specified directly, or actually parsed from the <varname>config</varname>. See <literal>lib.systems.parse</literal> for the exact representation.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>libc</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This is a string identifying the standard C library used. Valid identifiers include "glibc" for GNU libc, "libSystem" for Darwin's Libsystem, and "uclibc" for µClibc. It should probably be refactored to use the module system, like <varname>parse</varname>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>is*</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
These predicates are defined in <literal>lib.systems.inspect</literal>, and slapped onto every platform. They are superior to the ones in <varname>stdenv</varname> as they force the user to be explicit about which platform they are inspecting. Please use these instead of those.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>platform</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This is, quite frankly, a dumping ground of ad-hoc settings (it's an attribute set). See <literal>lib.systems.platforms</literal> for examples—there's hopefully one in there that will work verbatim for each platform that is working. Please help us triage these flags and give them better homes!
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
<section xml:id="ssec-cross-dependency-categorization">
|
||||
<title>Theory of dependency categorization</title>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
This is a rather philosophical description that isn't very Nixpkgs-specific. For an overview of all the relevant attributes given to <varname>mkDerivation</varname>, see <xref
|
||||
linkend="ssec-stdenv-dependencies"/>. For a description of how everything is implemented, see <xref linkend="ssec-cross-dependency-implementation" />.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
In this section we explore the relationship between both runtime and build-time dependencies and the 3 Autoconf platforms.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A run time dependency between two packages requires that their host platforms match. This is directly implied by the meaning of "host platform" and "runtime dependency": The package dependency exists while both packages are running on a single host platform.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A build time dependency, however, has a shift in platforms between the depending package and the depended-on package. "build time dependency" means that to build the depending package we need to be able to run the depended-on's package. The depending package's build platform is therefore equal to the depended-on package's host platform.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If both the dependency and depending packages aren't compilers or other machine-code-producing tools, we're done. And indeed <varname>buildInputs</varname> and <varname>nativeBuildInputs</varname> have covered these simpler build-time and run-time (respectively) changes for many years. But if the dependency does produce machine code, we might need to worry about its target platform too. In principle, that target platform might be any of the depending package's build, host, or target platforms, but we prohibit dependencies from a "later" platform to an earlier platform to limit confusion because we've never seen a legitimate use for them.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Finally, if the depending package is a compiler or other machine-code-producing tool, it might need dependencies that run at "emit time". This is for compilers that (regrettably) insist on being built together with their source langauges' standard libraries. Assuming build != host != target, a run-time dependency of the standard library cannot be run at the compiler's build time or run time, but only at the run time of code emitted by the compiler.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Putting this all together, that means we have dependencies in the form "host → target", in at most the following six combinations:
|
||||
<table>
|
||||
<caption>Possible dependency types</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Dependency's host platform</th>
|
||||
<th>Dependency's target platform</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>build</td>
|
||||
<td>build</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>build</td>
|
||||
<td>host</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>build</td>
|
||||
<td>target</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>host</td>
|
||||
<td>host</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>host</td>
|
||||
<td>target</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>target</td>
|
||||
<td>target</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Some examples will make this table clearer. Suppose there's some package that is being built with a <literal>(build, host, target)</literal> platform triple of <literal>(foo, bar, baz)</literal>. If it has a build-time library dependency, that would be a "host → build" dependency with a triple of <literal>(foo, foo, *)</literal> (the target platform is irrelevant). If it needs a compiler to be built, that would be a "build → host" dependency with a triple of <literal>(foo, foo, *)</literal> (the target platform is irrelevant). That compiler, would be built with another compiler, also "build → host" dependency, with a triple of <literal>(foo, foo, foo)</literal>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="ssec-cross-cookbook">
|
||||
<title>Cross packaging cookbook</title>
|
||||
|
||||
<para>
|
||||
Some frequently encountered problems when packaging for cross-compilation should be answered here. Ideally, the information above is exhaustive, so this section cannot provide any new information, but it is ludicrous and cruel to expect everyone to spend effort working through the interaction of many features just to figure out the same answer to the same common problem. Feel free to add to this list!
|
||||
</para>
|
||||
|
||||
<qandaset>
|
||||
<qandaentry xml:id="cross-qa-build-c-program-in-build-environment">
|
||||
<question>
|
||||
<para>
|
||||
What if my package's build system needs to build a C program to be run under the build environment?
|
||||
</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>
|
||||
<programlisting>depsBuildBuild = [ buildPackages.stdenv.cc ];</programlisting>
|
||||
Add it to your <function>mkDerivation</function> invocation.
|
||||
</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry xml:id="cross-qa-fails-to-find-ar">
|
||||
<question>
|
||||
<para>
|
||||
My package fails to find <command>ar</command>.
|
||||
</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>
|
||||
Many packages assume that an unprefixed <command>ar</command> is available, but Nix doesn't provide one. It only provides a prefixed one, just as it only does for all the other binutils programs. It may be necessary to patch the package to fix the build system to use a prefixed `ar`.
|
||||
</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
<qandaentry xml:id="cross-testsuite-runs-host-code">
|
||||
<question>
|
||||
<para>
|
||||
My package's testsuite needs to run host platform code.
|
||||
</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>
|
||||
<programlisting>doCheck = stdenv.hostPlatform != stdenv.buildPlatfrom;</programlisting>
|
||||
Add it to your <function>mkDerivation</function> invocation.
|
||||
</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
</qandaset>
|
||||
</section>
|
||||
</section>
|
||||
<!--============================================================-->
|
||||
<section xml:id="sec-cross-usage">
|
||||
<title>Cross-building packages</title>
|
||||
|
||||
<para>
|
||||
Nixpkgs can be instantiated with <varname>localSystem</varname> alone, in which case there is no cross-compiling and everything is built by and for that system, or also with <varname>crossSystem</varname>, in which case packages run on the latter, but all building happens on the former. Both parameters take the same schema as the 3 (build, host, and target) platforms defined in the previous section. As mentioned above, <literal>lib.systems.examples</literal> has some platforms which are used as arguments for these parameters in practice. You can use them programmatically, or on the command line:
|
||||
<programlisting>
|
||||
nix-build '<nixpkgs>' --arg crossSystem '(import <nixpkgs/lib>).systems.examples.fooBarBaz' -A whatever</programlisting>
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
Eventually we would like to make these platform examples an unnecessary convenience so that
|
||||
<programlisting>
|
||||
nix-build '<nixpkgs>' --arg crossSystem '{ config = "<arch>-<os>-<vendor>-<abi>"; }' -A whatever</programlisting>
|
||||
works in the vast majority of cases. The problem today is dependencies on other sorts of configuration which aren't given proper defaults. We rely on the examples to crudely to set those configuration parameters in some vaguely sane manner on the users behalf. Issue <link xlink:href="https://github.com/NixOS/nixpkgs/issues/34274">#34274</link> tracks this inconvenience along with its root cause in crufty configuration options.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
While one is free to pass both parameters in full, there's a lot of logic to fill in missing fields. As discussed in the previous section, only one of <varname>system</varname>, <varname>config</varname>, and <varname>parsed</varname> is needed to infer the other two. Additionally, <varname>libc</varname> will be inferred from <varname>parse</varname>. Finally, <literal>localSystem.system</literal> is also <emphasis>impurely</emphasis> inferred based on the platform evaluation occurs. This means it is often not necessary to pass <varname>localSystem</varname> at all, as in the command-line example in the previous paragraph.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
Many sources (manual, wiki, etc) probably mention passing <varname>system</varname>, <varname>platform</varname>, along with the optional <varname>crossSystem</varname> to nixpkgs: <literal>import <nixpkgs> { system = ..; platform = ..; crossSystem = ..; }</literal>. Passing those two instead of <varname>localSystem</varname> is still supported for compatibility, but is discouraged. Indeed, much of the inference we do for these parameters is motivated by compatibility as much as convenience.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
One would think that <varname>localSystem</varname> and <varname>crossSystem</varname> overlap horribly with the three <varname>*Platforms</varname> (<varname>buildPlatform</varname>, <varname>hostPlatform,</varname> and <varname>targetPlatform</varname>; see <varname>stage.nix</varname> or the manual). Actually, those identifiers are purposefully not used here to draw a subtle but important distinction: While the granularity of having 3 platforms is necessary to properly *build* packages, it is overkill for specifying the user's *intent* when making a build plan or package set. A simple "build vs deploy" dichotomy is adequate: the sliding window principle described in the previous section shows how to interpolate between the these two "end points" to get the 3 platform triple for each bootstrapping stage. That means for any package a given package set, even those not bound on the top level but only reachable via dependencies or <varname>buildPackages</varname>, the three platforms will be defined as one of <varname>localSystem</varname> or <varname>crossSystem</varname>, with the former replacing the latter as one traverses build-time dependencies. A last simple difference is that <varname>crossSystem</varname> should be null when one doesn't want to cross-compile, while the <varname>*Platform</varname>s are always non-null. <varname>localSystem</varname> is always non-null.
|
||||
</para>
|
||||
</section>
|
||||
<!--============================================================-->
|
||||
<section xml:id="sec-cross-infra">
|
||||
<title>Cross-compilation infrastructure</title>
|
||||
|
||||
<section xml:id="ssec-cross-dependency-implementation">
|
||||
<title>Implementation of dependencies</title>
|
||||
|
||||
<para>
|
||||
The categorizes of dependencies developed in <xref
|
||||
linkend="ssec-cross-dependency-categorization"/> are specified as lists of derivations given to <varname>mkDerivation</varname>, as documented in <xref linkend="ssec-stdenv-dependencies"/>. In short, each list of dependencies for "host → target" of "foo → bar" is called <varname>depsFooBar</varname>, with exceptions for backwards compatibility that <varname>depsBuildHost</varname> is instead called <varname>nativeBuildInputs</varname> and <varname>depsHostTarget</varname> is instead called <varname>buildInputs</varname>. Nixpkgs is now structured so that each <varname>depsFooBar</varname> is automatically taken from <varname>pkgsFooBar</varname>. (These <varname>pkgsFooBar</varname>s are quite new, so there is no special case for <varname>nativeBuildInputs</varname> and <varname>buildInputs</varname>.) For example, <varname>pkgsBuildHost.gcc</varname> should be used at build-time, while <varname>pkgsHostTarget.gcc</varname> should be used at run-time.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Now, for most of Nixpkgs's history, there were no <varname>pkgsFooBar</varname> attributes, and most packages have not been refactored to use it explicitly. Prior to those, there were just <varname>buildPackages</varname>, <varname>pkgs</varname>, and <varname>targetPackages</varname>. Those are now redefined as aliases to <varname>pkgsBuildHost</varname>, <varname>pkgsHostTarget</varname>, and <varname>pkgsTargetTarget</varname>. It is acceptable, even recommended, to use them for libraries to show that the host platform is irrelevant.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
But before that, there was just <varname>pkgs</varname>, even though both <varname>buildInputs</varname> and <varname>nativeBuildInputs</varname> existed. [Cross barely worked, and those were implemented with some hacks on <varname>mkDerivation</varname> to override dependencies.] What this means is the vast majority of packages do not use any explicit package set to populate their dependencies, just using whatever <varname>callPackage</varname> gives them even if they do correctly sort their dependencies into the multiple lists described above. And indeed, asking that users both sort their dependencies, <emphasis>and</emphasis> take them from the right attribute set, is both too onerous and redundant, so the recommended approach (for now) is to continue just categorizing by list and not using an explicit package set.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To make this work, we "splice" together the six <varname>pkgsFooBar</varname> package sets and have <varname>callPackage</varname> actually take its arguments from that. This is currently implemented in <filename>pkgs/top-level/splice.nix</filename>. <varname>mkDerivation</varname> then, for each dependency attribute, pulls the right derivation out from the splice. This splicing can be skipped when not cross-compiling as the package sets are the same, but still is a bit slow for cross-compiling. We'd like to do something better, but haven't come up with anything yet.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="ssec-bootstrapping">
|
||||
<title>Bootstrapping</title>
|
||||
|
||||
<para>
|
||||
Each of the package sets described above come from a single bootstrapping stage. While <filename>pkgs/top-level/default.nix</filename>, coordinates the composition of stages at a high level, <filename>pkgs/top-level/stage.nix</filename> "ties the knot" (creates the fixed point) of each stage. The package sets are defined per-stage however, so they can be thought of as edges between stages (the nodes) in a graph. Compositions like <literal>pkgsBuildTarget.targetPackages</literal> can be thought of as paths to this graph.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
While there are many package sets, and thus many edges, the stages can also be arranged in a linear chain. In other words, many of the edges are redundant as far as connectivity is concerned. This hinges on the type of bootstrapping we do. Currently for cross it is:
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>(native, native, native)</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>(native, native, foreign)</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>(native, foreign, foreign)</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
In each stage, <varname>pkgsBuildHost</varname> refers the the previous stage, <varname>pkgsBuildBuild</varname> refers to the one before that, and <varname>pkgsHostTarget</varname> refers to the current one, and <varname>pkgsTargetTarget</varname> refers to the next one. When there is no previous or next stage, they instead refer to the current stage. Note how all the invariants regarding the mapping between dependency and depending packages' build host and target platforms are preserved. <varname>pkgsBuildTarget</varname> and <varname>pkgsHostHost</varname> are more complex in that the stage fitting the requirements isn't always a fixed chain of "prevs" and "nexts" away (modulo the "saturating" self-references at the ends). We just special case each instead. All the primary edges are implemented is in <filename>pkgs/stdenv/booter.nix</filename>, and secondarily aliases in <filename>pkgs/top-level/stage.nix</filename>.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
Note the native stages are bootstrapped in legacy ways that predate the current cross implementation. This is why the the bootstrapping stages leading up to the final stages are ignored inthe previous paragraph.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
If one looks at the 3 platform triples, one can see that they overlap such that one could put them together into a chain like:
|
||||
<programlisting>
|
||||
(native, native, native, foreign, foreign)
|
||||
</programlisting>
|
||||
If one imagines the saturating self references at the end being replaced with infinite stages, and then overlays those platform triples, one ends up with the infinite tuple:
|
||||
<programlisting>
|
||||
(native..., native, native, native, foreign, foreign, foreign...)
|
||||
</programlisting>
|
||||
On can then imagine any sequence of platforms such that there are bootstrap stages with their 3 platforms determined by "sliding a window" that is the 3 tuple through the sequence. This was the original model for bootstrapping. Without a target platform (assume a better world where all compilers are multi-target and all standard libraries are built in their own derivation), this is sufficient. Conversely if one wishes to cross compile "faster", with a "Canadian Cross" bootstraping stage where <literal>build != host != target</literal>, more bootstrapping stages are needed since no sliding window providess the pesky <varname>pkgsBuildTarget</varname> package set since it skips the Canadian cross stage's "host".
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
It is much better to refer to <varname>buildPackages</varname> than <varname>targetPackages</varname>, or more broadly package sets that do not mention "target". There are three reasons for this.
|
||||
</para>
|
||||
<para>
|
||||
First, it is because bootstrapping stages do not have a unique <varname>targetPackages</varname>. For example a <literal>(x86-linux, x86-linux, arm-linux)</literal> and <literal>(x86-linux, x86-linux, x86-windows)</literal> package set both have a <literal>(x86-linux, x86-linux, x86-linux)</literal> package set. Because there is no canonical <varname>targetPackages</varname> for such a native (<literal>build == host == target</literal>) package set, we set their <varname>targetPackages</varname>
|
||||
</para>
|
||||
<para>
|
||||
Second, it is because this is a frequent source of hard-to-follow "infinite recursions" / cycles. When only package sets that don't mention target are used, the package set forms a directed acyclic graph. This means that all cycles that exist are confined to one stage. This means they are a lot smaller, and easier to follow in the code or a backtrace. It also means they are present in native and cross builds alike, and so more likely to be caught by CI and other users.
|
||||
</para>
|
||||
<para>
|
||||
Thirdly, it is because everything target-mentioning only exists to accommodate compilers with lousy build systems that insist on the compiler itself and standard library being built together. Of course that is bad because bigger derivations means longer rebuilds. It is also problematic because it tends to make the standard libraries less like other libraries than they could be, complicating code and build systems alike. Because of the other problems, and because of these innate disadvantages, compilers ought to be packaged another way where possible.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If one explores Nixpkgs, they will see derivations with names like <literal>gccCross</literal>. Such <literal>*Cross</literal> derivations is a holdover from before we properly distinguished between the host and target platforms—the derivation with "Cross" in the name covered the <literal>build = host != target</literal> case, while the other covered the <literal>host = target</literal>, with build platform the same or not based on whether one was using its <literal>.nativeDrv</literal> or <literal>.crossDrv</literal>. This ugliness will disappear soon.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -0,0 +1,350 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:id="chap-meta">
|
||||
<title>Meta-attributes</title>
|
||||
<para>
|
||||
Nix packages can declare <emphasis>meta-attributes</emphasis> that contain information about a package such as a description, its homepage, its license, and so on. For instance, the GNU Hello package has a <varname>meta</varname> declaration like this:
|
||||
<programlisting>
|
||||
meta = with stdenv.lib; {
|
||||
description = "A program that produces a familiar, friendly greeting";
|
||||
longDescription = ''
|
||||
GNU Hello is a program that prints "Hello, world!" when you run it.
|
||||
It is fully customizable.
|
||||
'';
|
||||
homepage = https://www.gnu.org/software/hello/manual/;
|
||||
license = licenses.gpl3Plus;
|
||||
maintainers = [ maintainers.eelco ];
|
||||
platforms = platforms.all;
|
||||
};
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Meta-attributes are not passed to the builder of the package. Thus, a change to a meta-attribute doesn’t trigger a recompilation of the package. The value of a meta-attribute must be a string.
|
||||
</para>
|
||||
<para>
|
||||
The meta-attributes of a package can be queried from the command-line using <command>nix-env</command>:
|
||||
<screen>
|
||||
<prompt>$ </prompt>nix-env -qa hello --json
|
||||
{
|
||||
"hello": {
|
||||
"meta": {
|
||||
"description": "A program that produces a familiar, friendly greeting",
|
||||
"homepage": "https://www.gnu.org/software/hello/manual/",
|
||||
"license": {
|
||||
"fullName": "GNU General Public License version 3 or later",
|
||||
"shortName": "GPLv3+",
|
||||
"url": "http://www.fsf.org/licensing/licenses/gpl.html"
|
||||
},
|
||||
"longDescription": "GNU Hello is a program that prints \"Hello, world!\" when you run it.\nIt is fully customizable.\n",
|
||||
"maintainers": [
|
||||
"Ludovic Court\u00e8s <ludo@gnu.org>"
|
||||
],
|
||||
"platforms": [
|
||||
"i686-linux",
|
||||
"x86_64-linux",
|
||||
"armv5tel-linux",
|
||||
"armv7l-linux",
|
||||
"mips32-linux",
|
||||
"x86_64-darwin",
|
||||
"i686-cygwin",
|
||||
"i686-freebsd",
|
||||
"x86_64-freebsd",
|
||||
"i686-openbsd",
|
||||
"x86_64-openbsd"
|
||||
],
|
||||
"position": "/home/user/dev/nixpkgs/pkgs/applications/misc/hello/default.nix:14"
|
||||
},
|
||||
"name": "hello-2.9",
|
||||
"system": "x86_64-linux"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</screen>
|
||||
<command>nix-env</command> knows about the <varname>description</varname> field specifically:
|
||||
<screen>
|
||||
<prompt>$ </prompt>nix-env -qa hello --description
|
||||
hello-2.3 A program that produces a familiar, friendly greeting
|
||||
</screen>
|
||||
</para>
|
||||
<section xml:id="sec-standard-meta-attributes">
|
||||
<title>Standard meta-attributes</title>
|
||||
|
||||
<para>
|
||||
It is expected that each meta-attribute is one of the following:
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>description</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A short (one-line) description of the package. This is shown by <command>nix-env -q --description</command> and also on the Nixpkgs release pages.
|
||||
</para>
|
||||
<para>
|
||||
Don’t include a period at the end. Don’t include newline characters. Capitalise the first character. For brevity, don’t repeat the name of package — just describe what it does.
|
||||
</para>
|
||||
<para>
|
||||
Wrong: <literal>"libpng is a library that allows you to decode PNG images."</literal>
|
||||
</para>
|
||||
<para>
|
||||
Right: <literal>"A library for decoding PNG images"</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>longDescription</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An arbitrarily long description of the package.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>branch</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Release branch. Used to specify that a package is not going to receive updates that are not in this branch; for example, Linux kernel 3.0 is supposed to be updated to 3.0.X, not 3.1.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>homepage</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The package’s homepage. Example: <literal>https://www.gnu.org/software/hello/manual/</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>downloadPage</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The page where a link to the current version can be found. Example: <literal>https://ftp.gnu.org/gnu/hello/</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>changelog</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A link or a list of links to the location of Changelog for a package. A link may use expansion to refer to the correct changelog version. Example: <literal>"https://git.savannah.gnu.org/cgit/hello.git/plain/NEWS?h=v${version}"</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>license</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The license, or licenses, for the package. One from the attribute set defined in <link
|
||||
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/licenses.nix"> <filename>nixpkgs/lib/licenses.nix</filename></link>. At this moment using both a list of licenses and a single license is valid. If the license field is in the form of a list representation, then it means that parts of the package are licensed differently. Each license should preferably be referenced by their attribute. The non-list attribute value can also be a space delimited string representation of the contained attribute shortNames or spdxIds. The following are all valid examples:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Single license referenced by attribute (preferred) <literal>stdenv.lib.licenses.gpl3</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Single license referenced by its attribute shortName (frowned upon) <literal>"gpl3"</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Single license referenced by its attribute spdxId (frowned upon) <literal>"GPL-3.0"</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Multiple licenses referenced by attribute (preferred) <literal>with stdenv.lib.licenses; [ asl20 free ofl ]</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Multiple licenses referenced as a space delimited string of attribute shortNames (frowned upon) <literal>"asl20 free ofl"</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
For details, see <xref linkend='sec-meta-license'/>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>maintainers</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A list of names and e-mail addresses of the maintainers of this Nix expression. If you would like to be a maintainer of a package, you may want to add yourself to <link
|
||||
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/maintainers/maintainer-list.nix"><filename>nixpkgs/maintainers/maintainer-list.nix</filename></link> and write something like <literal>[ stdenv.lib.maintainers.alice stdenv.lib.maintainers.bob ]</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>priority</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>priority</emphasis> of the package, used by <command>nix-env</command> to resolve file name conflicts between packages. See the Nix manual page for <command>nix-env</command> for details. Example: <literal>"10"</literal> (a low-priority package).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>platforms</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The list of Nix platform types on which the package is supported. Hydra builds packages according to the platform specified. If no platform is specified, the package does not have prebuilt binaries. An example is:
|
||||
<programlisting>
|
||||
meta.platforms = stdenv.lib.platforms.linux;
|
||||
</programlisting>
|
||||
Attribute Set <varname>stdenv.lib.platforms</varname> defines <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/systems/doubles.nix"> various common lists</link> of platforms types.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>tests</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<warning>
|
||||
<para>
|
||||
This attribute is special in that it is not actually under the <literal>meta</literal> attribute set but rather under the <literal>passthru</literal> attribute set. This is due to how <literal>meta</literal> attributes work, and the fact that they are supposed to contain only metadata, not derivations.
|
||||
</para>
|
||||
</warning>
|
||||
<para>
|
||||
An attribute set with as values tests. A test is a derivation, which builds successfully when the test passes, and fails to build otherwise. A derivation that is a test needs to have <literal>meta.timeout</literal> defined.
|
||||
</para>
|
||||
<para>
|
||||
The NixOS tests are available as <literal>nixosTests</literal> in parameters of derivations. For instance, the OpenSMTPD derivation includes lines similar to:
|
||||
<programlisting>
|
||||
{ /* ... */, nixosTests }:
|
||||
{
|
||||
# ...
|
||||
passthru.tests = {
|
||||
basic-functionality-and-dovecot-integration = nixosTests.opensmtpd;
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>timeout</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A timeout (in seconds) for building the derivation. If the derivation takes longer than this time to build, it can fail due to breaking the timeout. However, all computers do not have the same computing power, hence some builders may decide to apply a multiplicative factor to this value. When filling this value in, try to keep it approximately consistent with other values already present in <literal>nixpkgs</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>hydraPlatforms</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The list of Nix platform types for which the Hydra instance at <literal>hydra.nixos.org</literal> will build the package. (Hydra is the Nix-based continuous build system.) It defaults to the value of <varname>meta.platforms</varname>. Thus, the only reason to set <varname>meta.hydraPlatforms</varname> is if you want <literal>hydra.nixos.org</literal> to build the package on a subset of <varname>meta.platforms</varname>, or not at all, e.g.
|
||||
<programlisting>
|
||||
meta.platforms = stdenv.lib.platforms.linux;
|
||||
meta.hydraPlatforms = [];
|
||||
</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>broken</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
If set to <literal>true</literal>, the package is marked as “broken”, meaning that it won’t show up in <literal>nix-env -qa</literal>, and cannot be built or installed. Such packages should be removed from Nixpkgs eventually unless they are fixed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>updateWalker</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
If set to <literal>true</literal>, the package is tested to be updated correctly by the <literal>update-walker.sh</literal> script without additional settings. Such packages have <varname>meta.version</varname> set and their homepage (or the page specified by <varname>meta.downloadPage</varname>) contains a direct link to the package tarball.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
<section xml:id="sec-meta-license">
|
||||
<title>Licenses</title>
|
||||
|
||||
<para>
|
||||
The <varname>meta.license</varname> attribute should preferrably contain a value from <varname>stdenv.lib.licenses</varname> defined in <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/licenses.nix"> <filename>nixpkgs/lib/licenses.nix</filename></link>, or in-place license description of the same format if the license is unlikely to be useful in another expression.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Although it's typically better to indicate the specific license, a few generic options are available:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>stdenv.lib.licenses.free</varname>, <varname>"free"</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Catch-all for free software licenses not listed above.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>stdenv.lib.licenses.unfreeRedistributable</varname>, <varname>"unfree-redistributable"</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Unfree package that can be redistributed in binary form. That is, it’s legal to redistribute the <emphasis>output</emphasis> of the derivation. This means that the package can be included in the Nixpkgs channel.
|
||||
</para>
|
||||
<para>
|
||||
Sometimes proprietary software can only be redistributed unmodified. Make sure the builder doesn’t actually modify the original binaries; otherwise we’re breaking the license. For instance, the NVIDIA X11 drivers can be redistributed unmodified, but our builder applies <command>patchelf</command> to make them work. Thus, its license is <varname>"unfree"</varname> and it cannot be included in the Nixpkgs channel.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>stdenv.lib.licenses.unfree</varname>, <varname>"unfree"</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Unfree package that cannot be redistributed. You can build it yourself, but you cannot redistribute the output of the derivation. Thus it cannot be included in the Nixpkgs channel.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>stdenv.lib.licenses.unfreeRedistributableFirmware</varname>, <varname>"unfree-redistributable-firmware"</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This package supplies unfree, redistributable firmware. This is a separate value from <varname>unfree-redistributable</varname> because not everybody cares whether firmware is free.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -0,0 +1,232 @@
|
||||
<?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 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>
|
||||
|
||||
<para>
|
||||
In some cases it may be desirable to combine different outputs under a single store path. A function <literal>symlinkJoin</literal> can be used to do this. (Note that it may negate some closure size benefits of using a multiple-output package.)
|
||||
</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 <<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 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>
|
||||
@@ -0,0 +1,83 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:id="chap-platform-notes">
|
||||
<title>Platform Notes</title>
|
||||
<section xml:id="sec-darwin">
|
||||
<title>Darwin (macOS)</title>
|
||||
|
||||
<para>
|
||||
Some common issues when packaging software for Darwin:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The Darwin <literal>stdenv</literal> uses clang instead of gcc. When referring to the compiler <varname>$CC</varname> or <command>cc</command> will work in both cases. Some builds hardcode gcc/g++ in their build scripts, that can usually be fixed with using something like <literal>makeFlags = [ "CC=cc" ];</literal> or by patching the build scripts.
|
||||
</para>
|
||||
<programlisting>
|
||||
stdenv.mkDerivation {
|
||||
name = "libfoo-1.2.3";
|
||||
# ...
|
||||
buildPhase = ''
|
||||
$CC -o hello hello.c
|
||||
'';
|
||||
}
|
||||
</programlisting>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
On Darwin, libraries are linked using absolute paths, libraries are resolved by their <literal>install_name</literal> at link time. Sometimes packages won't set this correctly causing the library lookups to fail at runtime. This can be fixed by adding extra linker flags or by running <command>install_name_tool -id</command> during the <function>fixupPhase</function>.
|
||||
</para>
|
||||
<programlisting>
|
||||
stdenv.mkDerivation {
|
||||
name = "libfoo-1.2.3";
|
||||
# ...
|
||||
makeFlags = stdenv.lib.optional stdenv.isDarwin "LDFLAGS=-Wl,-install_name,$(out)/lib/libfoo.dylib";
|
||||
}
|
||||
</programlisting>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Even if the libraries are linked using absolute paths and resolved via their <literal>install_name</literal> correctly, tests can sometimes fail to run binaries. This happens because the <varname>checkPhase</varname> runs before the libraries are installed.
|
||||
</para>
|
||||
<para>
|
||||
This can usually be solved by running the tests after the <varname>installPhase</varname> or alternatively by using <varname>DYLD_LIBRARY_PATH</varname>. More information about this variable can be found in the <citerefentry>
|
||||
<refentrytitle>dyld</refentrytitle>
|
||||
<manvolnum>1</manvolnum></citerefentry> manpage.
|
||||
</para>
|
||||
<programlisting>
|
||||
dyld: Library not loaded: /nix/store/7hnmbscpayxzxrixrgxvvlifzlxdsdir-jq-1.5-lib/lib/libjq.1.dylib
|
||||
Referenced from: /private/tmp/nix-build-jq-1.5.drv-0/jq-1.5/tests/../jq
|
||||
Reason: image not found
|
||||
./tests/jqtest: line 5: 75779 Abort trap: 6
|
||||
</programlisting>
|
||||
<programlisting>
|
||||
stdenv.mkDerivation {
|
||||
name = "libfoo-1.2.3";
|
||||
# ...
|
||||
doInstallCheck = true;
|
||||
installCheckTarget = "check";
|
||||
}
|
||||
</programlisting>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Some packages assume xcode is available and use <command>xcrun</command> to resolve build tools like <command>clang</command>, etc. This causes errors like <code>xcode-select: error: no developer tools were found at '/Applications/Xcode.app'</code> while the build doesn't actually depend on xcode.
|
||||
</para>
|
||||
<programlisting>
|
||||
stdenv.mkDerivation {
|
||||
name = "libfoo-1.2.3";
|
||||
# ...
|
||||
prePatch = ''
|
||||
substituteInPlace Makefile \
|
||||
--replace '/usr/bin/xcrun clang' clang
|
||||
'';
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
The package <literal>xcbuild</literal> can be used to build projects that really depend on Xcode. However, this replacement is not 100% compatible with Xcode and can occasionally cause issues.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user