Derivations: Difference between revisions

DoggoBit (talk | contribs)
Low-level derivations: aaaand remove highlights ugh
DoggoBit (talk | contribs)
Finish rewriting the first section
Line 40: Line 40:
   ];
   ];
}</nowiki>}}
}</nowiki>}}
=== The result of a derivation ===
When building a derivation, its result will be added to the Nix store, and a symlink will be provided in the current directory, called <code>result</code>.
The <code>$out</code> variable above has a special meaning in the Nix context: it points to the file that will become the result of the derivation. Thus executing <code>chmod +x $out</code> makes the derivation executable. Because directories on POSIX systems are files themselves, the derivation's result can be an entire directory of files.
The actual directory of <code>$out</code> is an implementation detail abstracted away by Nix and the stdenv builder. Anything placed within <code>$out</code> will then be part of the final derivation. Most derivation aim to follow a FHS-like structure, with the following common subdirectories:
* <code>$out/bin</code> contains binaries;
* <code>$out/lib</code> contains shared objects
* <code>$out/include</code> contains headers
In the context of systems like NixOS or [[Home Manager]], these paths will usually be symlinked into the top-level derivation's directories (the resulting system build).


=== Standard environment derivations ===
=== Standard environment derivations ===
The standard environment provides us with a useful utility function for creating derivations called <code>stdenv.mkDerivation</code>. Among other things, it ensures we have all the common binaries and libraries we might expect from a Linux build environment already available to us. For example, the derivation above can be rewritten, removing the need to point to the bash and <code>coreutil</code> paths ourselves, as follows:{{File|example.nix|nix|<nowiki>
{ pkgs ? import </nowiki><<nowiki>nixpkgs</nowiki>><nowiki> {} }:


==== src ====
pkgs.stdenv.mkDerivation {
This attribute points towards the inputs used within the derivation. This can be source code, but it can also be a pre-build binary. Usually depending on what the source is, a special series of steps is done to ensure its correctness in a Nix environment.
  name = "hello-world";
 
  buildCommand = ''
    echo '#!/bin/bash' </nowiki>><nowiki> $out
    echo 'echo "Hello, World!"' </nowiki>>><nowiki> $out
    chmod +x $out
  '';
}
</nowiki>|highlight=}}


