Difference between revisions of "Import From Derivation"

From NixOS Wiki
Jump to: navigation, search
m (rollback unauthorized mass edits)
Tag: Rollback
 
(10 intermediate revisions by 7 users not shown)
Line 1: Line 1:
Import From Derivation (IFD) is where during a single Nix evaluation, the
+
See the Nix manual: [https://nixos.org/manual/nix/unstable/language/import-from-derivation Import From Derivation]
Nix expression:
 
  
# creates a derivation which will build a Nix expression
+
== Further reading ==
# imports that expression
 
# uses the results of the evaluation of the expression.
 
  
An example of IFD is:
+
* https://fzakaria.com/2020/10/21/nix-parallelism-import-from-derivation.html
  
<syntaxHighlight lang=nix>
+
[[Category: Nix]]
let
 
  pkgs = import <nixpkgs> {};
 
 
 
  # Create a derivation which, when built, writes some Nix code to
 
  # its $out path.
 
  derivation-to-import = pkgs.writeText "example" ''
 
    pkgs: {
 
      ifd-example = pkgs.stdenv.mkDerivation rec {
 
        name = "hello-2.10-ifd-example";
 
 
 
 
 
        src = pkgs.fetchurl {
 
          url = "mirror://gnu/hello/2.10.tar.gz";
 
          sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i";
 
        };
 
      };
 
    }
 
  '';
 
 
 
  # Import the derivation. This forces `derivation-to-import` to become
 
  # a string. This is normal behavior for Nix and Nixpkgs. The specific
 
  # difference here is the evaluation itself requires the result to be
 
  # built during the evaluation in order to continue evaluating.
 
  imported-derivation = import derivation-to-import;
 
 
 
  # Treat the imported-derivation variable as if we hadn't just created
 
  # its Nix expression inside this same evaluation.
 
  hello-package = (imported-derivation pkgs).ifd-example;
 
in hello-package
 
</syntaxHighlight>
 
 
 
Building this looks familiar, but with an extra <code>building ...</code> line:
 
 
 
{{Commands|<nowiki>
 
$ nix-build ./test.nix
 
building '/nix/store/8n001pyx2iqsnzd6niji1bvyjlg6x058-example.drv'... <- this build is forced at
 
                                                                        evaluation time
 
 
 
these derivations will be built:                                      <- now we're back to normal
 
                                                                        nix-build behavior
 
  /nix/store/3nm9rlv5smmvijcdifngjwl4v6zvll7k-hello-2.10-ifd-example.drv
 
 
 
building '/nix/store/3nm9rlv5smmvijcdifngjwl4v6zvll7k-hello-2.10-ifd-example.drv'...
 
[...snip...]
 
</nowiki>}}
 
 
 
we'll see pretty similar output if we just evaluate it:
 
 
 
{{Commands|<nowiki>
 
$ nix-instantiate ./test.nix
 
building '/nix/store/8n001pyx2iqsnzd6niji1bvyjlg6x058-example.drv'...
 
 
 
/nix/store/3nm9rlv5smmvijcdifngjwl4v6zvll7k-hello-2.10-ifd-example.drv
 
</nowiki>}}
 
 
 
Some examples of IFD can be seen when using nixpkgs to fetch a specific
 
version of nixpkgs, and then importing the source.
 
 
 
<h2>When to use IFD</h2>
 
 
 
IFD is a powerful feature, but it should be avoided _if possible_. IFD extends the duration of evaluation, which is single threaded and it affects the predictions of the `nix` progress bar.
 
 
 
Acceptable uses of IFD include importing a pinned nixpkgs and automation around lock files. Such uses vastly improve your development workflow, outweighing the slight disadvantages of IFD.
 
 
 
As a rule of thumb, if you can avoid IFD by refactoring Nix code or moving your build logic into the derivations themselves, you should do so.
 
 
 
<h2>Recognizing IFD</h2>
 
 
 
The textbook case of IFD looks like `import e` where `e` is an expression that requires a build to provide the value. However, `import` is not the only function that can require a build. For example, `builtins.readFile` can have the same effect.
 
 
 
All functions that query the filesystem will require a build when invoked on a derivation output path or subpath. This has the same effect and is therefore also called IFD. These include
 
 
 
* <code>import</code>
 
* <code>builtins.readFile</code>
 
* <code>builtins.readDir</code>
 
* <code>builtins.pathExists</code>
 
* <code>builtins.filterSource</code>
 
* <code>builtins.path</code>
 
* <code>builtins.hashFile</code>
 
* <code>builtins.scopedImport</code>
 
* potentially other functions if those read the filesystem in any way
 
* '''library functions''' that invoke the above, such as
 
* <code>lib.cleanSource</code>
 
* ...
 

Latest revision as of 10:59, 6 April 2024