1 { lib, stdenv, stdenvNoCC, lndir, runtimeShell, shellcheck }:
12 /* Run the shell command `buildCommand' to produce a store path named
13 * `name'. The attributes in `env' are added to the environment
14 * prior to running the command. By default `runCommand` runs in a
15 * stdenv with no compiler environment. `runCommandCC` uses the default
16 * stdenv, `pkgs.stdenv`.
19 * runCommand "name" {envVariable = true;} ''echo hello > $out''
20 * runCommandCC "name" {} ''gcc -o myfile myfile.c; cp myfile $out'';
22 * The `*Local` variants force a derivation to be built locally,
23 * it is not substituted.
25 * This is intended for very cheap commands (<1s execution time).
26 * It saves on the network roundrip and can speed up a build.
28 * It is the same as adding the special fields
29 * `preferLocalBuild = true;`
30 * `allowSubstitutes = false;`
31 * to a derivation’s attributes.
33 runCommand = name: env: runCommandWith {
39 runCommandLocal = name: env: runCommandWith {
46 runCommandCC = name: env: runCommandWith {
52 # `runCommandCCLocal` left out on purpose.
53 # We shouldn’t force the user to have a cc in scope.
55 /* Generalized version of the `runCommand`-variants
56 * which does customized behavior via a single
57 * attribute set passed as the first argument
58 * instead of having a lot of variants like
59 * `runCommand*`. Additionally it allows changing
60 * the used `stdenv` freely and has a more explicit
61 * approach to changing the arguments passed to
62 * `stdenv.mkDerivation`.
66 # prevent infinite recursion for the default stdenv value
67 defaultStdenv = stdenv;
69 { stdenv ? defaultStdenv
70 # which stdenv to use, defaults to a stdenv with a C compiler, pkgs.stdenv
72 # whether to build this derivation locally instead of substituting
74 # extra arguments to pass to stdenv.mkDerivation
76 # name of the resulting derivation
77 # TODO(@Artturin): enable strictDeps always
79 stdenv.mkDerivation ({
80 enableParallelBuilding = true;
81 inherit buildCommand name;
82 passAsFile = [ "buildCommand" ]
83 ++ (derivationArgs.passAsFile or []);
85 // (lib.optionalAttrs runLocal {
86 preferLocalBuild = true;
87 allowSubstitutes = false;
89 // builtins.removeAttrs derivationArgs [ "passAsFile" ]);
92 /* Writes a text file to the nix store.
93 * The contents of text is added to the file in the store.
96 * # Writes my-file to /nix/store/<store path>
103 * # See also the `writeText` helper function below.
105 * # Writes executable my-file to /nix/store/<store path>/bin/my-file
112 * destination = "/bin/my-file";
116 { name # the name of the derivation
118 , executable ? false # run chmod +x ?
119 , destination ? "" # relative path appended to $out eg "/bin/foo"
120 , checkPhase ? "" # syntax checks, e.g. for scripts
124 { inherit text executable checkPhase meta;
125 passAsFile = [ "text" ];
126 # Pointless to do this on a remote machine.
127 preferLocalBuild = true;
128 allowSubstitutes = false;
131 target=$out${lib.escapeShellArg destination}
132 mkdir -p "$(dirname "$target")"
134 if [ -e "$textPath" ]; then
135 mv "$textPath" "$target"
137 echo -n "$text" > "$target"
142 (test -n "$executable" && chmod +x "$target") || true
146 * Writes a text file to nix store with no optional parameters available.
149 * # Writes contents of file to /nix/store/<store path>
150 * writeText "my-file"
156 writeText = name: text: writeTextFile {inherit name text;};
159 * Writes a text file to nix store in a specific directory with no
160 * optional parameters available.
163 * # Writes contents of file to /nix/store/<store path>/share/my-file
164 * writeTextDir "share/my-file"
170 writeTextDir = path: text: writeTextFile {
172 name = builtins.baseNameOf path;
173 destination = "/${path}";
177 * Writes a text file to /nix/store/<store path> and marks the file as
180 * If passed as a build input, will be used as a setup hook. This makes setup
181 * hooks more efficient to create: you don't need a derivation that copies
182 * them to $out/nix-support/setup-hook, instead you can use the file as is.
185 * # Writes my-file to /nix/store/<store path> and makes executable
186 * writeScript "my-file"
192 writeScript = name: text: writeTextFile {inherit name text; executable = true;};
195 * Writes a text file to /nix/store/<store path>/bin/<name> and
196 * marks the file as executable.
199 * # Writes my-file to /nix/store/<store path>/bin/my-file and makes executable.
200 * writeScriptBin "my-file"
206 writeScriptBin = name: text: writeTextFile {inherit name text; executable = true; destination = "/bin/${name}";};
209 * Similar to writeScript. Writes a Shell script and checks its syntax.
210 * Automatically includes interpreter above the contents passed.
213 * # Writes my-file to /nix/store/<store path> and makes executable.
214 * writeShellScript "my-file"
220 writeShellScript = name: text:
229 ${stdenv.shellDryRun} "$target"
234 * Similar to writeShellScript and writeScriptBin.
235 * Writes an executable Shell script to /nix/store/<store path>/bin/<name> and checks its syntax.
236 * Automatically includes interpreter above the contents passed.
239 * # Writes my-file to /nix/store/<store path>/bin/my-file and makes executable.
240 * writeShellScriptBin "my-file"
246 writeShellScriptBin = name : text :
250 destination = "/bin/${name}";
256 ${stdenv.shellDryRun} "$target"
261 * Similar to writeShellScriptBin and writeScriptBin.
262 * Writes an executable Shell script to /nix/store/<store path>/bin/<name> and
263 * checks its syntax with shellcheck and the shell's -n option.
264 * Automatically includes sane set of shellopts (errexit, nounset, pipefail)
265 * and handles creation of PATH based on runtimeInputs
267 * Note that the checkPhase uses stdenv.shell for the test run of the script,
268 * while the generated shebang uses runtimeShell. If, for whatever reason,
269 * those were to mismatch you might lose fidelity in the default checks.
272 * # Writes my-file to /nix/store/<store path>/bin/my-file and makes executable.
273 * writeShellApplication {
275 * runtimeInputs = [ curl w3m ];
277 * curl -s 'https://nixos.org' | w3m -dump -T text/html
281 writeShellApplication =
284 , runtimeInputs ? [ ]
290 destination = "/bin/${name}";
296 '' + lib.optionalString (runtimeInputs != [ ]) ''
298 export PATH="${lib.makeBinPath runtimeInputs}:$PATH"
305 if checkPhase == null then ''
307 ${stdenv.shellDryRun} "$target"
308 ${shellcheck}/bin/shellcheck "$target"
313 meta.mainProgram = name;
317 writeCBin = name: code:
322 passAsFile = ["code"];
323 # Pointless to do this on a remote machine.
324 preferLocalBuild = true;
325 allowSubstitutes = false;
329 mkdir -p "$(dirname "$n")"
330 mv "$codePath" code.c
331 $CC -x c code.c -o "$n"
335 /* concat a list of files to the nix store.
336 * The contents of files are added to the file in the store.
339 * # Writes my-file to /nix/store/<store path>
342 * files = [ drv1 "${drv2}/path/to/file" ];
344 * # See also the `concatText` helper function below.
346 * # Writes executable my-file to /nix/store/<store path>/bin/my-file
349 * files = [ drv1 "${drv2}/path/to/file" ];
351 * destination = "/bin/my-file";
355 { name # the name of the derivation
357 , executable ? false # run chmod +x ?
358 , destination ? "" # relative path appended to $out eg "/bin/foo"
359 , checkPhase ? "" # syntax checks, e.g. for scripts
363 { inherit files executable checkPhase meta destination; }
365 file=$out$destination
366 mkdir -p "$(dirname "$file")"
369 (test -n "$executable" && chmod +x "$file") || true
375 * Writes a text file to nix store with no optional parameters available.
378 * # Writes contents of files to /nix/store/<store path>
379 * concatText "my-file" [ file1 file2 ]
382 concatText = name: files: concatTextFile { inherit name files; };
385 * Writes a text file to nix store with and mark it as executable.
388 * # Writes contents of files to /nix/store/<store path>
389 * concatScript "my-file" [ file1 file2 ]
392 concatScript = name: files: concatTextFile { inherit name files; executable = true; };
396 * Create a forest of symlinks to the files in `paths'.
398 * This creates a single derivation that replicates the directory structure
399 * of all the input paths.
401 * BEWARE: it may not "work right" when the passed paths contain symlinks to directories.
404 * # adds symlinks of hello to current build.
405 * symlinkJoin { name = "myhello"; paths = [ pkgs.hello ]; }
407 * # adds symlinks of hello and stack to current build and prints "links added"
408 * symlinkJoin { name = "myexample"; paths = [ pkgs.hello pkgs.stack ]; postBuild = "echo links added"; }
410 * This creates a derivation with a directory structure like the following:
412 * /nix/store/sglsr5g079a5235hy29da3mq3hv8sjmm-myexample
414 * | |-- hello -> /nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10/bin/hello
415 * | `-- stack -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/bin/stack
417 * |-- bash-completion
419 * | `-- stack -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/share/bash-completion/completions/stack
421 * | `-- vendor_completions.d
422 * | `-- stack.fish -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/share/fish/vendor_completions.d/stack.fish
425 * symlinkJoin and linkFarm are similar functions, but they output
426 * derivations with different structure.
428 * symlinkJoin is used to create a derivation with a familiar directory
429 * structure (top-level bin/, share/, etc), but with all actual files being symlinks to
430 * the files in the input derivations.
432 * symlinkJoin is used many places in nixpkgs to create a single derivation
433 * that appears to contain binaries, libraries, documentation, etc from
434 * multiple input derivations.
436 * linkFarm is instead used to create a simple derivation with symlinks to
437 * other derivations. A derivation created with linkFarm is often used in CI
438 * as a easy way to build multiple derivations at once.
443 , preferLocalBuild ? true
444 , allowSubstitutes ? false
449 args = removeAttrs args_ [ "name" "postBuild" ]
451 inherit preferLocalBuild allowSubstitutes;
452 passAsFile = [ "paths" ];
453 }; # pass the defaults
454 in runCommand name args
457 for i in $(cat $pathsPath); do
458 ${lndir}/bin/lndir -silent $i $out
464 * Quickly create a set of symlinks to derivations.
466 * This creates a simple derivation with symlinks to all inputs.
468 * entries is a list of attribute sets like
469 * { name = "name" ; path = "/nix/store/..."; }
473 * # Symlinks hello and stack paths in store to current $out/hello-test and
475 * linkFarm "myexample" [ { name = "hello-test"; path = pkgs.hello; } { name = "foobar"; path = pkgs.stack; } ]
477 * This creates a derivation with a directory structure like the following:
479 * /nix/store/qc5728m4sa344mbks99r3q05mymwm4rw-myexample
480 * |-- foobar -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1
481 * `-- hello-test -> /nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
483 * See the note on symlinkJoin for the difference between linkFarm and symlinkJoin.
485 linkFarm = name: entries: runCommand name { preferLocalBuild = true; allowSubstitutes = false; }
488 ${lib.concatMapStrings (x: ''
489 mkdir -p "$(dirname ${lib.escapeShellArg x.name})"
490 ln -s ${lib.escapeShellArg "${x.path}"} ${lib.escapeShellArg x.name}
495 * Easily create a linkFarm from a set of derivations.
497 * This calls linkFarm with a list of entries created from the list of input
498 * derivations. It turns each input derivation into an attribute set
499 * like { name = drv.name ; path = drv }, and passes this to linkFarm.
503 * # Symlinks the hello, gcc, and ghc derivations in $out
504 * linkFarmFromDrvs "myexample" [ pkgs.hello pkgs.gcc pkgs.ghc ]
506 * This creates a derivation with a directory structure like the following:
508 * /nix/store/m3s6wkjy9c3wy830201bqsb91nk2yj8c-myexample
509 * |-- gcc-wrapper-9.2.0 -> /nix/store/fqhjxf9ii4w4gqcsx59fyw2vvj91486a-gcc-wrapper-9.2.0
510 * |-- ghc-8.6.5 -> /nix/store/gnf3s07bglhbbk4y6m76sbh42siym0s6-ghc-8.6.5
511 * `-- hello-2.10 -> /nix/store/k0ll91c4npk4lg8lqhx00glg2m735g74-hello-2.10
513 linkFarmFromDrvs = name: drvs:
514 let mkEntryFromDrv = drv: { name = drv.name; path = drv; };
515 in linkFarm name (map mkEntryFromDrv drvs);
519 * Make a package that just contains a setup hook with the given contents.
520 * This setup hook will be invoked by any package that includes this package
521 * as a buildInput. Optionally takes a list of substitutions that should be
522 * applied to the resulting script.
525 * # setup hook that depends on the hello package and runs ./myscript.sh
526 * myhellohook = makeSetupHook { deps = [ hello ]; } ./myscript.sh;
528 * # writes a Linux-exclusive setup hook where @bash@ myscript.sh is substituted for the
529 * # bash interpreter.
530 * myhellohookSub = makeSetupHook {
532 * substitutions = { bash = "${pkgs.bash}/bin/bash"; };
533 * meta.platforms = lib.platforms.linux;
536 * # setup hook with a package test
537 * myhellohookTested = makeSetupHook {
539 * substitutions = { bash = "${pkgs.bash}/bin/bash"; };
540 * meta.platforms = lib.platforms.linux;
541 * passthru.tests.greeting = callPackage ./test { };
544 makeSetupHook = { name ? "hook", deps ? [], substitutions ? {}, meta ? {}, passthru ? {} }: script:
549 # TODO 2023-01, no backport: simplify to inherit passthru;
551 // optionalAttrs (substitutions?passthru)
552 (warn "makeSetupHook (name = ${lib.strings.escapeNixString name}): `substitutions.passthru` is deprecated. Please set `passthru` directly."
553 substitutions.passthru);
556 mkdir -p $out/nix-support
557 cp ${script} $out/nix-support/setup-hook
558 '' + lib.optionalString (deps != []) ''
559 printWords ${toString deps} > $out/nix-support/propagated-build-inputs
560 '' + lib.optionalString (substitutions != {}) ''
561 substituteAll ${script} $out/nix-support/setup-hook
565 # Write the references (i.e. the runtime dependencies in the Nix store) of `path' to a file.
567 writeReferencesToFile = path: runCommand "runtime-deps"
569 exportReferencesGraph = ["graph" path];
577 for ((i = 0; i < nrRefs; i++)); do read ref; done
582 Write the set of references to a file, that is, their immediate dependencies.
584 This produces the equivalent of `nix-store -q --references`.
586 writeDirectReferencesToFile = path: runCommand "runtime-references"
588 exportReferencesGraph = ["graph" path];
596 if [[ $p == $path ]]; then
597 for ((i = 0; i < nrRefs; i++)); do
599 echo $ref >>./references
602 for ((i = 0; i < nrRefs; i++)); do
607 sort ./references >$out
612 * Extract a string's references to derivations and paths (its
613 * context) and write them to a text file, removing the input string
614 * itself from the dependency graph. This is useful when you want to
615 * make a derivation depend on the string's references, but not its
616 * contents (to avoid unnecessary rebuilds, for example).
618 * Note that this only works as intended on Nix >= 2.3.
620 writeStringReferencesToFile = string:
622 * The basic operation this performs is to copy the string context
623 * from `string' to a second string and wrap that string in a
624 * derivation. However, that alone is not enough, since nothing in the
625 * string refers to the output paths of the derivations/paths in its
626 * context, meaning they'll be considered build-time dependencies and
627 * removed from the wrapper derivation's closure. Putting the
628 * necessary output paths in the new string is however not very
629 * straightforward - the attrset returned by `getContext' contains
630 * only references to derivations' .drv-paths, not their output
631 * paths. In order to "convert" them, we try to extract the
632 * corresponding paths from the original string using regex.
635 # Taken from https://github.com/NixOS/nix/blob/130284b8508dad3c70e8160b15f3d62042fc730a/src/libutil/hash.cc#L84
636 nixHashChars = "0123456789abcdfghijklmnpqrsvwxyz";
637 context = builtins.getContext string;
638 derivations = lib.filterAttrs (n: v: v ? outputs) context;
639 # Objects copied from outside of the store, such as paths and
640 # `builtins.fetch*`ed ones
641 sources = lib.attrNames (lib.filterAttrs (n: v: v ? path) context);
647 name = lib.head (builtins.match "${builtins.storeDir}/[${nixHashChars}]+-(.*)\.drv" name);
650 # The syntax of output paths differs between outputs named `out`
651 # and other, explicitly named ones. For explicitly named ones,
652 # the output name is suffixed as `-name`, but `out` outputs
653 # aren't suffixed at all, and thus aren't easily distinguished
654 # from named output paths. Therefore, we find all the named ones
655 # first so we can use them to remove false matches when looking
656 # for `out` outputs (see the definition of `outputPaths`).
665 (builtins.split "(${builtins.storeDir}/[${nixHashChars}]+-${name}-${output})" string))
666 (lib.remove "out" value.outputs)))
673 if lib.elem "out" value.outputs then
676 # If the matched path is in `namedOutputPaths`,
677 # it's a partial match of an output path where
678 # the output name isn't `out`
679 lib.all (o: !lib.hasPrefix (lib.head x) o) namedOutputPaths)
680 (builtins.split "(${builtins.storeDir}/[${nixHashChars}]+-${name})" string)
684 allPaths = lib.concatStringsSep "\n" (lib.unique (sources ++ namedOutputPaths ++ outputPaths));
685 allPathsWithContext = builtins.appendContext allPaths context;
687 if builtins ? getContext then
688 writeText "string-references" allPathsWithContext
690 writeDirectReferencesToFile (writeText "string-file" string);
693 /* Print an error message if the file with the specified name and
694 * hash doesn't exist in the Nix store. This function should only
695 * be used by non-redistributable software with an unfree license
696 * that we need to require the user to download manually. It produces
697 * packages that cannot be built automatically.
703 * url = "http://example.com/download/";
704 * sha256 = "ffffffffffffffffffffffffffffffffffffffffffffffffffff";
707 requireFile = { name ? null
714 assert (message != null) || (url != null);
715 assert (sha256 != null) || (sha1 != null);
716 assert (name != null) || (url != null);
718 if message != null then message
720 Unfortunately, we cannot download file ${name_} automatically.
721 Please go to ${url} to download it yourself, and add it to the Nix store
723 nix-store --add-fixed ${hashAlgo} ${name_}
725 nix-prefetch-url --type ${hashAlgo} file:///path/to/${name_}
727 hashAlgo = if sha256 != null then "sha256" else "sha1";
728 hash = if sha256 != null then sha256 else sha1;
729 name_ = if name == null then baseNameOf (toString url) else name;
731 stdenvNoCC.mkDerivation {
733 outputHashMode = hashMode;
734 outputHashAlgo = hashAlgo;
736 preferLocalBuild = true;
737 allowSubstitutes = false;
738 builder = writeScript "restrict-message" ''
739 source ${stdenvNoCC}/setup
752 # Copy a path to the Nix store.
753 # Nix automatically copies files to the store before stringifying paths.
754 # If you need the store path of a file, ${copyPathToStore <path>} can be
755 # shortened to ${<path>}.
756 copyPathToStore = builtins.filterSource (p: t: true);
759 # Copy a list of paths to the Nix store.
760 copyPathsToStore = builtins.map copyPathToStore;
762 /* Applies a list of patches to a source directory.
766 * # Patching nixpkgs:
771 * url = "https://github.com/NixOS/nixpkgs/commit/1f770d20550a413e508e081ddc08464e9d08ba3d.patch";
772 * sha256 = "1nlzx171y3r3jbk0qhvnl711kmdk57jlq4na8f8bs8wz2pbffymr";
779 , name ? (if builtins.typeOf src == "path"
780 then builtins.baseNameOf src
782 if builtins.isAttrs src && builtins.hasAttr "name" src
784 else throw "applyPatches: please supply a `name` argument because a default name can only be computed when the `src` is a path or is an attribute set with a `name` attribute."
788 }: stdenvNoCC.mkDerivation {
789 inherit name src patches postPatch;
790 preferLocalBuild = true;
791 allowSubstitutes = false;
792 phases = "unpackPhase patchPhase installPhase";
793 installPhase = "cp -R ./ $out";
796 /* An immutable file in the store with a length of 0 bytes. */
797 emptyFile = runCommand "empty-file" {
798 outputHashAlgo = "sha256";
799 outputHashMode = "recursive";
800 outputHash = "0ip26j2h11n1kgkz36rl4akv694yz65hr72q4kv4b3lxcbi65b3p";
801 preferLocalBuild = true;
804 /* An immutable empty directory in the store. */
805 emptyDirectory = runCommand "empty-directory" {
806 outputHashAlgo = "sha256";
807 outputHashMode = "recursive";
808 outputHash = "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5";
809 preferLocalBuild = true;