This usually is downloaded via a [https://nixos.org/manual/nixpkgs/unstable/#chap-pkgs-fetchers fetcher], but it can also be a local path:<syntaxhighlight lang="nix">
==== Including source code ====
{{Main|Fetchers}}
However, when building applications, packages, or derivations in general, we are almost never manually writing the source code ourselves within the derivation's build steps. Usually, we need to point to the derivation's source code. The <code>stdenv.mkDerivation</code> function takes in an attribute called <code>src</code>, which points to a location that should be included as one of the derivation's inputs.
 
When building the derivation, the source code will be copied in the Nix store before proceeding with the build. The reason for this is due to the nature of source code (and external files in general themselves): they ''change over time''. Source code gets edited, improved, reverted, etc. By copying the source code ''at the time of the derivation'' to the Nix store, it becomes ''immutable''; any subsequent changes would result in it getting copied to a ''different path'' in the store. Thus, Nix ensures the guarantees we expect from a derivation: it still is a deterministic output, a function of its inputs.
 
Grabbing the source code can be done in a number of different ways: it can be a store path, a location on the current system, or it can be downloaded via a [https://nixos.org/manual/nixpkgs/unstable/#chap-pkgs-fetchers fetcher], which is a special-purpose utility function for exactly this task:<syntaxhighlight lang="nix">
stdenv.mkDerivation {
stdenv.mkDerivation {
  src = ./relative-path/to/src;
  # or


  src = ./relative-path/to/src;
  # OR
   src = fetchFromGitHub {
   src = fetchFromGitHub {
     owner = "torvalds";
     owner = "torvalds";
Line 61: Line 91:
</syntaxhighlight>
</syntaxhighlight>


==== out ====
=== Nixpkgs packages ===
The Nixpkgs repository is relevant in two main ways: it itself contains many higher-level utilities that abstract over the <code>stdenv.mkDerivation</code> requirements for the most common use cases, and every [[Nixpkgs]] package is a derivation in of itself.


Unlike <code>src</code>, this is not an attribute you set but rather an environment variable which points to the finalized location of the derivation's contents. The actual directory of <code>$out</code> is an implementation detail abstracted away by Nix and the stdenv builder. Anything placed within <code>$out</code> will then be part of the final derivation. This follows an FHS-inspired like structure, where <code>$out/bin</code> contains binaries, <code>$out/lib</code> contains shared objects, <code>$out/include</code> contains headers, and so forth. These paths will become part of the derivation and are the resulting entries within the <code>/nix/store</code>.<blockquote>This attribute must point to either a file or directory, even if they are empty! Failure to create this path will result in the builder failing the entire build process.</blockquote>
==== Utility functions ====
 
For example, the derivation at the beginning of this section can be rewritten in just four lines using the <code>writeShellScript</code> utility package. It handles most of the little setup required by the standard environment for us. The majority of the derivations that need to be written almost definitely can make use of one of these utility packages. For example:{{File|example.nix|nix|{ pkgs ? import <nixpkgs> {} }:
This step is handled largely by the <code>installPhase</code>(see [[#Phases]] for more details):<syntaxhighlight lang="nix">
stdenv.mkDerivation {
  src = ...;
 
  installPhase = ''
    mkdir -p $out/bin
 
    install -Dm755 -t $out/bin ./my-binary
  '';
}
</syntaxhighlight>


==== meta ====
pkgs.writeShellScript "hello-world" ''
Unlike the previous two, this attribute has no significant relevance to building and largely contains a loose set of attributes useful with the context of Nixpkgs. Therefore, if you're writing a derivation that is not intended for Nixpkgs, this entire attribute set can be safely omitted.
  echo "Hello, World!"
''}}


Attributes in here relate to the upstream source, or the finalized derivation result. Some attributes, like <code>meta.homepage</code> and <code>meta.description</code>, are used to describe and link to relevant information about the upstream source this derivation builds. Attributes like <code>meta.platforms</code> and <code>meta.licenses</code> are also semantically relevant to upstream, but these are also useful for Nixpkgs to determine whether a package can be built on a different system (and whether to allow so in evaluation!), and if a package has a suitable license that allows for re-distribution (caching in the official [[Binary Cache|binary cache]]).
==== Package metadata ====
Derivations meant to be included as part of Nixpkgs usually include some metadata under the meta attribute. Common fields include:


There are also some other attributes that are only relevant within the context of Nixpkgs/Nix alone, such as <code>meta.mainProgram</code>, which describes the binary that can be considered the "main" program. For example, the cmake derivation would have meta.mainProgram set to <code>cmake</code>, which would be resolved as <code>$out/bin/cmake</code> when needed.
* <code>meta.homepage</code> and <code>meta.description</code> are used to describe and link to relevant information about the upstream source this derivation builds;
* <code>meta.platforms</code> is useful for Nixpkgs to determine whether a package can be built on a different system (and whether to allow so in evaluation);
* and <code>meta.licenses</code> is useful to check if a package has a suitable license that allows for re-distribution (caching in the official [[Binary Cache|binary cache]]<nowiki/>or one of the community caches);
* <code>meta.mainProgram</code> describes the binary that can be considered the "main" program. For example, the cmake derivation would have this attribute set to <code>cmake</code>, which would be resolved as <code>$out/bin/cmake</code> when needed.


A fully exhaustive documentation on all meta-attributes can be found in the [https://nixos.org/manual/nixpkgs/unstable/#chap-meta Nixpkgs manual].
A fully exhaustive documentation on all meta-attributes can be found in the [https://nixos.org/manual/nixpkgs/unstable/#chap-meta Nixpkgs manual].