mirror of
https://codeberg.org/mhwombat/nix-book.git
synced 2025-12-27 00:34:58 +08:00
5978 lines
No EOL
260 KiB
HTML
5978 lines
No EOL
260 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="generator" content="Asciidoctor 2.0.23">
|
||
<meta name="author" content="Amy de Buitléir">
|
||
<title>Wombat’s Book of Nix</title>
|
||
<style>
|
||
@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";
|
||
@import "https://cdn.jsdelivr.net/gh/asciidoctor/asciidoctor@2.0/data/stylesheets/asciidoctor-default.css";
|
||
|
||
.highlight01 {background: #66ffff}
|
||
.highlight02 {background: #b3ff66}
|
||
.highlight03 {background: #ffd966}
|
||
.highlight04 {background: #b366ff}
|
||
|
||
</style>
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||
<style>
|
||
pre.pygments .hll { background-color: #ffffcc }
|
||
pre.pygments { background: #f8f8f8; }
|
||
pre.pygments .tok-c { color: #3D7B7B; font-style: italic } /* Comment */
|
||
pre.pygments .tok-err { border: 1px solid #FF0000 } /* Error */
|
||
pre.pygments .tok-k { color: #008000; font-weight: bold } /* Keyword */
|
||
pre.pygments .tok-o { color: #666666 } /* Operator */
|
||
pre.pygments .tok-ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
|
||
pre.pygments .tok-cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
|
||
pre.pygments .tok-cp { color: #9C6500 } /* Comment.Preproc */
|
||
pre.pygments .tok-cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
|
||
pre.pygments .tok-c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
|
||
pre.pygments .tok-cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
|
||
pre.pygments .tok-gd { color: #A00000 } /* Generic.Deleted */
|
||
pre.pygments .tok-ge { font-style: italic } /* Generic.Emph */
|
||
pre.pygments .tok-ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
|
||
pre.pygments .tok-gr { color: #E40000 } /* Generic.Error */
|
||
pre.pygments .tok-gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||
pre.pygments .tok-gi { color: #008400 } /* Generic.Inserted */
|
||
pre.pygments .tok-go { color: #717171 } /* Generic.Output */
|
||
pre.pygments .tok-gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
||
pre.pygments .tok-gs { font-weight: bold } /* Generic.Strong */
|
||
pre.pygments .tok-gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||
pre.pygments .tok-gt { color: #0044DD } /* Generic.Traceback */
|
||
pre.pygments .tok-kc { color: #008000; font-weight: bold } /* Keyword.Constant */
|
||
pre.pygments .tok-kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
|
||
pre.pygments .tok-kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
|
||
pre.pygments .tok-kp { color: #008000 } /* Keyword.Pseudo */
|
||
pre.pygments .tok-kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
|
||
pre.pygments .tok-kt { color: #B00040 } /* Keyword.Type */
|
||
pre.pygments .tok-m { color: #666666 } /* Literal.Number */
|
||
pre.pygments .tok-s { color: #BA2121 } /* Literal.String */
|
||
pre.pygments .tok-na { color: #687822 } /* Name.Attribute */
|
||
pre.pygments .tok-nb { color: #008000 } /* Name.Builtin */
|
||
pre.pygments .tok-nc { color: #0000FF; font-weight: bold } /* Name.Class */
|
||
pre.pygments .tok-no { color: #880000 } /* Name.Constant */
|
||
pre.pygments .tok-nd { color: #AA22FF } /* Name.Decorator */
|
||
pre.pygments .tok-ni { color: #717171; font-weight: bold } /* Name.Entity */
|
||
pre.pygments .tok-ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
|
||
pre.pygments .tok-nf { color: #0000FF } /* Name.Function */
|
||
pre.pygments .tok-nl { color: #767600 } /* Name.Label */
|
||
pre.pygments .tok-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
|
||
pre.pygments .tok-nt { color: #008000; font-weight: bold } /* Name.Tag */
|
||
pre.pygments .tok-nv { color: #19177C } /* Name.Variable */
|
||
pre.pygments .tok-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
|
||
pre.pygments .tok-w { color: #bbbbbb } /* Text.Whitespace */
|
||
pre.pygments .tok-mb { color: #666666 } /* Literal.Number.Bin */
|
||
pre.pygments .tok-mf { color: #666666 } /* Literal.Number.Float */
|
||
pre.pygments .tok-mh { color: #666666 } /* Literal.Number.Hex */
|
||
pre.pygments .tok-mi { color: #666666 } /* Literal.Number.Integer */
|
||
pre.pygments .tok-mo { color: #666666 } /* Literal.Number.Oct */
|
||
pre.pygments .tok-sa { color: #BA2121 } /* Literal.String.Affix */
|
||
pre.pygments .tok-sb { color: #BA2121 } /* Literal.String.Backtick */
|
||
pre.pygments .tok-sc { color: #BA2121 } /* Literal.String.Char */
|
||
pre.pygments .tok-dl { color: #BA2121 } /* Literal.String.Delimiter */
|
||
pre.pygments .tok-sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
|
||
pre.pygments .tok-s2 { color: #BA2121 } /* Literal.String.Double */
|
||
pre.pygments .tok-se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
|
||
pre.pygments .tok-sh { color: #BA2121 } /* Literal.String.Heredoc */
|
||
pre.pygments .tok-si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
|
||
pre.pygments .tok-sx { color: #008000 } /* Literal.String.Other */
|
||
pre.pygments .tok-sr { color: #A45A77 } /* Literal.String.Regex */
|
||
pre.pygments .tok-s1 { color: #BA2121 } /* Literal.String.Single */
|
||
pre.pygments .tok-ss { color: #19177C } /* Literal.String.Symbol */
|
||
pre.pygments .tok-bp { color: #008000 } /* Name.Builtin.Pseudo */
|
||
pre.pygments .tok-fm { color: #0000FF } /* Name.Function.Magic */
|
||
pre.pygments .tok-vc { color: #19177C } /* Name.Variable.Class */
|
||
pre.pygments .tok-vg { color: #19177C } /* Name.Variable.Global */
|
||
pre.pygments .tok-vi { color: #19177C } /* Name.Variable.Instance */
|
||
pre.pygments .tok-vm { color: #19177C } /* Name.Variable.Magic */
|
||
pre.pygments .tok-il { color: #666666 } /* Literal.Number.Integer.Long */
|
||
</style>
|
||
</head>
|
||
<body class="book toc2 toc-left">
|
||
<div id="header">
|
||
<h1>Wombat’s Book of Nix</h1>
|
||
<div class="details">
|
||
<span id="author" class="author">Amy de Buitléir</span><br>
|
||
</div>
|
||
<div id="toc" class="toc2">
|
||
<div id="toctitle">Table of Contents</div>
|
||
<ul class="sectlevel1">
|
||
<li><a href="#_acknowledgments">Acknowledgments</a></li>
|
||
<li><a href="#_introduction">1. Introduction</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_why_nix">1.1. Why Nix?</a></li>
|
||
<li><a href="#_why_flakes">1.2. Why <em>flakes</em>?</a></li>
|
||
<li><a href="#_prerequisites">1.3. Prerequisites</a></li>
|
||
<li><a href="#_see_an_error_have_a_suggestion_or_want_more">1.4. See an error? Have a suggestion? Or want more?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_the_nix_language">2. The Nix language</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_introducing_the_nix_language">2.1. Introducing the Nix language</a></li>
|
||
<li><a href="#_data_types">2.2. Data types</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#type-string">2.2.1. Strings</a></li>
|
||
<li><a href="#type-integer">2.2.2. Integers</a></li>
|
||
<li><a href="#type-float">2.2.3. Floating point numbers</a></li>
|
||
<li><a href="#type-boolean">2.2.4. Boolean</a></li>
|
||
<li><a href="#type-path">2.2.5. Paths</a></li>
|
||
<li><a href="#type-list">2.2.6. Lists</a></li>
|
||
<li><a href="#type-set">2.2.7. Attribute sets</a></li>
|
||
<li><a href="#type-lambda">2.2.8. Functions</a></li>
|
||
<li><a href="#type-derivation">2.2.9. Derivations</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_stop_reading_this_chapter">2.3. Stop reading this chapter!</a></li>
|
||
<li><a href="#_the_nix_repl">2.4. The Nix REPL</a></li>
|
||
<li><a href="#_variables">2.5. Variables</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_assignment">2.5.1. Assignment</a></li>
|
||
<li><a href="#_immutability">2.5.2. Immutability</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_numeric_operations">2.6. Numeric operations</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_arithmetic_operators">2.6.1. Arithmetic operators</a></li>
|
||
<li><a href="#_floating_point_calculations">2.6.2. Floating-point calculations</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_string_operations">2.7. String operations</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_string_comparison">2.7.1. String comparison</a></li>
|
||
<li><a href="#_string_concatenation">2.7.2. String concatenation</a></li>
|
||
<li><a href="#_string_interpolation">2.7.3. String interpolation</a></li>
|
||
<li><a href="#_useful_built_in_functions_for_strings">2.7.4. Useful built-in functions for strings</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_boolean_operations">2.8. Boolean operations</a></li>
|
||
<li><a href="#_path_operations">2.9. Path operations</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_concatenating_paths">2.9.1. Concatenating paths</a></li>
|
||
<li><a href="#_concatenating_a_path_a_string">2.9.2. Concatenating a path + a string</a></li>
|
||
<li><a href="#_concatenating_a_string_a_path">2.9.3. Concatenating a string + a path</a></li>
|
||
<li><a href="#_useful_built_in_functions_for_paths">2.9.4. Useful built-in functions for paths</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_list_operations">2.10. List operations</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_list_concatenation">2.10.1. List concatenation</a></li>
|
||
<li><a href="#_useful_built_in_functions_for_lists">2.10.2. Useful built-in functions for lists</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_attribute_set_operations">2.11. Attribute set operations</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_selection">2.11.1. Selection</a></li>
|
||
<li><a href="#_query">2.11.2. Query</a></li>
|
||
<li><a href="#_union">2.11.3. Union</a></li>
|
||
<li><a href="#rec-attrset">2.11.4. Recursive attribute sets</a></li>
|
||
<li><a href="#_useful_built_in_functions_for_attribute_sets">2.11.5. Useful built-in functions for attribute sets</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#functions">2.12. Functions</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_anonymous_functions">2.12.1. Anonymous functions</a></li>
|
||
<li><a href="#_named_functions_and_function_application">2.12.2. Named functions and function application</a></li>
|
||
<li><a href="#_multiple_parameters_using_nested_functions">2.12.3. Multiple parameters using nested functions</a></li>
|
||
<li><a href="#_multiple_parameters_using_attribute_sets">2.12.4. Multiple parameters using attribute sets</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#argument-sets">2.13. Argument sets</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_set_patterns">2.13.1. Set patterns</a></li>
|
||
<li><a href="#_optional_parameters">2.13.2. Optional parameters</a></li>
|
||
<li><a href="#_variadic_attributes">2.13.3. Variadic attributes</a></li>
|
||
<li><a href="#at-patterns">2.13.4. @-patterns</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#derivations">2.14. Derivations</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_instantiation_vs_realisation">2.14.1. Instantiation vs Realisation</a></li>
|
||
<li><a href="#_instantiate_evaluate_a_derivation">2.14.2. Instantiate (evaluate) a derivation</a></li>
|
||
<li><a href="#_find_out_where_the_package_would_be_or_was_installed">2.14.3. Find out where the package would be (or was) installed</a></li>
|
||
<li><a href="#_build_realise_a_derivation">2.14.4. Build (realise) a derivation.</a></li>
|
||
<li><a href="#_remove_a_derivation">2.14.5. Remove a derivation</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_if_expressions">2.15. If expressions</a></li>
|
||
<li><a href="#_let_expressions">2.16. Let expressions</a></li>
|
||
<li><a href="#_with_expressions">2.17. With expressions</a></li>
|
||
<li><a href="#_inherit">2.18. Inherit</a></li>
|
||
<li><a href="#_import">2.19. Import</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_nixpkgs">3. Nixpkgs</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#genAttrs">3.1. <code>lib.genAttrs</code></a></li>
|
||
<li><a href="#getExe">3.2. <code>lib.getExe</code> and <code>lib.getExe'</code></a></li>
|
||
<li><a href="#flakeExposed">3.3. <code>lib.systems.flakeExposed</code></a></li>
|
||
<li><a href="#mkShell">3.4. <code>pkgs.mkShell</code> and <code>pkgs.mkShellNoCC</code></a></li>
|
||
<li><a href="#mkDerivation">3.5. <code>stdenv.mkDerivation</code></a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_hello_flake">4. Hello, flake!</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_flake_outputs">4.1. Flake outputs</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_the_hello_flake_repo">5. The hello-flake repo</a></li>
|
||
<li><a href="#_flake_structure">6. Flake structure</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#flake-inputs">6.1. Inputs</a></li>
|
||
<li><a href="#flake-outputs">6.2. Outputs</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_a_generic_flake">7. A generic flake</a></li>
|
||
<li><a href="#_another_look_at_hello_flake">8. Another look at hello-flake</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#standard-environment">8.1. The Nix standard environment</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_a_new_flake_from_scratch">9. A new flake from scratch</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_haskell">9.1. Haskell</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_a_simple_haskell_program">9.1.1. A simple Haskell program</a></li>
|
||
<li><a href="#_running_the_program_manually_optional">9.1.2. Running the program manually (optional)</a>
|
||
<ul class="sectlevel4">
|
||
<li><a href="#_some_unsuitable_shells">Some unsuitable shells</a></li>
|
||
<li><a href="#_a_suitable_shell_for_a_quick_test">A suitable shell for a quick test</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_the_cabal_file">9.1.3. The cabal file</a></li>
|
||
<li><a href="#_building_the_program_manually_optional">9.1.4. Building the program manually (optional)</a></li>
|
||
<li><a href="#haskell-flake">9.1.5. The Nix flake</a></li>
|
||
<li><a href="#_building_the_program">9.1.6. Building the program</a></li>
|
||
<li><a href="#_running_the_program">9.1.7. Running the program</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_python">9.2. Python</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_a_simple_python_program">9.2.1. A simple Python program</a></li>
|
||
<li><a href="#_running_the_program_manually_optional_2">9.2.2. Running the program manually (optional)</a></li>
|
||
<li><a href="#_configuring_setuptools">9.2.3. Configuring setuptools</a></li>
|
||
<li><a href="#_building_the_program_manually_optional_2">9.2.4. Building the program manually (optional)</a></li>
|
||
<li><a href="#python-flake">9.2.5. The Nix flake</a></li>
|
||
<li><a href="#_building_the_program_2">9.2.6. Building the program</a></li>
|
||
<li><a href="#_running_the_program_2">9.2.7. Running the program</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_recipes">10. Recipes</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_running_programs_directly_without_installing_them">10.1. Running programs directly (without installing them)</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_run_a_top_level_package_from_the_nixpkgsnixos_repo">10.1.1. Run a top level package from the Nixpkgs/NixOS repo</a></li>
|
||
<li><a href="#flakeref">10.1.2. Run a flake</a>
|
||
<ul class="sectlevel4">
|
||
<li><a href="#_run_a_flake_defined_in_a_local_file">Run a flake defined in a local file</a></li>
|
||
<li><a href="#_run_a_flake_defined_in_a_remote_git_repo">Run a flake defined in a remote git repo</a></li>
|
||
<li><a href="#_run_a_flake_defined_in_a_zip_archive">Run a flake defined in a zip archive</a></li>
|
||
<li><a href="#_run_a_flake_defined_in_a_compressed_tar_archive">Run a flake defined in a compressed tar archive</a></li>
|
||
<li><a href="#_run_other_types_of_flake_references">Run other types of flake references</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_ad_hoc_environments">10.2. Ad hoc environments</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_access_a_top_level_package_from_the_nixpkgsnixos_repo">10.2.1. Access a top level package from the Nixpkgs/NixOS repo</a></li>
|
||
<li><a href="#_access_a_flake">10.2.2. Access a flake</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#shebang">10.3. Scripts</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_access_a_top_level_package_from_the_nixpkgsnixos_repo_2">10.3.1. Access a top level package from the Nixpkgs/NixOS repo</a></li>
|
||
<li><a href="#_access_a_flake_2">10.3.2. Access a flake</a></li>
|
||
<li><a href="#_access_a_haskell_library_package_in_the_nixpkgs_repo_without_a_cabal_file">10.3.3. Access a Haskell library package in the nixpkgs repo (without a <code>.cabal</code> file)</a></li>
|
||
<li><a href="#_access_a_python_library_package_in_the_nixpkgs_repo_without_using_a_python_builder">10.3.4. Access a Python library package in the nixpkgs repo (without using a Python builder)</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_development_environments">10.4. Development environments</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_access_a_top_level_package_from_the_nixpkgsnixos_repo_3">10.4.1. Access a top level package from the Nixpkgs/NixOS repo</a></li>
|
||
<li><a href="#_access_a_flake_3">10.4.2. Access a flake</a></li>
|
||
<li><a href="#_access_a_haskell_library_package_in_the_nixpkgs_repo_without_using_a_cabal_file">10.4.3. Access a Haskell library package in the nixpkgs repo (without using a <code>.cabal</code> file)</a></li>
|
||
<li><a href="#_set_an_environment_variable">10.4.4. Set an environment variable</a></li>
|
||
<li><a href="#devshell-nix-non-flake">10.4.5. Access a non-flake package (not in nixpkgs)</a>
|
||
<ul class="sectlevel4">
|
||
<li><a href="#devshell-pure">If the nix derivation does not require nixpkgs</a></li>
|
||
<li><a href="#devshell-impure">If the nix derivation requires <code>nixpkgs</code></a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_buildruntime_environments">10.5. Build/runtime environments</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_access_a_flake_4">10.5.1. Access a flake</a></li>
|
||
<li><a href="#_access_a_haskell_library_package_in_the_nixpkgs_repo">10.5.2. Access a Haskell library package in the nixpkgs repo</a></li>
|
||
<li><a href="#_access_to_a_haskell_package_defined_in_a_flake">10.5.3. Access to a Haskell package defined in a flake</a></li>
|
||
<li><a href="#_access_a_non_flake_package_not_in_nixpkgs">10.5.4. Access a non-flake package (not in nixpkgs)</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_an_old_style_nix_shell_with_access_to_a_flake">10.6. An (old-style) Nix shell with access to a flake</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div id="content">
|
||
<div id="preamble">
|
||
<div class="sectionbody">
|
||
<div class="imageblock">
|
||
<div class="content">
|
||
<img src="images/wombat.svg" alt="wombat reclining against a lambda">
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This book is available
|
||
<a href="https://mhwombat.codeberg.page/nix-book/">online</a>
|
||
and as a downloadable
|
||
<a href="https://codeberg.org/mhwombat/nix-book/raw/branch/pages/wombats-book-of-nix.pdf">PDF</a>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><em>Last updated 2025-10-14 at 11:02:03 IST</em>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_acknowledgments">Acknowledgments</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>I would like to thank the patient people on the
|
||
<a href="https://discourse.nixos.org/">NixOS Discourse Forum</a>
|
||
who answered my many questions,
|
||
especially <code>cdepillabout</code>, <code>FedericoSchonborn</code>, <code>tejing</code> and <code>smkuehnhold</code>.
|
||
Any mistakes in this book are my own, however.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>I would also like to thank Luca Bruno (aka Lethalman).
|
||
Although I have never interacted with them personally,
|
||
I learned a great deal from
|
||
their series of tutorials called <a href="https://nixos.org/guides/nix-pills/">Nix pills</a>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_introduction">1. Introduction</h2>
|
||
<div class="sectionbody">
|
||
<div class="sect2">
|
||
<h3 id="_why_nix">1.1. Why Nix?</h3>
|
||
<div class="paragraph">
|
||
<p>If you’ve opened this PDF, you already have your own motivation for
|
||
learning Nix. Here’s how it helps me. As a researcher, I tend to work on
|
||
a series of short-term projects, mostly demos and prototypes. For each
|
||
one, I typically develop some software using a compiler, often with some
|
||
open source libraries. Often I use other tools to analyse data or
|
||
generate documentation, for example.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Problems would arise when handing off the project to colleagues; they
|
||
would report errors when trying to build or run the project. Belatedly I
|
||
would realise that my code relies on a library that they need to
|
||
install. Or perhaps they had installed the library, but the version
|
||
they’re using is incompatible.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Using containers helped with the problem. However, I didn’t want to
|
||
<em>develop</em> in a container. I did all my development in my nice, familiar,
|
||
environment with my custom aliases and shell prompt. and <em>then</em> I
|
||
containerised the software. This added step was annoying for me, and if
|
||
my colleague wanted to do some additional development, they would
|
||
probably extract all of the source code from the container first anyway.
|
||
Containers are great, but this isn’t the ideal use case for them.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Nix allows me to work in my custom environment, but forces me to specify
|
||
any dependencies. It automatically tracks the version of each dependency
|
||
so that it can replicate the environment wherever and whenever it’s
|
||
needed.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_why_flakes">1.2. Why <em>flakes</em>?</h3>
|
||
<div class="paragraph">
|
||
<p>Flakes are labeled as an experimental feature, so it might seem safer to
|
||
avoid them. However, they have been in use for years, and there is
|
||
widespread adoption, so the aren’t going away any time soon. Flakes are
|
||
easier to understand, and offer more features than the traditional Nix
|
||
approach. After weighing the pros and cons, I feel it’s better to learn
|
||
and use flakes; and this seems to be the general consensus.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_prerequisites">1.3. Prerequisites</h3>
|
||
<div class="paragraph">
|
||
<p>To follow along with the examples in this book, you will need access to a computer
|
||
or (virtual machine) with Nix (or NixOS) installed and <em>flakes enabled</em>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>I recommend the installer from
|
||
<a href="https://zero-to-nix.com/start/install">zero-to-nix.com</a>. This installer
|
||
automatically enables flakes.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>More documentation (and another installer) available at
|
||
<a href="https://nixos.org/">nixos.org</a>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>To <em>enable flakes on an existing Nix or NixOS installation</em>,
|
||
see the instructions in the <a href="https://nixos.wiki/wiki/Flakes">NixOS wiki</a>.</p>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>There are hyphenated and un-hyphenated versions of many Nix commands.
|
||
For example, <code>nix-shell</code> and <code>nix shell</code> are two different commands.
|
||
Don’t confuse them!</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Generally speaking, the un-hyphenated versions are for working directly
|
||
with flakes, while the hyphenated versions are for everything else.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_see_an_error_have_a_suggestion_or_want_more">1.4. See an error? Have a suggestion? Or want more?</h3>
|
||
<div class="paragraph">
|
||
<p>If notice an error in this book, have a suggestion on how to improve it,
|
||
or you’re interested in an area that isn’t covered, feel free to open an
|
||
<a href="https://codeberg.org/mhwombat/nix-book/issues">issue</a>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_the_nix_language">2. The Nix language</h2>
|
||
<div class="sectionbody">
|
||
<div class="sect2">
|
||
<h3 id="_introducing_the_nix_language">2.1. Introducing the Nix language</h3>
|
||
<div class="paragraph">
|
||
<p>Nix and NixOS use a functional programming language called <em>Nix</em>
|
||
to specify how to build and install software,
|
||
and how to configure system, user, and project-specific environments.
|
||
(Yes, “Nix” is the name of both the package manager and the language it uses.)</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Nix is a <em>functional</em> language.
|
||
In a <em>procedural</em> language such as C or Java,
|
||
the focus is on writing a series of <em>steps</em> (statements) to achieve a desired result.
|
||
By contrast, in a functional language the focus is on <em>defining</em> the desired result.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In the case of Nix, the desired result is usually a <em>derivation</em>:
|
||
a software package that has been built and made available for use.
|
||
The Nix language has been designed for that purpose,
|
||
and thus has some features you don’t typically find in general-purpose languages.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_data_types">2.2. Data types</h3>
|
||
<div class="sect3">
|
||
<h4 id="type-string">2.2.1. Strings</h4>
|
||
<div class="paragraph">
|
||
<p>Strings are enclosed by double quotes (<code>"</code>), or <em>two</em> single quotes (<code>'</code>).</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">"Hello, world!"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">''This string contains "double quotes"''</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>They can span multiple lines.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">''Old pond
|
||
A frog jumps in
|
||
The sound of water
|
||
-- Basho''</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="type-integer">2.2.2. Integers</h4>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">7
|
||
256</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="type-float">2.2.3. Floating point numbers</h4>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">3.14
|
||
6.022e23</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="type-boolean">2.2.4. Boolean</h4>
|
||
<div class="paragraph">
|
||
<p>The Boolean values in Nix are <code>true</code> and <code>false</code>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="type-path">2.2.5. Paths</h4>
|
||
<div class="paragraph">
|
||
<p>File paths play an important role in building software, so Nix has a special data type for them.
|
||
Paths may be absolute (e.g. <code>/bin/sh</code>) or relative (e.g. <code>./data/file1.csv</code>).
|
||
Note that paths are not enclosed in quotation marks; they are not strings!</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Enclosing a path in angle brackets, e.g. <nixpkgs> causes the directories
|
||
listed in the environment variable NIX_PATH to be searched for the given
|
||
file or directory name.
|
||
These are called <em>lookup paths</em>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="type-list">2.2.6. Lists</h4>
|
||
<div class="paragraph">
|
||
<p>List elements are enclosed in square brackets and separated by spaces (not commas).
|
||
The elements need not be of the same type.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">[ "apple" 123 ./build.sh false ]</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Lists can be empty.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">[]</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>List elements can be of any type, and can even be lists themselves.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">[ [ 1 2 ] [ 3 4 ] ]</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="type-set">2.2.7. Attribute sets</h4>
|
||
<div class="paragraph">
|
||
<p>Attribute sets associate keys with values.
|
||
They are enclosed in curly brackets, and the associations are terminated by semi-colons.
|
||
Note that the final semi-colon before the closing bracket is required.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">{ name = "Professor Paws"; age = 10; species = "cat"; }</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The keys of an attribute set must be strings.
|
||
When the key is not a valid identifier, it must be enclosed in quotation marks.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">{ abc = true; "123" = false; }</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Attribute sets can be empty.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">{}</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Values of attribute sets can be of any type, and can even be attribute sets themselves.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">{ name = { first = "Professor"; last = "Paws"; }; age = 10; species = "cat"; }</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In <a href="#rec-attrset">Section 2.11.4, “Recursive attribute sets”</a> you will be introduced to a special type of attribute set.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>In some Nix documentation, and in many articles about Nix,
|
||
attribute sets are simply called "sets".</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="type-lambda">2.2.8. Functions</h4>
|
||
<div class="paragraph">
|
||
<p>We’ll learn how to write functions in <a href="#functions">Section 2.12, “Functions”</a>.
|
||
For now, note that functions are "first-class values",
|
||
meaning that they can be treated like any other data type.
|
||
For example, a function can be assigned to a variable, appear as an element in a list,
|
||
be associated with a key in an attribute set, or be passed as input to another function.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">[ "apple" 123 ./build.sh false (x: x*x) ]
|
||
{ name = "Professor Paws"; age = 10; species = "cat"; formula = (x: x*2); }</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="type-derivation">2.2.9. Derivations</h4>
|
||
<div class="paragraph">
|
||
<p>A <a href="https://nix.dev/manual/nix/latest/store/derivation/">derivation</a>
|
||
is an attribute set, but one which is a recipe for producing a Nix package.
|
||
We’ll learn how to write derivations in <a href="#derivations">Section 2.14, “Derivations”</a>.
|
||
For now, note that derivations are "first-class values",
|
||
meaning that they can be treated like any other data type.
|
||
For example, a derivation can be assigned to a variable, appear as an element in a list,
|
||
be associated with a key in an attribute set, or be passed as input to a function.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_stop_reading_this_chapter">2.3. Stop reading this chapter!</h3>
|
||
<div class="paragraph">
|
||
<p>When I first began using Nix, it seemed logical to start by learning the Nix language.
|
||
However, after following an in-depth tutorial,
|
||
I found that I didn’t know how to do anything useful with the language!
|
||
It wasn’t until later that I understood what I was missing:
|
||
a guide to the most useful library functions.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>When working with Nix or NixOS,
|
||
it’s very rare that you’ll want to write something from scratch.
|
||
Instead, you’ll use one of the many library functions
|
||
that make things easier and shield you from the underlying complexity.
|
||
Many of these functions are language-specific,
|
||
and the documentation for them may be inadequate.
|
||
Often the easiest (or only) way to learn to use them
|
||
is to find an example that does something similar to what you want,
|
||
and then modify the function parameters to suit your needs.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>At this point you’ve learned enough of the Nix language
|
||
to do the majority of common Nix tasks.
|
||
So when I say "Stop reading this chapter!", I’m only half-joking.
|
||
Instead I suggest that you <em>skim</em> the rest of this chapter,
|
||
paying special attention to anything marked with <span class="icon"><i class="fa fa-exclamation-circle"></i></span>.
|
||
Then move on to the following chapters
|
||
where you will learn how to develop and package software using Nix.
|
||
Afterward, come back to this chapter and read it in more detail.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>While writing this book, I anticipated that readers would want to skip around,
|
||
alternating between pure learning and learning-by-doing.
|
||
I’ve tried to structure the book to support that;
|
||
providing extensive cross-references to earlier and later sections,
|
||
and sometimes repeating information from earlier chapters that you might have skipped.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_the_nix_repl">2.4. The Nix REPL</h3>
|
||
<div class="paragraph">
|
||
<p>The Nix REPL (REPL is an acronym for Read-Eval-Print-Loop)
|
||
is an interactive environment for evaluating and debugging Nix code.
|
||
It’s also a good place to begin learning Nix.
|
||
Enter it using the command <code>nix repl</code>.
|
||
Within the REPL, type <code>:?</code> to see a list of available commands.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>$ nix repl
|
||
Welcome to Nix 2.18.1. Type :? for help.
|
||
|
||
nix-repl> :?
|
||
The following commands are available:
|
||
|
||
<expr> Evaluate and print expression
|
||
<x> = <expr> Bind expression to variable
|
||
:a, :add <expr> Add attributes from resulting set to scope
|
||
:b <expr> Build a derivation
|
||
:bl <expr> Build a derivation, creating GC roots in the
|
||
working directory
|
||
:e, :edit <expr> Open package or function in $EDITOR
|
||
:i <expr> Build derivation, then install result into
|
||
current profile
|
||
:l, :load <path> Load Nix expression and add it to scope
|
||
:lf, :load-flake <ref> Load Nix flake and add it to scope
|
||
:p, :print <expr> Evaluate and print expression recursively
|
||
:q, :quit Exit nix-repl
|
||
:r, :reload Reload all files
|
||
:sh <expr> Build dependencies of derivation, then start
|
||
nix-shell
|
||
:t <expr> Describe result of evaluation
|
||
:u <expr> Build derivation, then start nix-shell
|
||
:doc <expr> Show documentation of a builtin function
|
||
:log <expr> Show logs for a derivation
|
||
:te, :trace-enable [bool] Enable, disable or toggle showing traces for
|
||
errors
|
||
:?, :help Brings up this help menu</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>A command that is useful to beginners is <code>:t</code>, which tells you the type of an expression.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> :t { abc = true; "123" = false; }
|
||
a set
|
||
|
||
nix-repl> f = x: y: x * y
|
||
|
||
nix-repl> :t f
|
||
a function</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note that the command to exit the REPL is <code>:q</code> (or <code>:quit</code> if you prefer).</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_variables">2.5. Variables</h3>
|
||
<div class="sect3">
|
||
<h4 id="_assignment">2.5.1. Assignment</h4>
|
||
<div class="paragraph">
|
||
<p>You can declare variables in Nix and assign values to them.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> a = 7
|
||
|
||
nix-repl> b = 3
|
||
|
||
nix-repl> a - b
|
||
4</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>The spaces before and after operators aren’t always required.
|
||
However, you can get unexpected results when you omit them, as shown in the following example.
|
||
Nix allows hyphens (<code>-</code>) in variable names,
|
||
so <code>a-b</code> is interpreted as the name of a variable rather than a subtraction operation.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> a-b
|
||
error: undefined variable 'a-b'
|
||
|
||
at «string»:1:1:
|
||
|
||
1| a-b
|
||
| ^</code></pre>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_immutability">2.5.2. Immutability</h4>
|
||
<div class="paragraph">
|
||
<p>In Nix, values are <em>immutable</em>;
|
||
once you assign a value to a variable, you cannot change it.
|
||
You can, however, create a new variable with the same name, but in a different scope.
|
||
Don’t worry if you don’t completely understand the previous sentence;
|
||
we will see some examples in <a href="#functions">Section 2.12, “Functions”</a>, <a href="#_let_expressions">Section 2.16, “Let expressions”</a>, and <a href="#_with_expressions">Section 2.17, “With expressions”</a>.</p>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>In the Nix REPL, it may seem like the values of variables can be changed,
|
||
in <em>apparent</em> contradiction to the previous paragraph.
|
||
In truth, the REPL works some behind-the-scenes "magic",
|
||
effectively creating a new nested scope with each assignment.
|
||
This makes it much easier to experiment in the REPL.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> x = 1
|
||
|
||
nix-repl> x
|
||
1
|
||
|
||
nix-repl> x = x + 1 # creates a new variable called "x"; the original is no longer in scope
|
||
|
||
nix-repl> x
|
||
2</code></pre>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_numeric_operations">2.6. Numeric operations</h3>
|
||
<div class="sect3">
|
||
<h4 id="_arithmetic_operators">2.6.1. Arithmetic operators</h4>
|
||
<div class="paragraph">
|
||
<p>The usual arithmetic operators are provided.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> 1 + 2 # addition
|
||
3
|
||
|
||
nix-repl> 5 - 3 # subtraction
|
||
2
|
||
|
||
nix-repl> 3 * 4 # multiplication
|
||
12
|
||
|
||
nix-repl> 6 / 2 # division
|
||
3
|
||
|
||
nix-repl> -1 # negation
|
||
-1</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>As mentioned in <a href="#_variables">Section 2.5, “Variables”</a>,
|
||
you can get unexpected results when you omit spaces around operators.
|
||
Consider the following example.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> 6/2
|
||
/home/amy/codeberg/nix-book/6/2</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>What happened?
|
||
Let’s use the <code>:t</code> command to find out the type of the expression.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> :t 6/2
|
||
a path</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If an expression can be interpreted as a path, Nix will do so.
|
||
This is useful, because paths are <em>far</em> more commonly used in Nix expressions
|
||
than arithmetic operators.
|
||
In this case, Nix interpreted <code>6/2</code> as a relative path from the current directory,
|
||
which in the above example was <code>/home/amy/codeberg/nix-book</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Adding a space after the <code>/</code> operator produces the expected result.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> 6/ 2
|
||
3</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>To avoid surprises and improve readability, I prefer to use spaces before and after all operators.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_floating_point_calculations">2.6.2. Floating-point calculations</h4>
|
||
<div class="paragraph">
|
||
<p>Numbers without a decimal point are assumed to be integers.
|
||
To ensure that a number is interpreted as a floating-point value, add a decimal point.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> :t 5
|
||
an integer
|
||
|
||
nix-repl> :t 5.0
|
||
a float
|
||
|
||
nix-repl> :t 5.
|
||
a float</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In the example below, the first expression results in integer division (rounding down),
|
||
while the second produces a floating-point result.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> 5 / 3
|
||
1
|
||
|
||
nix-repl> 5.0 / 3
|
||
1.66667</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_string_operations">2.7. String operations</h3>
|
||
<div class="sect3">
|
||
<h4 id="_string_comparison">2.7.1. String comparison</h4>
|
||
<div class="paragraph">
|
||
<p>Nix provides the usual lexicographic comparison operations.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> "apple" == "banana" # equality
|
||
false
|
||
|
||
nix-repl> "apple" != "banana" # inequality
|
||
true
|
||
|
||
nix-repl> "apple" < "banana" # comes alphabetically before?
|
||
true
|
||
|
||
nix-repl> "apple" <= "banana" # equal or comes alphabetically before?
|
||
true
|
||
|
||
nix-repl> "apple" > "banana" # comes alphabetically after?
|
||
false
|
||
|
||
nix-repl> "apple" >= "banana" # equal or comes alphabetically after?
|
||
false</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_string_concatenation">2.7.2. String concatenation</h4>
|
||
<div class="paragraph">
|
||
<p>String concatenation uses the <code>+</code> operator.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> "Hello, " + "world!"
|
||
"Hello, world!"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_string_interpolation">2.7.3. String interpolation</h4>
|
||
<div class="paragraph">
|
||
<p>You can use the <code>${<em>variable</em>}</code> syntax to insert the value of a variable within a string.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> name = "Wombat"
|
||
|
||
nix-repl> "Hi, I'm ${name}."
|
||
"Hi, I'm Wombat."</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>You cannot mix numbers and strings.
|
||
Earlier we set <code>a = 7</code>, so the following expression fails.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> "My favourite number is ${a}."
|
||
error:
|
||
… while evaluating a path segment
|
||
|
||
at «string»:1:25:
|
||
|
||
1| "My favourite number is ${a}."
|
||
| ^
|
||
|
||
error: cannot coerce an integer to a string</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Nix does provide functions for converting between types; we’ll see these in the
|
||
<a href="#convert-to-string">next section</a>.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_useful_built_in_functions_for_strings">2.7.4. Useful built-in functions for strings</h4>
|
||
<div class="paragraph">
|
||
<p>Nix provides some built-in functions for working with strings;
|
||
a few examples are shown below.
|
||
For more information on these and other built-in functions, see the Nix Manual
|
||
(<a href="https://nixos.org/manual/nix/stable/language/builtins" class="bare">https://nixos.org/manual/nix/stable/language/builtins</a>).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>How long is this string?</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.stringLength "supercalifragilisticexpialidocious"
|
||
34</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Given a starting position and a length, extract a substring.
|
||
The first character of a string has index <code>0</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.substring 3 6 "hayneedlestack"
|
||
"needle"</code></pre>
|
||
</div>
|
||
</div>
|
||
<div id="convert-to-string" class="paragraph">
|
||
<p>Convert an expression to a string.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.toString 7
|
||
"7"
|
||
|
||
nix-repl> builtins.toString (3*4 + 1)
|
||
"13"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_boolean_operations">2.8. Boolean operations</h3>
|
||
<div class="paragraph">
|
||
<p>The usual boolean operators are available.
|
||
Recall that earlier we set <code>a = 7</code> and <code>b = 3</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> a == 7 # equality test
|
||
true
|
||
|
||
nix-repl> b != 3 # inequality
|
||
false
|
||
|
||
nix-repl> a > 12 # greater than
|
||
false
|
||
|
||
nix-repl> b >= 2 # greater than or equal
|
||
true
|
||
|
||
nix-repl> a < b # less than
|
||
false
|
||
|
||
nix-repl> b <= a # less than or equal
|
||
true
|
||
|
||
nix-repl> !true # logical negation
|
||
false
|
||
|
||
nix-repl> (3 * a == 21) && (a > b) # logical AND
|
||
true
|
||
|
||
nix-repl> (b > a) || (b > 10) # logical OR
|
||
false</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>One operator that might be unfamiliar to you is <em>logical implication</em>, which uses the symbol <code>→</code>.
|
||
The expression <code>u → v</code> is equivalent to <code>!u || v</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> u = false
|
||
|
||
nix-repl> v = true
|
||
|
||
nix-repl> u -> v
|
||
true
|
||
|
||
nix-repl> v -> u
|
||
false</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_path_operations">2.9. Path operations</h3>
|
||
<div class="paragraph">
|
||
<p>Any expression that contains a forward slash (<code>/</code>) <em>not</em> followed by a space
|
||
is interpreted as a path.
|
||
To refer to a file or directory relative to the current directory, prefix it with <code>./</code>.
|
||
You can specify the current directory as <code>./.</code></p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> ./file.txt
|
||
/home/amy/codeberg/nix-book/file.txt
|
||
|
||
nix-repl> ./.
|
||
/home/amy/codeberg/nix-book</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_concatenating_paths">2.9.1. Concatenating paths</h4>
|
||
<div class="paragraph">
|
||
<p>Paths can be concatenated to produce a new path.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> /home/wombat + /bin/sh
|
||
/home/wombat/bin/sh
|
||
|
||
nix-repl> :t /home/wombat + /bin/sh
|
||
a path</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>Relative paths are made absolute when they are parsed, which occurs before concatenation.
|
||
This is why the result in the example below is not <code>/home/wombat/file.txt</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> /home/wombat + ./file.txt
|
||
/home/wombat/home/amy/codeberg/nix-book/file.txt</code></pre>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_concatenating_a_path_a_string">2.9.2. Concatenating a path + a string</h4>
|
||
<div class="paragraph">
|
||
<p>A path can be concatenated with a string to produce a new path.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> /home/wombat + "/file.txt"
|
||
/home/wombat/file.txt
|
||
|
||
nix-repl> :t /home/wombat + "/file.txt"
|
||
a path</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>The Nix reference manual says that the string must not "have a string context" that refers to a store path.
|
||
String contexts are beyond the scope of this book;
|
||
for more information see <a href="https://nixos.org/manual/nix/stable/language/operators#path-concatenation" class="bare">https://nixos.org/manual/nix/stable/language/operators#path-concatenation</a>.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_concatenating_a_string_a_path">2.9.3. Concatenating a string + a path</h4>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>Strings can be concatenated with paths, but with a side-effect that may surprise you:
|
||
if the path exists, the file is copied to the Nix store!
|
||
The result is a string, not a path.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In the example below, you might expect the result to be <code>"home/wombat/file.nix"</code>.
|
||
However, the file <code>file.txt</code> is copied to <code>/nix/store/gp8ba25gpwvbqizqfr58jr014gmv1hd8-file.txt</code>
|
||
before concatenating it to the string.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> "/home/wombat" + ./file.txt
|
||
"/home/wombat/nix/store/gp8ba25gpwvbqizqfr58jr014gmv1hd8-file.txt"</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>When concatenating a string with a path, the path must exist.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> "/home/wombat" + ./no-such-file.txt
|
||
error (ignored): error: end of string reached
|
||
error: getting status of '/home/amy/codeberg/nix-book/no-such-file.txt': No such file or directory</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_useful_built_in_functions_for_paths">2.9.4. Useful built-in functions for paths</h4>
|
||
<div class="paragraph">
|
||
<p>Nix provides some built-in functions for working with paths;
|
||
a few examples are shown below.
|
||
For more information on these and other built-in functions, see the Nix Manual
|
||
(<a href="https://nixos.org/manual/nix/stable/language/builtins" class="bare">https://nixos.org/manual/nix/stable/language/builtins</a>).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Does the path exist?</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.pathExists ./index.html
|
||
true
|
||
|
||
nix-repl> builtins.pathExists /no/such/path
|
||
false</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Get a list of the files in a directory, along with the type of each file.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.readDir ./.
|
||
{ ".envrc" = "regular"; ".git" = "directory"; ".gitignore" = "regular"; Makefile = "regular"; images = "directory"; "index.html" = "regular"; "shell.nix" = "regular"; source = "directory"; themes = "directory"; "wombats-book-of-nix.pdf" = "regular"; }</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Read the contents of a file into a string.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.readFile ./.envrc
|
||
"use nix\n"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_list_operations">2.10. List operations</h3>
|
||
<div class="sect3">
|
||
<h4 id="_list_concatenation">2.10.1. List concatenation</h4>
|
||
<div class="paragraph">
|
||
<p>Lists can be concatenated using the <code>++</code> operator.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> [ 1 2 3 ] ++ [ "apple" "banana" ]
|
||
[ 1 2 3 "apple" "banana" ]</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_useful_built_in_functions_for_lists">2.10.2. Useful built-in functions for lists</h4>
|
||
<div class="paragraph">
|
||
<p>Nix provides some built-in functions for working with lists;
|
||
a few examples are shown below.
|
||
For more information on these and other built-in functions, see the Nix Manual
|
||
(<a href="https://nixos.org/manual/nix/stable/language/builtins" class="bare">https://nixos.org/manual/nix/stable/language/builtins</a>).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Testing if an element appears in a list.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> fruit = [ "apple" "banana" "cantaloupe" ]
|
||
|
||
nix-repl> builtins.elem "apple" fruit
|
||
true
|
||
|
||
nix-repl> builtins.elem "broccoli" fruit
|
||
false</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Selecting an item from a list by index.
|
||
The first element in a list has index <code>0</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.elemAt fruit 0
|
||
"apple"
|
||
|
||
nix-repl> builtins.elemAt fruit 2
|
||
"cantaloupe"</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Determining the number of elements in a list.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.length fruit
|
||
3</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Accessing the first element of a list.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.head fruit
|
||
"apple"</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Dropping the first element of a list.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.tail fruit
|
||
[ "banana" "cantaloupe" ]</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Functions are useful for working with lists.
|
||
Functions will be introduced in <a href="#functions">Section 2.12, “Functions”</a>,
|
||
but the following examples should be somewhat self-explanatory.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Using a function to filter (select elements from) a list.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> numbers = [ 1 3 6 8 9 15 25 ]
|
||
|
||
nix-repl> isBig = n: n > 10 # is the number "big" (greater than 10)?
|
||
|
||
nix-repl> builtins.filter isBig numbers # get just the "big" numbers
|
||
[ 15 25 ]</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Applying a function to all the elements in a list.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> double = n: 2*n # multiply by two
|
||
|
||
nix-repl> builtins.map double numbers # double each element in the list
|
||
[ 2 6 12 16 18 30 50 ]</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_attribute_set_operations">2.11. Attribute set operations</h3>
|
||
<div class="sect3">
|
||
<h4 id="_selection">2.11.1. Selection</h4>
|
||
<div class="paragraph">
|
||
<p>The <code>.</code> operator selects an attribute from a set.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> animal = { name = { first = "Professor"; last = "Paws"; }; age = 10; species = "cat"; }
|
||
|
||
nix-repl> animal . age
|
||
10
|
||
|
||
nix-repl> animal . name . first
|
||
"Professor"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_query">2.11.2. Query</h4>
|
||
<div class="paragraph">
|
||
<p>We can use the <code>?</code> operator to find out if a set has a particular attribute.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> animal ? species
|
||
true
|
||
|
||
nix-repl> animal ? bicycle
|
||
false</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_union">2.11.3. Union</h4>
|
||
<div class="paragraph">
|
||
<p>We can use the <code>//</code> operator to combine two attribute sets.
|
||
Attributes in the right-hand set take preference.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> a = { x = 7; y = "hello"; }
|
||
|
||
nix-repl> b = { y = "wombat"; z = 3; }
|
||
|
||
nix-repl> a // b
|
||
{
|
||
x = 7;
|
||
y = "wombat";
|
||
z = 3;
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This is often used to "modify" one or more values in the set.
|
||
Recall that Nix values are immutable, so the result is a new value (the original is not actually modified).</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> animal // { species = "tiger"; }
|
||
{ age = 10; name = { ... }; species = "tiger"; }</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="rec-attrset">2.11.4. Recursive attribute sets</h4>
|
||
<div class="paragraph">
|
||
<p>An ordinary attribute set cannot refer to its own elements.
|
||
To do this, you need a <em>recursive</em> attribute set.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> { x = 3; y = 4*x; }
|
||
error: undefined variable 'x'
|
||
|
||
at «string»:1:16:
|
||
|
||
1| { x = 3; y = 4*x; }
|
||
| ^
|
||
|
||
nix-repl> rec { x = 3; y = 4*x; }
|
||
{ x = 3; y = 12; }</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_useful_built_in_functions_for_attribute_sets">2.11.5. Useful built-in functions for attribute sets</h4>
|
||
<div class="paragraph">
|
||
<p>Nix provides some built-in functions for working with attribute sets;
|
||
a few examples are shown below.
|
||
For more information on these and other built-in functions, see the Nix Manual
|
||
(<a href="https://nixos.org/manual/nix/stable/language/builtins" class="bare">https://nixos.org/manual/nix/stable/language/builtins</a>).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Get an alphabetical list of the keys.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.attrNames animal
|
||
[ "age" "name" "species" ]</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Get the values associated with each key, in alphabetical order by the key names.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.attrValues animal
|
||
[ 10 "Professor Paws" "cat" ]</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>What value is associated with a key?</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.getAttr "age" animal
|
||
10</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Does the set have a value for a key?</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.hasAttr "name" animal
|
||
true
|
||
|
||
nix-repl> builtins.hasAttr "car" animal
|
||
false</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Remove one or more keys and associated values from a set.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.removeAttrs animal [ "age" "species" ]
|
||
{ name = "Professor Paws"; }</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Display an attribute set, including nested sets.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> builtins.toJSON animal
|
||
"{\"age\":10,\"name\":{\"first\":\"Professor\",\"last\":\"Paws\"},\"species\":\"cat\"}"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="functions">2.12. Functions</h3>
|
||
<div class="sect3">
|
||
<h4 id="_anonymous_functions">2.12.1. Anonymous functions</h4>
|
||
<div class="paragraph">
|
||
<p>Functions are defined using the syntax <code><em>parameter</em>: <em>expression</em></code>,
|
||
where the <em>expression</em> typically involves the <em>parameter</em>.
|
||
Consider the following example.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> x: x + 1
|
||
«lambda @ «string»:1:1»</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We created a function that adds <code>1</code> to its input.
|
||
However, it doesn’t have a name, so we can’t use it directly.
|
||
Anonymous functions do have their uses, as we shall see shortly.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note that the message printed by the Nix REPL when we created the function uses the term <em>lambda</em>.
|
||
This derives from a branch of mathematics called <em>lambda calculus</em>.
|
||
Lambda calculus was the inspiration for most functional languages such as Nix.
|
||
Functional programmers often call anonymous functions "lambdas".</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The Nix REPL confirms that the expression <code>x: x + 1</code> defines a function.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> :t x: x + 1
|
||
a function</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_named_functions_and_function_application">2.12.2. Named functions and function application</h4>
|
||
<div class="paragraph">
|
||
<p>How can we use a function?
|
||
Recall from <a href="#type-lambda">Section 2.2.8, “Functions”</a> that functions can be treated like any other data type.
|
||
In particular, we can assign it to a variable.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> f = x: x + 1
|
||
|
||
nix-repl> f
|
||
«lambda @ «string»:1:2»</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Procedural languages such as C or Java often use parenthesis to apply a function to a value, e.g. <code>f(5)</code>.
|
||
Nix, like lambda calculus and most functional languages, does not require parenthesis for function application.
|
||
This reduces visual clutter when chaining a series of functions.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now that our function has a name, we can use it.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> f 5
|
||
6</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_multiple_parameters_using_nested_functions">2.12.3. Multiple parameters using nested functions</h4>
|
||
<div class="paragraph">
|
||
<p>Functions in Nix always have a single parameter.
|
||
To define a calculation that requires more than one parameter,
|
||
we create functions that return functions!</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> add = a: (b: a+b)</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We have created a function called <code>add</code>.
|
||
When applied to a parameter <code>a</code>, it returns a new function that adds <code>a</code> to its input.
|
||
Note that the expression <code>(b: a+b)</code> is an anonymous function.
|
||
We never call it directly, so it doesn’t need a name.
|
||
Anonymous functions are useful after all!</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>I used parentheses to emphasise the inner function, but they aren’t necessary.
|
||
More commonly we would write the following.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> add = a: b: a+b</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If we only supply one parameter to <code>add</code>, the result is a new function rather than a simple value.
|
||
Invoking a function without supplying all of the expected parameters is called <em>partial application</em>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> add 3 # Returns a function that adds 3 to any input
|
||
«lambda @ «string»:1:6»</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now let’s apply <code>add 3</code> to the value <code>5</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> (add 3) 5
|
||
8</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In fact, the parentheses aren’t needed.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> add 3 5
|
||
8</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If you’ve never used a functional programming language, this all probably seems very strange.
|
||
Imagine that you want to add two numbers, but you have a very unusual calculator labeled "add".
|
||
This calculator never displays a result, it only produces more calculators!
|
||
If you enter the value <code>3</code> into the "add" calculator, it gives you a second calculator labeled "add 3".
|
||
You then enter <code>5</code> into the "add 3" calculator, which displays the result of the addition, <code>8</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>With that image in mind, let’s walk through the steps again in the REPL, but this time in more detail.
|
||
The function <code>add</code> takes a single parameter <code>a</code>,
|
||
and returns a new function that takes a single parameter <code>b</code>, and returns the value <code>a + b</code>.
|
||
Let’s apply <code>add</code> to the value <code>3</code>, and give the resulting new function a name, <code>g</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> g = add 3</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The function <code>g</code> takes a single parameter and adds <code>3</code> to it.
|
||
The Nix REPL confirms that <code>g</code> is indeed a function.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> :t g
|
||
a function</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now we can apply <code>g</code> to a number to get a new number.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> g 5
|
||
8</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_multiple_parameters_using_attribute_sets">2.12.4. Multiple parameters using attribute sets</h4>
|
||
<div class="paragraph">
|
||
<p>I said earlier that a function in Nix always has a single parameter.
|
||
However, that parameter need not be a simple value; it could be a list or an attribute set.
|
||
This approach is widely used in Nix, and the language has some special features to support it.
|
||
This is an important topic, so we will cover it separately in <a href="#argument-sets">Section 2.13, “Argument sets”</a>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="argument-sets">2.13. Argument sets</h3>
|
||
<div class="paragraph">
|
||
<p>An attribute set that is used as a function parameter is often called an <em>argument set</em>.</p>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_set_patterns">2.13.1. Set patterns</h4>
|
||
<div class="paragraph">
|
||
<p>To specify an attribute set as a function parameter, we use a <em>set pattern</em>,
|
||
which has the form</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code>{ <em>name1</em>, <em>name2</em>, ... }</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note that while the key-value associations in attribute sets are separated by semi-colons,
|
||
the key names in the attribute set _pattern are separated by commas.
|
||
Here’s an example of a function that has an attribute set as an input parameter.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> greet = { first, last }: "Hello ${first} ${last}! May I call you ${first}?"
|
||
|
||
nix-repl> greet { first="Amy"; last="de Buitléir"; }
|
||
"Hello Amy de Buitléir! May I call you Amy?"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_optional_parameters">2.13.2. Optional parameters</h4>
|
||
<div class="paragraph">
|
||
<p>We can make some values in an argument set optional by providing default values,
|
||
using the syntax <code><em>name</em> ? <em>value</em></code>.
|
||
This is illustrated below.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> greet = { first, last ? "whatever-your-lastname-is", topic ? "Nix" }: "Hello ${first} ${last}! May I call you ${first}? Are you enjoying learning ${topic}?"
|
||
|
||
nix-repl> greet { first="Amy"; }
|
||
"Hello Amy whatever-your-lastname-is! May I call you Amy? Are you enjoying learning Nix?"
|
||
|
||
nix-repl> greet { first="Amy"; topic="Mathematics";}
|
||
"Hello Amy whatever-your-lastname-is! May I call you Amy? Are you enjoying learning Mathematics?"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_variadic_attributes">2.13.3. Variadic attributes</h4>
|
||
<div class="paragraph">
|
||
<p>A function can allow the caller to supply argument sets that contain "extra" values.
|
||
This is done with the special parameter <code>…​</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> formatName = { first, last, ... }: "${first} ${last}"</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>One reason for doing this is to allow the caller to pass the same argument set to multiple functions,
|
||
even though each function may not need all of the values.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> person = { first="Joe"; last="Bloggs"; address="123 Main Street"; }
|
||
|
||
nix-repl> formatName person
|
||
"Joe Bloggs"</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Another reason for allowing variadic arguments is when a function calls another function,
|
||
supplying the same argument set.
|
||
An example is shown in <a href="#at-patterns">Section 2.13.4, “@-patterns”</a>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="at-patterns">2.13.4. @-patterns</h4>
|
||
<div class="paragraph">
|
||
<p>It can be convenient for a function to be able to reference the argument set as a whole.
|
||
This is done using an <em>@-pattern</em>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> formatPoint = p@{ x, y, ... }: builtins.toXML p
|
||
|
||
nix-repl> formatPoint { x=5; y=3; z=2; }
|
||
"<?xml version='1.0' encoding='utf-8'?>\n<expr>\n <attrs>\n <attr name=\"x\">\n <int value=\"5\" />\n </attr>\n <attr name=\"y\">\n <int value=\"3\" />\n </attr>\n <attr name=\"z\">\n <int value=\"2\" />\n </attr>\n </attrs>\n</expr>\n"</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Alternatively, the @-pattern can appear <em>after</em> the argument set, as in the example below.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> formatPoint = { x, y, ... } @ p: builtins.toXML p</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>An @-pattern is the only way a function can access variadic attributes,
|
||
so they are often used together.
|
||
In the example below, the function <code>greet</code> passes its argument set, including the variadic arguments,
|
||
to the function <code>confirmAddress</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> confirmAddress = { address, ... }: "Do you still live at ${address}?"
|
||
|
||
nix-repl> greet = args@{ first, last, ... }: "Hello ${first}. " + confirmAddress args
|
||
|
||
nix-repl> greet person
|
||
"Hello Joe. Do you still live at 123 Main Street?"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="derivations">2.14. Derivations</h3>
|
||
<div class="paragraph">
|
||
<p>Derivations can be created using the primitive built-in <code>derivation</code> function.
|
||
It takes the following arguments.</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>system</code> (e.g. <code>x86_64-linux</code>).</p>
|
||
</li>
|
||
<li>
|
||
<p><code>name</code>, the package name.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>builder</code>, the executable that builds the package.
|
||
Attributes are passed to the builder as environment variables.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>args</code> (optional), command line arguments to be passed to the builder.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>outputs</code> (optional, defaults to <code>out</code>), output names.
|
||
Nix will pass them to the builder as environment variables containing
|
||
the output paths.</p>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">d = derivation { name = "myname"; builder = "mybuilder"; system = "mysystem"; }</pre>
|
||
</div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> d = derivation { name = "myname"; builder = "mybuilder"; system = "mysystem"; }</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In place of using <code>derivation</code>, it is generally more convenient to use
|
||
<code>stdenv.mkDerivation</code>, which will be be introduced in
|
||
<a href="#mkDerivation">Section 3.5, “<code>stdenv.mkDerivation</code>”</a></p>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_instantiation_vs_realisation">2.14.1. Instantiation vs Realisation</h4>
|
||
<div class="paragraph">
|
||
<p>When a derivation is <em>instantiated</em> (<em>evaluated</em>),
|
||
the Nix expression is parsed and interpreted.
|
||
The result is a <code>.drv</code> file containing a derivation set.
|
||
The package is not built in this step.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The package itself is created when the derivation is <em>built</em> (<em>realised</em>).
|
||
Any dependencies are also built at this time.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_instantiate_evaluate_a_derivation">2.14.2. Instantiate (evaluate) a derivation</h4>
|
||
<div class="paragraph">
|
||
<p>Using the derivation "d" created above…​</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> d
|
||
«derivation /nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv»</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>That <code>.drv</code> file is plain text; it contains the derivation in a different format.
|
||
The mysterious sequence of characters in the filename is a hash of the derivation.
|
||
The hash is unique to this derivation.
|
||
We could have multiple derivations for a package, perhaps different versions or with different options enabled,
|
||
but each one would have a unique hash.
|
||
Any changes to the derivation would result in a new hash.
|
||
Using the hash, Nix can tell the different derivations apart,
|
||
and avoid rebuilding a derivation that has already been built.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We can inspect the derivation in the Nix repl.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> d.drvAttrs
|
||
{ builder = "mybuilder"; name = "myname"; system = "mysystem"; }</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We can examine the <code>.drv</code> file.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>$ cat /nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv
|
||
Derive([("out","/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname","","")],[],[],"mysystem","mybuilder",[],[("builder","mybuilder"),("name","myname"),("out","/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname"),("system","mysystem")])%</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Or get a nicely formatted version.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>$ nix show-derivation /nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv
|
||
{
|
||
"/nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv": {
|
||
"outputs": {
|
||
"out": {
|
||
"path": "/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname"
|
||
}
|
||
},
|
||
"inputSrcs": [],
|
||
"inputDrvs": {},
|
||
"system": "mysystem",
|
||
"builder": "mybuilder",
|
||
"args": [],
|
||
"env": {
|
||
"builder": "mybuilder",
|
||
"name": "myname",
|
||
"out": "/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname",
|
||
"system": "mysystem"
|
||
}
|
||
}
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_find_out_where_the_package_would_be_or_was_installed">2.14.3. Find out where the package would be (or was) installed</h4>
|
||
<div class="paragraph">
|
||
<p>Using the derivation "d" created above…​</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> d.outPath
|
||
"/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname"
|
||
|
||
nix-repl> builtins.toString d # also works
|
||
"/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_build_realise_a_derivation">2.14.4. Build (realise) a derivation.</h4>
|
||
<div class="paragraph">
|
||
<p>In the Nix REPL, using the derivation "d" created above…​</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> :b d
|
||
error: a 'mysystem' with features {} is required to build '/nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv', but I am a 'x86_64-linux' with features {benchmark, big-parallel, kvm, nixos-test}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Of course, this example failed to build because the builder and system are fake.
|
||
We can achieve the same result at the command line.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-build /nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv
|
||
this derivation will be built:
|
||
/nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv
|
||
error: a 'mysystem' with features {} is required to build '/nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv', but I am a 'x86_64-linux' with features {benchmark, big-parallel, kvm, nixos-test}</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_remove_a_derivation">2.14.5. Remove a derivation</h4>
|
||
<div class="paragraph">
|
||
<p>Delete a path from the store <strong>if it is safe to do so</strong> (i.e. if it is
|
||
eligible for garbage collection).</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-store --delete /nix/store/rc3n0lc4aijyi9wwpmcss7hbxryz6bnh-foo</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_if_expressions">2.15. If expressions</h3>
|
||
<div class="paragraph">
|
||
<p>The conditional construct in Nix is an <em>expression</em>, not a <em>statement</em>.
|
||
Since expressions must have values in all cases, you must specify both the <code>then</code> and the <code>else</code> branch.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> a = 7
|
||
|
||
nix-repl> b = 3
|
||
|
||
nix-repl> if a > b then "yes" else "no"
|
||
"yes"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_let_expressions">2.16. Let expressions</h3>
|
||
<div class="paragraph">
|
||
<p>A <code>let</code> expression defines a value with a local scope.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> let x = 3; in x*x
|
||
9
|
||
|
||
nix-repl> let x = 3; y = 2; in x*x + y
|
||
11</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>You can also nest <code>let</code> expressions.
|
||
The previous expression is equivalent to the following.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> let x = 3; in let y = 2; in x*x + y
|
||
11</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>A variable defined inside a <code>let</code> expression will "shadow" an outer variable with the same name.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> x = 100
|
||
|
||
nix-repl> let x = 3; in x*x
|
||
9
|
||
|
||
nix-repl> let x = 3; in let x = 7; in x+1
|
||
8</code></pre>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>A variable in a let expression can refer to another variable in the expression.
|
||
This is similar to how recursive attribute sets work.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> let x = 3; y = x + 1; in x*y
|
||
12</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_with_expressions">2.17. With expressions</h3>
|
||
<div class="paragraph">
|
||
<p>A <code>with</code> expression is somewhat similar to a <code>let</code> expression,
|
||
but it brings all of the associations in an attribute set into scope.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> point = { x1 = 3; x2 = 2; }
|
||
|
||
nix-repl> with point; x1*x1 + x2
|
||
11</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>Unlike a <code>let</code> expression, a variable defined inside a <code>with</code> expression will <em>not</em>
|
||
"shadow" an outer variable with the same name.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> name = "Amy"
|
||
|
||
nix-repl> animal = { name = "Professor Paws"; age = 10; species = "cat"; }
|
||
|
||
nix-repl> with animal; "Hello, " + name
|
||
"Hello, Amy"</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>However, you can refer to the variable in the inner scope
|
||
using the attribute selection operator (<code>.</code>).</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> with animal; "Hello, " + animal.name
|
||
"Hello, Professor Paws"</code></pre>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_inherit">2.18. Inherit</h3>
|
||
<div class="paragraph">
|
||
<p>The <code>inherit</code> keyword causes the specified attributes to be bound to
|
||
whatever variables with the same name happen to be in scope.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>When defining a set or in a let-expression it is often convenient to copy variables
|
||
from the surrounding lexical scope (e.g., when you want to propagate attributes).
|
||
This can be shortened using <code>inherit</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For instance,</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-k">let</span> <span class="tok-ss">x</span> <span class="tok-o">=</span> <span class="tok-mi">123</span><span class="tok-p">;</span> <span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-k">inherit</span> x<span class="tok-p">;</span>
|
||
<span class="tok-ss">y</span> <span class="tok-o">=</span> <span class="tok-mi">456</span><span class="tok-p">;</span>
|
||
<span class="tok-p">}</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>is equivalent to</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-k">let</span> <span class="tok-ss">x</span> <span class="tok-o">=</span> <span class="tok-mi">123</span><span class="tok-p">;</span> <span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">x</span> <span class="tok-o">=</span> x<span class="tok-p">;</span>
|
||
<span class="tok-ss">y</span> <span class="tok-o">=</span> <span class="tok-mi">456</span><span class="tok-p">;</span>
|
||
<span class="tok-p">}</span></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_import">2.19. Import</h3>
|
||
<div class="paragraph">
|
||
<p>The built-in <code>import</code> function provides a way to parse a <code>.nix</code> file.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">a.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">message</span> <span class="tok-o">=</span> <span class="tok-s2">"You successfully imported me!"</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">b</span> <span class="tok-o">=</span> <span class="tok-mi">12</span><span class="tok-p">;</span>
|
||
<span class="tok-p">}</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> a = import ./a.nix
|
||
|
||
nix-repl> a.message
|
||
"You successfully imported me!"
|
||
|
||
nix-repl> a.b
|
||
12</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>If path supplied to the <code>import</code> function is a directory,
|
||
the file default.nix in that directory is imported.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The scope of the imported file does not inherit the scope of the importer.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">b.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span>x <span class="tok-o">+</span> <span class="tok-mi">7</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> x = 12
|
||
|
||
nix-repl> y = import ./b.nix
|
||
|
||
nix-repl> y
|
||
error:
|
||
… while calling the 'import' builtin
|
||
at «string»:1:2:
|
||
1| import ./b.nix
|
||
| ^
|
||
|
||
error: undefined variable 'x'
|
||
at /home/amy/codeberg/nix-book/b.nix:1:1:
|
||
1| x + 7
|
||
| ^
|
||
2|</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>So to pass information when importing something, use a function.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">c.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span>x<span class="tok-p">:</span> x <span class="tok-o">+</span> <span class="tok-mi">7</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> f = import ./c.nix
|
||
|
||
nix-repl> f 12
|
||
19</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The imported file may import other files, which may in turn import more files.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_nixpkgs">3. Nixpkgs</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>The Nix Packages collection (nixpkgs) is a large set of Nix expressions containing hundreds of software packages.
|
||
The collection includes functions, definitions and other tools provided by Nix for
|
||
creating, using, and maintaining Nix packages.
|
||
This chapter will explore some of the most useful tools provided by nixpkgs.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In order to use nixpkgs, you must import it.
|
||
As discussed in <a href="#type-path">Section 2.2.5, “Paths”</a>, enclosing a path in angle brackets, e.g. <nixpkgs> causes the directories
|
||
listed in the environment variable NIX_PATH to be searched for the given
|
||
file or directory name.
|
||
In the REPL, the command <code>:l <nixpkgs></code> will import nixpkgs.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> :l <nixpkgs>
|
||
Added 25694 variables.</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Alternatively, you can automatically import nixpkgs when you enter the REPL
|
||
using the command <code>nix repl '<nixpkgs>'</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Within a Nix flake or module, you would use the <code>import</code> command.
|
||
For example,</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-k">with</span> <span class="tok-p">(</span><span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{});</span> <span class="tok-o">...</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>When you import nixpkgs, you are importing a file, which imports other files, which import still more files.
|
||
You can find the location of the nixpkgs directory.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> <nixpkgs>
|
||
/nix/store/5izw1shpjxb9qhlf67bx427cih5czj8w-source</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In that directory is a file called <code>default.nix</code>, which is what is actually imported.
|
||
That file contains an import directive, which triggers more imports, and so on.
|
||
As a result, tens of thousands of variables are added to the scope.
|
||
Don’t worry; this doesn’t cause those hundreds of packages to be installed on your system.
|
||
It merely gives you access to the recipes for those packages,
|
||
plus some tools for working with packages.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This chapter will focus on a few especially useful Nixpkgs library functions.
|
||
You can find a full list in the
|
||
<a href="https://nixos.org/manual/nixpkgs/unstable/#sec-functions-library">Nixpkgs manual</a>.</p>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="genAttrs">3.1. <code>lib.genAttrs</code></h3>
|
||
<div class="paragraph">
|
||
<p>The function
|
||
<a href="https://nixos.org/manual/nixpkgs/stable/#function-library-lib.attrsets.genAttrs"><code>lib.genAttrs</code></a>
|
||
generates an attribute set by mapping a function over a list of attribute names.
|
||
It is an alias for <code>lib.attrsets.genAttrs</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>It takes two arguments:
|
||
- names of values in the resulting attribute set
|
||
- a function which, given the name of the attribute, returns the attribute’s value</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: "some definitions for ${system}")
|
||
{
|
||
aarch64-linux = "some definitions for aarch64-linux";
|
||
x86_64-linux = "some definitions for x86_64-linux";
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>As we shall see later, this is very useful when writing flakes.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="getExe">3.2. <code>lib.getExe</code> and <code>lib.getExe'</code></h3>
|
||
<div class="paragraph">
|
||
<p>The function
|
||
<a href="https://nixos.org/manual/nixpkgs/stable/#function-library-lib.meta.getExe"><code>lib.getExe</code></a>
|
||
returns the path to the main program of a package.
|
||
It is an alias for <code>lib.meta.getExe</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> system = "x86_64-linux"
|
||
|
||
nix-repl> pkgs = import <nixpkgs> { inherit system; }
|
||
|
||
nix-repl> lib.getExe pkgs.hello
|
||
"/nix/store/s9p0adfpzarzfa5kcnqhwargfwiq8qmj-hello-2.12.2/bin/hello"</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The function
|
||
<a href="https://nixos.org/manual/nixpkgs/stable/#function-library-lib.meta.getExe"><code>lib.getExe'</code></a>
|
||
returns the path to the specified program of a package.
|
||
It is an alias for <code>lib.meta.getExe'</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> lib.getExe' pkgs.imagemagick "convert"
|
||
"/nix/store/rn6ck85zkpkgdnm00jmn762z22wz86w6-imagemagick-7.1.2-3/bin/convert"</code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="flakeExposed">3.3. <code>lib.systems.flakeExposed</code></h3>
|
||
<div class="paragraph">
|
||
<p>This attribute is a list of systems that can support flakes.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Example</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><span></span>nix-repl> lib.systems.flakeExposed
|
||
[
|
||
"x86_64-linux"
|
||
"aarch64-linux"
|
||
"x86_64-darwin"
|
||
"armv6l-linux"
|
||
"armv7l-linux"
|
||
"i686-linux"
|
||
"aarch64-darwin"
|
||
"powerpc64le-linux"
|
||
"riscv64-linux"
|
||
"x86_64-freebsd"
|
||
]</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>This attribute is considered experimental and is subject to change.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="mkShell">3.4. <code>pkgs.mkShell</code> and <code>pkgs.mkShellNoCC</code></h3>
|
||
<div class="paragraph">
|
||
<p>The function
|
||
<a href="https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell"><code>pkgs.mkShell</code></a>
|
||
defines a Bash environment.
|
||
It is a wrapper around <code>stdenv.mkDerivation</code>, discussed in <a href="#mkDerivation">Section 3.5, “<code>stdenv.mkDerivation</code>”</a>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The following attributes are accepted,
|
||
along with all attributes of <code>stdenv.mkDerivation</code>.</p>
|
||
</div>
|
||
<table class="tableblock frame-all grid-all fit-content">
|
||
<colgroup>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th class="tableblock halign-left valign-top">attribute</th>
|
||
<th class="tableblock halign-left valign-top">description</th>
|
||
<th class="tableblock halign-left valign-top">default</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>name</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">the name of the derivation</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>nix-shell</code></p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>packages</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">executable packages to add the shell</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>[]</code></p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>inputsFrom</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">build dependencies to add to the shell</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>[]</code></p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>shellHook</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Bash statements to be executed by the shell</p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>""</code></p></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="paragraph">
|
||
<p>If you don’t need a C compiler, you can use <code>mkShellNoCC</code> instead.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="mkDerivation">3.5. <code>stdenv.mkDerivation</code></h3>
|
||
<div class="paragraph">
|
||
<p>The function
|
||
<a href="https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell"><code>pkgs.mkShell</code></a>
|
||
is a wrapper around the primitive <code>derivation</code> function, discussed in <a href="#derivations">Section 2.14, “Derivations”</a>.
|
||
Some of the commonly used attributes are listed below.</p>
|
||
</div>
|
||
<table class="tableblock frame-all grid-all fit-content">
|
||
<colgroup>
|
||
<col>
|
||
<col>
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th class="tableblock halign-left valign-top">attribute</th>
|
||
<th class="tableblock halign-left valign-top">description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>pname</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">package name</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>version</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">version number. Use <a href="https://semver.org/">semantic versioning</a>, i.e., MAJOR.MINOR.PATCH</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>src</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">location of the source files</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>unpackPhase</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Bash command to copy/unpack the source files. If set to <code>"true"</code>, copies/unpacks all files in <code>src</code>, including subdirectories.</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>buildPhase</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Bash commands to build the package. If no action is required, use the no-op <code>":"</code> command.</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>installPhase</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Bash commands to install the package into the Nix store.</p></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="paragraph">
|
||
<p>Older Nix flakes combined the package name and version number into a single <code>name</code> attribute;
|
||
however, this is now discouraged.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>A complete list of phases is available in the
|
||
<a href="https://nixos.org/manual/nixpkgs/stable/#sec-stdenv-phases">Nixpkgs manual</a>.
|
||
Additional arguments are also listed in the
|
||
<a href="https://nixos.org/manual/nixpkgs/stable/#ssec-stdenv-attributes">Nixpkgs manual</a>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_hello_flake">4. Hello, flake!</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>Before learning to write Nix flakes, let’s learn how to use them. I’ve
|
||
created a simple example of a flake in this git repository:
|
||
<a href="https://codeberg.org/mhwombat/hello-flake" class="bare">https://codeberg.org/mhwombat/hello-flake</a>.
|
||
To run this flake, you don’t need to install anything;
|
||
simply run the command below.
|
||
The first time you use a flake, Nix has to fetch and build it, which
|
||
may take time. Subsequent invocations should be instantaneous.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run "git+https://codeberg.org/mhwombat/hello-flake"
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>That’s a lot to type every time we want to use this package. Instead, we
|
||
can enter a shell with the package available to us, using the
|
||
<code>nix shell</code> command.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix shell "git+https://codeberg.org/mhwombat/hello-flake"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In this shell, the command is on our <code>$PATH</code>, so we can execute the
|
||
command by name.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Nix didn’t <em>install</em> the package; it merely built and placed it in a
|
||
directory called the “Nix store”. Thus we can have multiple versions
|
||
of a package without worrying about conflicts. We can find out the
|
||
location of the executable, if we’re curious.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ which hello-flake
|
||
/nix/store/pki997yy2drky7s07q1zcm9qs608y080-hello-flake/bin/hello-flake</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Once we exit that shell, the <code>hello-flake</code> command is no longer
|
||
directly available.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ exit
|
||
$ hello-flake # Fails outside development shell
|
||
bash: line 24: hello-flake: command not found</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>However, we can still run the command using the store path we found
|
||
earlier. That’s not particularly convenient, but it does demonstrate
|
||
that the package remains in the store for future use.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ /nix/store/pki997yy2drky7s07q1zcm9qs608y080-hello-flake/bin/hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_flake_outputs">4.1. Flake outputs</h3>
|
||
<div class="paragraph">
|
||
<p>You can find out what packages and apps a flake provides using the <code>nix flake show</code> command.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix flake show --all-systems git+https://codeberg.org/mhwombat/hello-flake
|
||
git+https://codeberg.org/mhwombat/hello-flake?ref=refs/heads/main&rev=60de6f2ab044e8020d2100e0fcac57c5c1e5f8ae
|
||
├───apps
|
||
│ ├───aarch64-darwin
|
||
│ │ ├───default: app: no description
|
||
│ │ └───hello: app: no description
|
||
│ ├───aarch64-linux
|
||
│ │ ├───default: app: no description
|
||
│ │ └───hello: app: no description
|
||
│ ├───armv6l-linux
|
||
│ │ ├───default: app: no description
|
||
│ │ └───hello: app: no description
|
||
│ ├───armv7l-linux
|
||
│ │ ├───default: app: no description
|
||
│ │ └───hello: app: no description
|
||
│ ├───i686-linux
|
||
│ │ ├───default: app: no description
|
||
│ │ └───hello: app: no description
|
||
│ ├───powerpc64le-linux
|
||
│ │ ├───default: app: no description
|
||
│ │ └───hello: app: no description
|
||
│ ├───riscv64-linux
|
||
│ │ ├───default: app: no description
|
||
│ │ └───hello: app: no description
|
||
│ ├───x86_64-darwin
|
||
│ │ ├───default: app: no description
|
||
│ │ └───hello: app: no description
|
||
│ ├───x86_64-freebsd
|
||
│ │ ├───default: app: no description
|
||
│ │ └───hello: app: no description
|
||
│ └───x86_64-linux
|
||
│ ├───default: app: no description
|
||
│ └───hello: app: no description
|
||
└───packages
|
||
├───aarch64-darwin
|
||
│ ├───default: package 'hello-flake'
|
||
│ └───hello: package 'hello-flake'
|
||
├───aarch64-linux
|
||
│ ├───default: package 'hello-flake'
|
||
│ └───hello: package 'hello-flake'
|
||
├───armv6l-linux
|
||
│ ├───default: package 'hello-flake'
|
||
│ └───hello: package 'hello-flake'
|
||
├───armv7l-linux
|
||
│ ├───default: package 'hello-flake'
|
||
│ └───hello: package 'hello-flake'
|
||
├───i686-linux
|
||
│ ├───default: package 'hello-flake'
|
||
│ └───hello: package 'hello-flake'
|
||
├───powerpc64le-linux
|
||
│ ├───default: package 'hello-flake'
|
||
│ └───hello: package 'hello-flake'
|
||
├───riscv64-linux
|
||
│ ├───default: package 'hello-flake'
|
||
│ └───hello: package 'hello-flake'
|
||
├───x86_64-darwin
|
||
│ ├───default: package 'hello-flake'
|
||
│ └───hello: package 'hello-flake'
|
||
├───x86_64-freebsd
|
||
│ ├───default: package 'hello-flake'
|
||
│ └───hello: package 'hello-flake'
|
||
└───x86_64-linux
|
||
├───default: package 'hello-flake'
|
||
└───hello: package 'hello-flake'</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Examining the output of this command,
|
||
we see that this flake supports multiple architectures
|
||
(aarch64-darwin, aarch64-linux, x86_64-darwin and x86_64-linux)
|
||
and provides both a package and an app called <code>hello</code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_the_hello_flake_repo">5. The hello-flake repo</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>Let’s clone the repository and see how the flake is defined.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ git clone https://codeberg.org/mhwombat/hello-flake
|
||
Cloning into 'hello-flake'...
|
||
$ cd hello-flake
|
||
$ ls
|
||
flake.lock
|
||
flake.nix
|
||
hello-flake
|
||
LICENSE
|
||
README.md</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This is a simple repo with just a few files. Like most git repos, it
|
||
includes <code>LICENSE</code>, which contains the software license, and <code>README.md</code>
|
||
which provides information about the repo.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>hello-flake</code> file is the executable we ran earlier.
|
||
This particular executable is just a shell script, so we can view it.
|
||
It’s an extremely simple script with just two lines.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">hello-flake</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="bash"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-ch">#!/usr/bin/env sh</span>
|
||
|
||
<span class="tok-nb">echo</span><span class="tok-w"> </span><span class="tok-s2">"Hello from your flake!"</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now that we have a copy of the repo, we can execute this script
|
||
directly.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ ./hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Not terribly exciting, I know. But starting with such a simple package
|
||
makes it easier to focus on the flake system without getting bogged down
|
||
in the details. We’ll make this script a little more interesting later.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s look at another file. The file that defines how to package a flake
|
||
is always called <code>flake.nix</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span>
|
||
<span class="normal">28</span>
|
||
<span class="normal">29</span>
|
||
<span class="normal">30</span>
|
||
<span class="normal">31</span>
|
||
<span class="normal">32</span>
|
||
<span class="normal">33</span>
|
||
<span class="normal">34</span>
|
||
<span class="normal">35</span>
|
||
<span class="normal">36</span>
|
||
<span class="normal">37</span>
|
||
<span class="normal">38</span>
|
||
<span class="normal">39</span>
|
||
<span class="normal">40</span>
|
||
<span class="normal">41</span>
|
||
<span class="normal">42</span>
|
||
<span class="normal">43</span>
|
||
<span class="normal">44</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">description</span> <span class="tok-o">=</span> <span class="tok-s2">"a very simple and friendly flake"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-parts<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:hercules-ci/flake-parts"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs</span> <span class="tok-o">=</span> inputs<span class="tok-p">@{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-parts<span class="tok-p">,</span> <span class="tok-o">...</span> <span class="tok-p">}:</span>
|
||
flake-parts<span class="tok-o">.</span>lib<span class="tok-o">.</span>mkFlake <span class="tok-p">{</span> <span class="tok-k">inherit</span> inputs<span class="tok-p">;</span> <span class="tok-p">}</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">systems</span> <span class="tok-o">=</span> nixpkgs<span class="tok-o">.</span>lib<span class="tok-o">.</span>systems<span class="tok-o">.</span>flakeExposed<span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">perSystem</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self'<span class="tok-p">,</span> pkgs<span class="tok-p">,</span> <span class="tok-o">...</span> <span class="tok-p">}:</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">packages</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>stdenv<span class="tok-o">.</span>mkDerivation <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">name</span> <span class="tok-o">=</span> <span class="tok-s2">"hello-flake"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">src</span> <span class="tok-o">=</span> <span class="tok-l">./.</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">unpackPhase</span> <span class="tok-o">=</span> <span class="tok-s2">"true"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">buildPhase</span> <span class="tok-o">=</span> <span class="tok-s2">":"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">installPhase</span> <span class="tok-o">=</span>
|
||
<span class="tok-s tok-s-Multiline">''</span>
|
||
<span class="tok-s tok-s-Multiline"> mkdir -p $out/bin</span>
|
||
<span class="tok-s tok-s-Multiline"> cp $src/hello-flake $out/bin/hello-flake</span>
|
||
<span class="tok-s tok-s-Multiline"> chmod +x $out/bin/hello-flake</span>
|
||
<span class="tok-s tok-s-Multiline"> ''</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span> <span class="tok-c1"># packages</span>
|
||
|
||
<span class="tok-ss">apps</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">type</span> <span class="tok-o">=</span> <span class="tok-s2">"app"</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">program</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>lib<span class="tok-o">.</span>getExe' self'<span class="tok-o">.</span>packages<span class="tok-o">.</span>hello <span class="tok-s2">"hello-flake"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span> <span class="tok-c1"># apps</span>
|
||
<span class="tok-p">};</span> <span class="tok-c1"># perSystem</span>
|
||
<span class="tok-p">};</span> <span class="tok-c1"># mkFlake</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If this is your first time seeing a flake definition, it probably looks
|
||
intimidating.
|
||
Flakes are written in the Nix language, introduced in <a href="#_the_nix_language">Chapter 2, <em>The Nix language</em></a>.
|
||
However, you don’t really need to know Nix to follow this example.
|
||
For now, I’d like to focus on the inputs section.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>There are just two entries, one for <code>nixpkgs</code> and one for <code>flake-utils</code>.
|
||
The first one, <code>nixpkgs</code> refers to the collection of standard software
|
||
packages that can be installed with the Nix package manager. The second,
|
||
<code>flake-utils</code>, is a collection of utilities that simplify writing
|
||
flakes. The important thing to note is that the <code>hello-flake</code> package
|
||
<em>depends</em> on <code>nixpkgs</code> and <code>flake-utils</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Finally, let’s look at <code>flake.lock</code>, or rather, just part of it.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.lock</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span>
|
||
<span class="normal">28</span>
|
||
<span class="normal">29</span>
|
||
<span class="normal">30</span>
|
||
<span class="normal">31</span>
|
||
<span class="normal">32</span>
|
||
<span class="normal">33</span>
|
||
<span class="normal">34</span>
|
||
<span class="normal">35</span>
|
||
<span class="normal">36</span>
|
||
<span class="normal">37</span>
|
||
<span class="normal">38</span>
|
||
<span class="normal">39</span>
|
||
<span class="normal">40</span>
|
||
<span class="normal">41</span></pre></div></td><td class="code"><div><pre><span></span>{
|
||
"nodes": {
|
||
"flake-parts": {
|
||
"inputs": {
|
||
"nixpkgs-lib": "nixpkgs-lib"
|
||
},
|
||
"locked": {
|
||
"lastModified": 1759362264,
|
||
"narHash": "sha256-wfG0S7pltlYyZTM+qqlhJ7GMw2fTF4mLKCIVhLii/4M=",
|
||
"owner": "hercules-ci",
|
||
"repo": "flake-parts",
|
||
"rev": "758cf7296bee11f1706a574c77d072b8a7baa881",
|
||
"type": "github"
|
||
},
|
||
"original": {
|
||
"owner": "hercules-ci",
|
||
"repo": "flake-parts",
|
||
"type": "github"
|
||
}
|
||
},
|
||
"nixpkgs": {
|
||
"locked": {
|
||
"lastModified": 1757873102,
|
||
"narHash": "sha256-kYhNxLlYyJcUouNRazBufVfBInMWMyF+44xG/xar2yE=",
|
||
"owner": "NixOS",
|
||
"repo": "nixpkgs",
|
||
"rev": "88cef159e47c0dc56f151593e044453a39a6e547",
|
||
"type": "github"
|
||
},
|
||
"original": {
|
||
"owner": "NixOS",
|
||
"repo": "nixpkgs",
|
||
"type": "github"
|
||
}
|
||
},
|
||
"nixpkgs-lib": {
|
||
"locked": {
|
||
"lastModified": 1754788789,
|
||
"narHash": "sha256-x2rJ+Ovzq0sCMpgfgGaaqgBSwY+LST+WbZ6TytnT9Rk=",
|
||
"owner": "nix-community",
|
||
. . .
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <code>flake.nix</code> seemed intimidating, then this file looks like an
|
||
invocation for Cthulhu. The good news is that this file is automatically
|
||
generated; you never need to write it. It contains information about all
|
||
of the dependencies for the flake, including where they came from, the
|
||
exact version/revision, and hash. This lockfile <em>uniquely</em> specifies all
|
||
flake dependencies, (e.g., version number, branch, revision, hash), so
|
||
that <em>anyone, anywhere, any time, can re-create the exact same
|
||
environment that the original developer used.</em></p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>No more complaints of "but it works on my machine!". That is the
|
||
benefit of using flakes.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_flake_structure">6. Flake structure</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>The basic structure of a flake is shown below.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix">{
|
||
description = <em>package description</em>
|
||
inputs = <em>dependencies</em>
|
||
outputs = <em>what the flake produces</em>
|
||
nixConfig = <em>advanced configuration options</em>
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>description</code> part is self-explanatory; it’s just a string. You
|
||
probably won’t need <code>nixConfig</code> unless you’re doing something fancy. I’m
|
||
going to focus on what goes into the <code>inputs</code> and <code>outputs</code> sections,
|
||
and highlight some of the things I found confusing when I began using flakes.</p>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="flake-inputs">6.1. Inputs</h3>
|
||
<div class="paragraph">
|
||
<p>This section specifies the dependencies of a flake. It’s an <em>attribute
|
||
set</em>; it maps keys to values.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>To ensure that a build is reproducible, the build step runs in a <em>pure</em>
|
||
environment with no network access. Therefore, any external dependencies
|
||
must be specified in the “inputs” section so they can be fetched in
|
||
advance (before we enter the pure environment).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Each entry in this section maps an input name to a <em>flake reference</em>.
|
||
This commonly takes the following form.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">NAME.url = URL-LIKE-EXPRESSION</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>As a first example of a flake reference, all (almost all?) flakes depend on “nixpkgs”,
|
||
which is a large Git repository of programs and libraries that are
|
||
pre-packaged for Nix. We can write that as</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix">nixpkgs.url = "github:NixOS/nixpkgs/nixos-<em>version</em>";</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>where <em>version</em> is replaced with the version number that you used to build
|
||
the package, e.g. <code>22.11</code>. Information about the latest nixpkgs releases
|
||
is available at <a href="https://status.nixos.org/" class="bare">https://status.nixos.org/</a>. You can also write the entry
|
||
without the version number</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span>nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs/nixos"</span><span class="tok-p">;</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>or more simply,</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span>nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"nixpkgs"</span><span class="tok-p">;</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>You might be concerned that omitting the version number would make the
|
||
build non-reproducible. If someone else builds the flake, could they end
|
||
up with a different version of nixpkgs? No! remember that the lockfile
|
||
(<code>flake.lock</code>) <em>uniquely</em> specifies all flake inputs.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Git and Mercurial repositories are the most common type of flake
|
||
reference, as in the examples below.</p>
|
||
</div>
|
||
<div class="dlist">
|
||
<dl>
|
||
<dt class="hdlist1">A Git repository</dt>
|
||
<dd>
|
||
<p><code>git+https://github.com/NixOS/patchelf</code></p>
|
||
</dd>
|
||
<dt class="hdlist1">A specific branch of a Git repository</dt>
|
||
<dd>
|
||
<p><code>git+https://github.com/NixOS/patchelf?ref=master</code></p>
|
||
</dd>
|
||
<dt class="hdlist1">A specific revision of a Git repository</dt>
|
||
<dd>
|
||
<p><br>
|
||
<code>git+https://github.com/NixOS/patchelf?ref=master&rev=f34751b88bd07d7f44f5cd3200fb4122bf916c7e</code></p>
|
||
</dd>
|
||
<dt class="hdlist1">A tarball</dt>
|
||
<dd>
|
||
<p><code><a href="https://github.com/NixOS/patchelf/archive/master.tar.gz" class="bare">https://github.com/NixOS/patchelf/archive/master.tar.gz</a></code></p>
|
||
</dd>
|
||
</dl>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>You can find more examples of flake references in the
|
||
<a href="https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html#examples">Nix
|
||
Reference Manual</a>.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>Although you probably won’t need to use it, there is another syntax for
|
||
flake references that you might encounter. This example</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span>inputs<span class="tok-o">.</span><span class="tok-nb">import</span><span class="tok-o">-</span><span class="tok-ss">cargo</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">type</span> <span class="tok-o">=</span> <span class="tok-s2">"github"</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">owner</span> <span class="tok-o">=</span> <span class="tok-s2">"edolstra"</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">repo</span> <span class="tok-o">=</span> <span class="tok-s2">"import-cargo"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>is equivalent to</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span>inputs<span class="tok-o">.</span><span class="tok-nb">import</span><span class="tok-o">-</span>cargo<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:edolstra/import-cargo"</span><span class="tok-p">;</span></code></pre>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Each of the <code>inputs</code> is fetched, evaluated and passed to the <code>outputs</code>
|
||
function as a set of attributes with the same name as the corresponding
|
||
input.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="flake-outputs">6.2. Outputs</h3>
|
||
<div class="paragraph">
|
||
<p>This section is a function that essentially returns the recipe for
|
||
building the flake.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We said above that <code>inputs</code> are passed to the <code>outputs</code>, so we need to
|
||
list them as parameters. This example references the <code>import-cargo</code>
|
||
dependency defined in the previous example.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix">outputs = { self, nixpkgs, import-cargo }: {
|
||
<mark><em>definitions for outputs</em></mark>
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>So what actually goes in the highlighted section?
|
||
That depends on the programming languages your software is written in,
|
||
the build system you use, and more. There are Nix functions and tools
|
||
that can simplify much of this, and new, easier-to-use ones are released
|
||
regularly. We’ll look at some of these in the next section.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_a_generic_flake">7. A generic flake</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>The previous section presented a very high-level view of flakes,
|
||
focusing on the basic structure. In this section, we will add a bit more
|
||
detail.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Flakes are written in the Nix programming language, which is a
|
||
functional language. As with most programming languages, there are many
|
||
ways to achieve the same result. Below is an example you can follow when
|
||
writing your own flakes. I’ll explain the example in some detail.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code>{
|
||
description = "<mark><em>brief package description</em></mark>";
|
||
|
||
inputs = {
|
||
<span class="highlight01">nixpkgs</span>.url = "github:NixOS/nixpkgs";
|
||
<span class="highlight03">...<em>other dependencies</em>...</span> ❶
|
||
};
|
||
|
||
outputs = { self, <span class="highlight01">nixpkgs</span>, <span class="highlight03">...<em>other dependencies</em>...</span> ❷ }: {
|
||
|
||
devShells = <mark><em>shell definitions</em></mark>; ❸
|
||
|
||
packages = <mark><em>package definitions</em></mark>; ❹
|
||
|
||
apps = <mark><em>app definitions</em></mark>; ❺
|
||
|
||
};
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We discussed how to specify flake inputs <code>❶</code> in the previous section, so
|
||
this part of the flake should be familiar. Remember also that any
|
||
dependencies in the input section should also be listed at the beginning
|
||
of the outputs section <code>❷</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>devShells</code> attribute <code>❸</code> specifies the environment that should be
|
||
available when doing development on the package.
|
||
This includes any tools
|
||
(e.g., compilers and other language-specific build tools and packages).
|
||
If you don’t need a special development environment, you can omit this section.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>packages</code> attribute <code>❹</code> defines the packages that this flake provides.
|
||
The definition depends on the programming languages your
|
||
software is written in, the build system you use, and more.
|
||
There are Nix functions and tools that can simplify much of this, and new,
|
||
easier-to-use ones are released regularly.
|
||
These functions are very language-specific, and not always well-documented.
|
||
We will see examples for some languages later in the tutorial.
|
||
In general, I recommend that you do a web search for
|
||
"nix <em>language-name</em>", and try to find resources that were written or updated
|
||
recently.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>apps</code> attribute <code>❺</code> identifies any applications provided by the flake.
|
||
In particular, it identifies the default executable that <code>nix run</code>
|
||
will run if you don’t specify an app.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If we want the development shell, packages, and apps
|
||
to be available for multiple systems
|
||
(e.g., <code>x86_64-linux</code>, <code>aarch64-linux</code>, <code>x86_64-darwin</code>, and
|
||
<code>aarch64-darwin</code>),
|
||
we need to provide a definition for each of those systems.
|
||
The result <em>could</em> be an outputs section like the one shown below.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code> outputs = { self, <span class="highlight01">nixpkgs</span>, <span class="highlight03">...<em>other dependencies</em>...</span> ❷ }: {
|
||
|
||
devShells.x86_64-linux.default = ...;
|
||
devShells.aarch64-linux.default = ...;
|
||
. . .
|
||
|
||
packages.x86_64-linux.my-app = ...;
|
||
packages.aarch64-linux.my-app = ...;
|
||
. . .
|
||
|
||
apps.x86_64-linux.my-app = ...;
|
||
apps.aarch64-linux.my-app = ...;
|
||
. . .
|
||
|
||
apps.x86_64-linux.default = ...;
|
||
apps.aarch64-linux.default = ...;
|
||
. . .
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>You won’t see definitions like that in most flakes.
|
||
Typically the definitions for each shell, package or app
|
||
would be identical, apart from a reference to the system name.
|
||
There are techniques and tools that allow you to write a single definition
|
||
and use it to automatically generate the definitions for multiple architectures.
|
||
We will see some examples of this later in the tutorial.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Below is a list of some functions that are commonly used in
|
||
the output section.</p>
|
||
</div>
|
||
<div class="dlist">
|
||
<dl>
|
||
<dt class="hdlist1">General-purpose</dt>
|
||
<dd>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://noogle.dev/f/pkgs/stdenv/mkDerivation"><code>mkDerivation</code></a>
|
||
is especially useful for the typical
|
||
<code>./configure; make; make install</code> scenario.
|
||
It’s customisable.</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://nixos.org/manual/nixpkgs/unstable/#sec-pkgs-mkShell"><code>mkShell</code></a>
|
||
simplifies writing a development shell definition.</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeShellApplication"><code>writeShellApplication</code></a>
|
||
creates an executable shell script which also defines the appropriate environment.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</dd>
|
||
<dt class="hdlist1">Python</dt>
|
||
<dd>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>buildPythonApplication</code></p>
|
||
</li>
|
||
<li>
|
||
<p><code>buildPythonPackage</code>.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</dd>
|
||
<dt class="hdlist1">Haskell</dt>
|
||
<dd>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>mkDerivation</code> (Haskell version, which is a wrapper around the
|
||
standard environment version)</p>
|
||
</li>
|
||
<li>
|
||
<p><code>developPackage</code></p>
|
||
</li>
|
||
<li>
|
||
<p><code>callCabal2Nix</code>.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</dd>
|
||
</dl>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p><a href="https://noogle.dev/">Noogλe</a> allows you to search for
|
||
documentation for Nix functions and other definitions.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_another_look_at_hello_flake">8. Another look at hello-flake</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>Now that we have a better understanding of the structure of <code>flake.nix</code>,
|
||
let’s have a look at the one we saw earlier, in the <code>hello-flake</code> repo.
|
||
If you compare this flake definition to the colour-coded template
|
||
presented in <a href="#_a_generic_flake">Chapter 7, <em>A generic flake</em></a>, most of it should look familiar.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">description</span> <span class="tok-o">=</span> <span class="tok-s2">"a very simple and friendly flake"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils <span class="tok-p">}:</span>
|
||
flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs</span> <span class="tok-o">=</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span> <span class="tok-k">inherit</span> system<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">packages</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello</span> <span class="tok-o">=</span>
|
||
<span class="tok-o">.</span> <span class="tok-o">.</span> <span class="tok-o">.</span>
|
||
_SOME UNFAMILIAR STUFF_
|
||
<span class="tok-o">.</span> <span class="tok-o">.</span> <span class="tok-o">.</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">apps</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello</span> <span class="tok-o">=</span> flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>mkApp <span class="tok-p">{</span> <span class="tok-ss">drv</span> <span class="tok-o">=</span> self<span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-si">${</span>system<span class="tok-si">}</span><span class="tok-o">.</span>hello<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This <code>flake.nix</code> doesn’t have a <code>devShells</code> section, because development
|
||
on the current version doesn’t require anything beyond
|
||
the “bare bones” linux commands. Later we will add a feature that requires
|
||
additional development tools.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now let’s look at the section I labeled <code>SOME UNFAMILIAR STUFF</code> and
|
||
see what it does.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"> packages = rec {
|
||
hello = pkgs.stdenv.mkDerivation rec { ❶
|
||
name = "hello-flake";
|
||
|
||
src = ./.; ❷
|
||
|
||
unpackPhase = "true";
|
||
|
||
buildPhase = ":";
|
||
|
||
installPhase =
|
||
''
|
||
mkdir -p $out/bin ❸
|
||
cp $src/hello-flake $out/bin/hello-flake ❹
|
||
chmod +x $out/bin/hello-flake ❺
|
||
'';
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This flake uses <a href="https://noogle.dev/f/pkgs/stdenv/mkDerivation"><code>mkDerivation</code></a> <code>❶</code>
|
||
which is a very useful general-purpose package builder provided by the Nix standard
|
||
environment. It’s especially useful for the typical
|
||
<code>./configure; make; make install</code> scenario, but for this flake we don’t
|
||
even need that.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>name</code> variable is the name of the flake, as it would appear in a
|
||
package listing if we were to add it to Nixpkgs or another package
|
||
collection. The <code>src</code> variable <code>❷</code> supplies the location of the source
|
||
files, relative to <code>flake.nix</code>. When a flake is accessed for the first
|
||
time, the repository contents are fetched in the form of a tarball. The
|
||
<code>unpackPhase</code> variable indicates that we do want the tarball to be
|
||
unpacked.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>buildPhase</code> variable is a sequence of Linux commands to build the
|
||
package. Typically, building a package requires compiling the source
|
||
code. However, that’s not required for a simple shell script. So
|
||
<code>buildPhase</code> consists of a single command, <code>:</code>,
|
||
which is a no-op or “do nothing” command.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>installPhase</code> variable is a sequence of Linux commands that will do
|
||
the actual installation. In this case, we create a directory <code>❸</code> for the
|
||
installation, copy the <code>hello-flake</code> script there <code>❹</code>, and make the
|
||
script executable <code>❺</code>. The environment variable <code>$src</code> refers to the
|
||
source directory, which we specified earlier <code>❷</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Earlier we said that the build step runs in a pure environment to ensure
|
||
that builds are reproducible. This means no Internet access; indeed no
|
||
access to any files outside the build directory. During the build and
|
||
install phases, the only commands available are those provided by the
|
||
Nix standard environment and the external dependencies identified in the
|
||
<code>inputs</code> section of the flake.</p>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="standard-environment">8.1. The Nix standard environment</h3>
|
||
<div class="paragraph">
|
||
<p>I’ve mentioned the Nix standard environment before, but I didn’t explain
|
||
what it is. The standard environment, or <code>stdenv</code>, refers to the
|
||
functionality that is available during the build and install phases of a
|
||
Nix package (or flake). It includes the commands listed
|
||
below.</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>The GNU C Compiler, configured with C and C++ support.</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU coreutils (contains a few dozen standard Unix commands).</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU findutils (contains find).</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU diffutils (contains diff, cmp).</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU sed.</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU grep.</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU awk.</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU tar.</p>
|
||
</li>
|
||
<li>
|
||
<p>gzip, bzip2 and xz.</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU Make.</p>
|
||
</li>
|
||
<li>
|
||
<p>Bash.</p>
|
||
</li>
|
||
<li>
|
||
<p>The patch command.</p>
|
||
</li>
|
||
<li>
|
||
<p>On Linux, stdenv also includes the patchelf utility.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Only a few environment variables are available. The most interesting
|
||
ones are listed below.</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>$name</code> is the package name.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>$src</code> refers to the source directory.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>$out</code> is the path to the location in the Nix store where the package
|
||
will be added.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>$system</code> is the system that the package is being built for.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>$PWD</code> and <code>$TMP</code> both point to temporary build directories</p>
|
||
</li>
|
||
<li>
|
||
<p><code>$HOME</code> and <code>$PATH</code> point to nonexistent directories, so the build
|
||
cannot rely on them.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>For more information on the standard environment, see the
|
||
<a href="https://nixos.org/manual/nixpkgs/stable/#sec-tools-of-stdenv">Nixpkgs
|
||
manual</a>.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_a_new_flake_from_scratch">9. A new flake from scratch</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>At last we are ready to create a flake from scratch!
|
||
No matter what programming languages you normally use,
|
||
I recommend that you start by reading the <a href="#_bash">[_bash]</a> section.
|
||
In it, I start with an extremely simple flake, and show how to improve and extend it.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The remaining sections in this chapter are very similar;
|
||
read the one for your language of choice.
|
||
If you’re interested in a language that I haven’t covered, feel free to suggest it by creating an
|
||
<a href="https://codeberg.org/mhwombat/nix-book/issues">issue</a>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>sh: line 1: run-code-inline: command not found</p>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_haskell">9.1. Haskell</h3>
|
||
<div class="paragraph">
|
||
<p>Start with an empty directory and create a git repository.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ mkdir hello-haskell
|
||
$ cd hello-haskell
|
||
$ git init
|
||
Initialized empty Git repository in /home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell/.git/</pre>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_a_simple_haskell_program">9.1.1. A simple Haskell program</h4>
|
||
<div class="paragraph">
|
||
<p>Next, we’ll create a simple Haskell program.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Main.hs</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="haskell"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span>
|
||
<span class="normal">5</span>
|
||
<span class="normal">6</span>
|
||
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-kr">import</span><span class="tok-w"> </span><span class="tok-nn">Network.HostName</span>
|
||
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">::</span><span class="tok-w"> </span><span class="tok-kt">IO</span><span class="tok-w"> </span><span class="tok-nb">()</span>
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-kr">do</span>
|
||
<span class="tok-w"> </span><span class="tok-n">putStrLn</span><span class="tok-w"> </span><span class="tok-s">"Hello from Haskell inside a Nix flake!"</span>
|
||
<span class="tok-w"> </span><span class="tok-n">h</span><span class="tok-w"> </span><span class="tok-ow"><-</span><span class="tok-w"> </span><span class="tok-n">getHostName</span>
|
||
<span class="tok-w"> </span><span class="tok-n">putStrLn</span><span class="tok-w"> </span><span class="tok-o">$</span><span class="tok-w"> </span><span class="tok-s">"Your hostname is: "</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-n">h</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_running_the_program_manually_optional">9.1.2. Running the program manually (optional)</h4>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>In this section you will learn how to do some development tasks manually, the "hard" way.
|
||
This can help you understand the distinction between Nix’s role and
|
||
the Haskell build system you’ve chosen.
|
||
Also, if you have a build problem but you’re not sure if the fault is in
|
||
your flake definition or some other configuration file,
|
||
these commands can help you narrow it down.
|
||
But you may wish to skip to the <a href="#_the_cabal_file">next section</a>
|
||
and come back here later.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Before we package the program, let’s verify that it runs. We’re going to
|
||
need Haskell. By now you’ve probably figured out that we can write a
|
||
<code>flake.nix</code> and define a development shell that includes Haskell. We’ll
|
||
do that shortly, but first I want to show you a handy shortcut. We can
|
||
launch a <em>temporary</em> shell with any Nix packages we want. This is
|
||
convenient when you just want to try out some new software and you’re
|
||
not sure if you’ll use it again. It’s also convenient when you’re not
|
||
ready to write <code>flake.nix</code> (perhaps you’re not sure what tools and
|
||
packages you need), and you want to experiment a bit first.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The command to enter a temporary shell is</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>nix shell -p <em>installables</em></code></p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Where <em>installables</em> are flakes and other types of packages that you need.
|
||
(You can learn more about these in the
|
||
<a href="https://nix.dev/manual/nix/stable/command-ref/new-cli/nix#installables">Nix manual</a>.)</p>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="_some_unsuitable_shells">Some unsuitable shells</h5>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>In this section, we will try commands that fail in subtle ways.
|
||
Examining these failures will give you a much better understanding of Haskell development with Nix,
|
||
and help you avoid (or at least diagnose) similar problems in future.
|
||
If you’re impatient, you can skip to the next section to see the right way to do it.
|
||
You can come back to this section later to learn more.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s enter a shell with the Glasgow Haskell Compiler ("ghc") and try to run the program.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix shell nixpkgs#ghc
|
||
$ runghc Main.hs # Fails
|
||
|
||
Main.hs:1:1: error: [GHC-87110]
|
||
Could not find module ‘Network.HostName’.
|
||
Use :set -v to see a list of the files searched for.
|
||
|
|
||
1 | import Network.HostName
|
||
| ^^^^^^^^^^^^^^^^^^^^^^^</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The error message tells us that we need the module <code>Network.HostName</code>.
|
||
That module is provided by the Haskell package called <code>hostname</code>.
|
||
Let’s exit that shell and try again, this time adding the <code>hostname</code> package.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ exit
|
||
$ nix shell nixpkgs#ghc nixpkgs#hostname
|
||
$ runghc Main.hs # Fails
|
||
|
||
Main.hs:1:1: error: [GHC-87110]
|
||
Could not find module ‘Network.HostName’.
|
||
Use :set -v to see a list of the files searched for.
|
||
|
|
||
1 | import Network.HostName
|
||
| ^^^^^^^^^^^^^^^^^^^^^^^</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>That reason that failed is that we asked for the wrong package.
|
||
The Nix package <code>hostname</code> isn’t the Haskell package we wanted,
|
||
it’s a different package entirely (an alias for <code>hostname-net-tools</code>.)
|
||
The package we want is in the <em>package set</em> called <code>haskellPackages</code>, so we can refer to it as <code>haskellPackages.hostname</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s try that again, with the correct package.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ exit
|
||
$ nix shell nixpkgs#ghc nixpkgs#haskellPackages.hostname
|
||
$ runghc Main.hs # Fails
|
||
|
||
Main.hs:1:1: error: [GHC-87110]
|
||
Could not find module ‘Network.HostName’.
|
||
Use :set -v to see a list of the files searched for.
|
||
|
|
||
1 | import Network.HostName
|
||
| ^^^^^^^^^^^^^^^^^^^^^^^</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now what’s wrong?
|
||
The syntax we used in the <code>nix shell</code> command above is fine,
|
||
but it doesn’t make the package <em>available to GHC</em>!</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="_a_suitable_shell_for_a_quick_test">A suitable shell for a quick test</h5>
|
||
<div class="paragraph">
|
||
<p>Now we will create a shell that can run the program.
|
||
When you need support for both a language and some of
|
||
its packages, it’s best to use one of the Nix functions that are
|
||
specific to the programming language and build system.
|
||
For Haskell, we can use the <code>ghcWithPackages</code> function.
|
||
The command below is rather complex,
|
||
and a complete explanation would be rather lengthy.</p>
|
||
</div>
|
||
<div id="haskell-nix-shell" class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix shell --impure --expr 'with import <nixpkgs> {}; haskellPackages.ghcWithPackages (p: [ p.hostname ])'
|
||
$ runghc Main.hs
|
||
Hello from Haskell inside a Nix flake!
|
||
Your hostname is: wombat11k</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Success! Now we know the program works.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_the_cabal_file">9.1.3. The cabal file</h4>
|
||
<div class="paragraph">
|
||
<p>It’s time to write a Cabal file for this program.
|
||
This is just an ordinary Cabal file; we don’t need to do anything special for Nix.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">hello-flake-haskell.cabal</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="cabal"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span></pre></div></td><td class="code"><div><pre><span></span>cabal-version: 3.0
|
||
name: hello-flake-haskell
|
||
version: 1.0.0
|
||
synopsis: A simple demonstration using a Nix flake to package a Haskell program.
|
||
description:
|
||
For more information and a tutorial on how to use this package,
|
||
please see the README at <https://codeberg.org/mhwombat/hello-flake-haskell#readme>.
|
||
homepage: https://codeberg.org/mhwombat/nix-book
|
||
bug-reports: https://codeberg.org/mhwombat/nix-book/issues
|
||
license: GPL-3.0-only
|
||
license-file: LICENSE
|
||
author: Amy de Buitléir
|
||
maintainer: amy@nualeargais.ie
|
||
copyright: (c) 2023 Amy de Buitléir
|
||
category: Text
|
||
build-type: Simple
|
||
|
||
executable hello-flake-haskell
|
||
main-is: Main.hs
|
||
build-depends:
|
||
base,
|
||
hostname
|
||
-- NOTE: Best practice is to specify version constraints for the packages we depend on.
|
||
-- However, I'm confident that this package will only be used as a Nix flake.
|
||
-- Nix will automatically ensure that anyone running this program is using the
|
||
-- same library versions that I used to build it.
|
||
default-language: Haskell2010
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_building_the_program_manually_optional">9.1.4. Building the program manually (optional)</h4>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>In this section you will learn how to do some development tasks manually, the "hard" way.
|
||
This can help you understand the distinction between Nix’s role and
|
||
the Haskell build system you’ve chosen.
|
||
Also, if you have a build problem but you’re not sure if the fault is in
|
||
your flake definition or some other configuration file,
|
||
these commands can help you narrow it down.
|
||
But you may wish to skip to the <a href="#haskell-flake">next section</a>
|
||
and come back here later.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We won’t write <code>flake.nix</code> just yet.
|
||
First we’ll try building the package manually.
|
||
(If you didn’t run the <code>nix shell</code> command from <a href="#haskell-nix-shell">earlier</a>, do so now.)</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ cabal build
|
||
sh: line 42: cabal: command not found</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>cabal</code> command is provided by the <code>cabal-install</code> package.
|
||
The error happens because we don’t have <code>cabal-install</code> available
|
||
in the temporary shell.
|
||
We can correct that.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix shell --impure --expr 'with import <nixpkgs> {}; haskellPackages.ghcWithPackages (p: [ p.hostname p.cabal-install ])'</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note that we’re now inside a temporary shell inside the previous
|
||
temporary shell! To get back to the original shell, we have to <code>exit</code>
|
||
twice.
|
||
Alternatively, we could have done <code>exit</code> followed by the
|
||
second <code>nix-shell</code> command.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ cabal build
|
||
. . .
|
||
Preprocessing executable 'hello-flake-haskell' for hello-flake-haskell-1.0.0...
|
||
Building executable 'hello-flake-haskell' for hello-flake-haskell-1.0.0...
|
||
[1 of 1] Compiling Main ( Main.hs, dist-newstyle/build/x86_64-linux/ghc-9.8.4/hello-flake-haskell-1.0.0/x/hello-flake-haskell/build/hello-flake-haskell/hello-flake-haskell-tmp/Main.o )
|
||
[2 of 2] Linking dist-newstyle/build/x86_64-linux/ghc-9.8.4/hello-flake-haskell-1.0.0/x/hello-flake-haskell/build/hello-flake-haskell/hello-flake-haskell</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>After a lot of output messages, the build succeeds.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="haskell-flake">9.1.5. The Nix flake</h4>
|
||
<div class="paragraph">
|
||
<p>Now we should write <code>flake.nix</code>.
|
||
We already know how to write most of the flake from the examples we did earlier.
|
||
The two parts that will be different are the development shell and the package builder.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>However, there’s a <em>much</em> simpler way, using <code>haskell-flake</code>.
|
||
The following command will create <code>flake.nix</code> based on their template.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix flake init -t github:srid/haskell-flake
|
||
wrote: "/home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell/flake.nix"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Examining the flake,
|
||
you’ll notice that it is well-commented.
|
||
The only thing we need to change for now is the name in <code>packages.default</code>;
|
||
I’ve highlighted the change below.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span>
|
||
<span class="normal">28</span>
|
||
<span class="normal">29</span>
|
||
<span class="normal">30</span>
|
||
<span class="normal">31</span>
|
||
<span class="normal">32</span>
|
||
<span class="normal">33</span>
|
||
<span class="normal">34</span>
|
||
<span class="normal">35</span>
|
||
<span class="normal">36</span>
|
||
<span class="normal">37</span>
|
||
<span class="normal">38</span>
|
||
<span class="normal">39</span>
|
||
<span class="normal">40</span>
|
||
<span class="normal">41</span>
|
||
<span class="normal">42</span>
|
||
<span class="normal">43</span>
|
||
<span class="normal">44</span>
|
||
<span class="normal">45</span>
|
||
<span class="normal">46</span>
|
||
<span class="normal">47</span>
|
||
<span class="normal">48</span>
|
||
<span class="normal">49</span>
|
||
<span class="normal">50</span>
|
||
<span class="normal">51</span>
|
||
<span class="normal">52</span>
|
||
<span class="normal">53</span>
|
||
<span class="normal">54</span>
|
||
<span class="normal">55</span>
|
||
<span class="normal">56</span>
|
||
<span class="normal">57</span>
|
||
<span class="normal">58</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:nixos/nixpkgs/nixpkgs-unstable"</span><span class="tok-p">;</span>
|
||
flake-parts<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:hercules-ci/flake-parts"</span><span class="tok-p">;</span>
|
||
haskell-flake<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:srid/haskell-flake"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-ss">outputs</span> <span class="tok-o">=</span> inputs<span class="tok-p">@{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-parts<span class="tok-p">,</span> <span class="tok-o">...</span> <span class="tok-p">}:</span>
|
||
flake-parts<span class="tok-o">.</span>lib<span class="tok-o">.</span>mkFlake <span class="tok-p">{</span> <span class="tok-k">inherit</span> inputs<span class="tok-p">;</span> <span class="tok-p">}</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">systems</span> <span class="tok-o">=</span> nixpkgs<span class="tok-o">.</span>lib<span class="tok-o">.</span>systems<span class="tok-o">.</span>flakeExposed<span class="tok-p">;</span>
|
||
<span class="tok-ss">imports</span> <span class="tok-o">=</span> <span class="tok-p">[</span> inputs<span class="tok-o">.</span>haskell-flake<span class="tok-o">.</span>flakeModule <span class="tok-p">];</span>
|
||
|
||
<span class="tok-ss">perSystem</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self'<span class="tok-p">,</span> pkgs<span class="tok-p">,</span> <span class="tok-o">...</span> <span class="tok-p">}:</span> <span class="tok-p">{</span>
|
||
|
||
<span class="tok-c1"># Typically, you just want a single project named "default". But</span>
|
||
<span class="tok-c1"># multiple projects are also possible, each using different GHC version.</span>
|
||
haskellProjects<span class="tok-o">.</span><span class="tok-ss">default</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
<span class="tok-c1"># The base package set representing a specific GHC version.</span>
|
||
<span class="tok-c1"># By default, this is pkgs.haskellPackages.</span>
|
||
<span class="tok-c1"># You may also create your own. See https://community.flake.parts/haskell-flake/package-set</span>
|
||
<span class="tok-c1"># basePackages = pkgs.haskellPackages;</span>
|
||
|
||
<span class="tok-c1"># Extra package information. See https://community.flake.parts/haskell-flake/dependency</span>
|
||
<span class="tok-c1">#</span>
|
||
<span class="tok-c1"># Note that local packages are automatically included in `packages`</span>
|
||
<span class="tok-c1"># (defined by `defaults.packages` option).</span>
|
||
<span class="tok-c1">#</span>
|
||
<span class="tok-ss">packages</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
<span class="tok-c1"># aeson.source = "1.5.0.0"; # Override aeson to a custom version from Hackage</span>
|
||
<span class="tok-c1"># shower.source = inputs.shower; # Override shower to a custom source path</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-ss">settings</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
<span class="tok-c1"># aeson = {</span>
|
||
<span class="tok-c1"># check = false;</span>
|
||
<span class="tok-c1"># };</span>
|
||
<span class="tok-c1"># relude = {</span>
|
||
<span class="tok-c1"># haddock = false;</span>
|
||
<span class="tok-c1"># broken = false;</span>
|
||
<span class="tok-c1"># };</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">devShell</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
<span class="tok-c1"># Enabled by default</span>
|
||
<span class="tok-c1"># enable = true;</span>
|
||
|
||
<span class="tok-c1"># Programs you want to make available in the shell.</span>
|
||
<span class="tok-c1"># Default programs can be disabled by setting to 'null'</span>
|
||
<span class="tok-c1"># tools = hp: { fourmolu = hp.fourmolu; ghcid = null; };</span>
|
||
|
||
<span class="tok-c1"># Check that haskell-language-server works</span>
|
||
<span class="tok-c1"># hlsCheck.enable = true; # Requires sandbox to be disabled</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-c1"># haskell-flake doesn't set the default package, but you can do it here.</span>
|
||
<span class="hll"> packages<span class="tok-o">.</span><span class="tok-ss">default</span> <span class="tok-o">=</span> self'<span class="tok-o">.</span>packages<span class="tok-o">.</span>hello-flake-haskell<span class="tok-p">;</span>
|
||
</span> <span class="tok-p">};</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We also need a <code>LICENSE</code> file.
|
||
For now, this can be empty.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ touch LICENSE</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_building_the_program">9.1.6. Building the program</h4>
|
||
<div class="paragraph">
|
||
<p>Let’s try out the new flake.
|
||
Nix flakes only “see” files that are
|
||
part of the repository. We need to add all of the important files to the
|
||
repo before building or running the flake.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ git add flake.nix hello-flake-haskell.cabal LICENSE Main.hs
|
||
$ nix build
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell' is dirty
|
||
warning: creating lock file '"/home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell/flake.lock"':
|
||
• Added input 'flake-parts':
|
||
'github:hercules-ci/flake-parts/758cf7296bee11f1706a574c77d072b8a7baa881?narHash=sha256-wfG0S7pltlYyZTM%2BqqlhJ7GMw2fTF4mLKCIVhLii/4M%3D' (2025-10-01)
|
||
• Added input 'flake-parts/nixpkgs-lib':
|
||
'github:nix-community/nixpkgs.lib/a73b9c743612e4244d865a2fdee11865283c04e6?narHash=sha256-x2rJ%2BOvzq0sCMpgfgGaaqgBSwY%2BLST%2BWbZ6TytnT9Rk%3D' (2025-08-10)
|
||
• Added input 'haskell-flake':
|
||
'github:srid/haskell-flake/3ab2a076aba01d932644f6f21e8aa507d28bb36b?narHash=sha256-k6ctrfZ%2B5jO1vnqmQpkog0yXcXDGDbHxF6o5MWa2vKk%3D' (2025-10-12)
|
||
• Added input 'nixpkgs':
|
||
'github:nixos/nixpkgs/362791944032cb532aabbeed7887a441496d5e6e?narHash=sha256-gKl2Gtro/LNf8P%2B4L3S2RsZ0G390ccd5MyXYrTdMCFE%3D' (2025-10-11)
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell' is dirty</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We’ll deal with those warnings later.
|
||
The important thing for now is that the build succeeded.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_running_the_program">9.1.7. Running the program</h4>
|
||
<div class="paragraph">
|
||
<p>Now we can run the program.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell' is dirty
|
||
Hello from Haskell inside a Nix flake!
|
||
Your hostname is: wombat11k</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>By the way, we didn’t need to do <code>nix build</code> earlier.
|
||
The <code>nix run</code> command will first build the program for us if needed.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We’d like to share this package with others, but first we should do some
|
||
cleanup.
|
||
It’s time to deal with those warnings.
|
||
When the package was built, Nix created a <code>flake.lock</code> file.
|
||
We need to add this to the repo, and commit all important files.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ git add flake.lock
|
||
$ git commit -a -m 'initial commit'
|
||
[master (root-commit) e59ea35] initial commit
|
||
5 files changed, 170 insertions(+)
|
||
create mode 100644 LICENSE
|
||
create mode 100644 Main.hs
|
||
create mode 100644 flake.lock
|
||
create mode 100644 flake.nix
|
||
create mode 100644 hello-flake-haskell.cabal</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>You can test that your package is properly configured by going to
|
||
another directory and running it from there.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ cd ..
|
||
$ nix run ./hello-haskell
|
||
Hello from Haskell inside a Nix flake!
|
||
Your hostname is: wombat11k</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If you move the project to a public repo, anyone can run it. Recall from
|
||
the beginning of the tutorial that you were able to run <code>hello-flake</code>
|
||
directly from my repo with the following command.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">nix run "git+https://codeberg.org/mhwombat/hello-flake"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Modify the URL accordingly and invite someone else to run your new
|
||
Haskell flake.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_python">9.2. Python</h3>
|
||
<div class="paragraph">
|
||
<p>Start with an empty directory and create a git repository.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ mkdir hello-python
|
||
$ cd hello-python
|
||
$ git init
|
||
Initialized empty Git repository in /home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python/.git/</pre>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_a_simple_python_program">9.2.1. A simple Python program</h4>
|
||
<div class="paragraph">
|
||
<p>Next, we’ll create a simple Python program.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">hello.py</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="python"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span>
|
||
<span class="normal">5</span>
|
||
<span class="normal">6</span>
|
||
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-ch">#!/usr/bin/env python</span>
|
||
|
||
<span class="tok-k">def</span> <span class="tok-nf">main</span><span class="tok-p">():</span>
|
||
<span class="tok-nb">print</span><span class="tok-p">(</span><span class="tok-s2">"Hello from inside a Python program built with a Nix flake!"</span><span class="tok-p">)</span>
|
||
|
||
<span class="tok-k">if</span> <span class="tok-vm">__name__</span> <span class="tok-o">==</span> <span class="tok-s2">"__main__"</span><span class="tok-p">:</span>
|
||
<span class="tok-n">main</span><span class="tok-p">()</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_running_the_program_manually_optional_2">9.2.2. Running the program manually (optional)</h4>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>In this section you will learn how to do some development tasks manually, the "hard" way.
|
||
This can help you understand the distinction between Nix’s role and
|
||
the Python build system you’ve chosen.
|
||
Also, if you have a build problem but you’re not sure if the fault is in
|
||
your flake definition or some other configuration file,
|
||
these commands can help you narrow it down.
|
||
But you may wish to skip to the <a href="#_configuring_setuptools">next section</a>
|
||
and come back here later.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Before we package the program, let’s verify that it runs. We’re going to
|
||
need Python. By now you’ve probably figured out that we can write a
|
||
<code>flake.nix</code> and define a development shell that includes Python. We’ll
|
||
do that shortly, but first I want to show you a handy shortcut. We can
|
||
launch a <em>temporary</em> shell with any Nix packages we want. This is
|
||
convenient when you just want to try out some new software and you’re
|
||
not sure if you’ll use it again. It’s also convenient when you’re not
|
||
ready to write <code>flake.nix</code> (perhaps you’re not sure what tools and
|
||
packages you need), and you want to experiment a bit first.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The command to enter a temporary shell is</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>nix shell -p <em>installables</em></code></p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Where <em>installables</em> are flakes and other types of packages that you need.
|
||
(You can learn more about these in the
|
||
<a href="https://nix.dev/manual/nix/stable/command-ref/new-cli/nix#installables">Nix manual</a>.)</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s enter a shell with Python so we can test the program.</p>
|
||
</div>
|
||
<div id="python-nix-shell" class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix shell nixpkgs#python3
|
||
$ python hello.py
|
||
Hello from inside a Python program built with a Nix flake!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_configuring_setuptools">9.2.3. Configuring setuptools</h4>
|
||
<div class="paragraph">
|
||
<p>Next, configure the package. We’ll use Python’s
|
||
setuptools, but you can use other build tools. For more information on
|
||
setuptools, see the
|
||
<a href="https://setuptools.pypa.io/en/latest/index.html">Setuptools documentation</a>, especially the section on
|
||
<a href="https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html">pyproject.toml</a>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">pyproject.toml</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="toml"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-k">[project]</span>
|
||
<span class="tok-n">name</span><span class="tok-w"> </span><span class="tok-o">=</span><span class="tok-w"> </span><span class="tok-s2">"hello"</span>
|
||
<span class="tok-n">version</span><span class="tok-w"> </span><span class="tok-o">=</span><span class="tok-w"> </span><span class="tok-s2">"0.1.0"</span>
|
||
<span class="tok-n">dependencies</span><span class="tok-w"> </span><span class="tok-o">=</span><span class="tok-w"> </span><span class="tok-p">[</span><span class="tok-w"> </span><span class="tok-p">]</span>
|
||
|
||
<span class="tok-k">[build-system]</span>
|
||
<span class="tok-n">requires</span><span class="tok-w"> </span><span class="tok-o">=</span><span class="tok-w"> </span><span class="tok-p">[</span><span class="tok-s2">"setuptools"</span><span class="tok-p">]</span>
|
||
<span class="tok-n">build-backend</span><span class="tok-w"> </span><span class="tok-o">=</span><span class="tok-w"> </span><span class="tok-s2">"setuptools.build_meta"</span>
|
||
|
||
<span class="tok-k">[project.scripts]</span>
|
||
<span class="tok-n">hello</span><span class="tok-w"> </span><span class="tok-o">=</span><span class="tok-w"> </span><span class="tok-s2">"hello:main"</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_building_the_program_manually_optional_2">9.2.4. Building the program manually (optional)</h4>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>In this section you will learn how to do some development tasks manually, the "hard" way.
|
||
This can help you understand the distinction between Nix’s role and
|
||
the Python build system you’ve chosen.
|
||
Also, if you have a build problem but you’re not sure if the fault is in
|
||
your flake definition or some other configuration file,
|
||
these commands can help you narrow it down.
|
||
But you may wish to skip to the <a href="#python-flake">next section</a>
|
||
and come back here later.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We won’t write <code>flake.nix</code> just yet.
|
||
First we’ll try building the package manually.
|
||
(If you didn’t run the <code>nix shell</code> command from <a href="#python-nix-shell">earlier</a>, do so now.)</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ python -m build # Fails
|
||
/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/bin/python: No module named build</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The missing module error happens because we don’t have <code>build</code> available
|
||
in the temporary shell. We can fix that by adding “build” to the
|
||
temporary shell. When you need support for both a language and some of
|
||
its packages, it’s best to use one of the Nix functions that are
|
||
specific to the programming language and build system. For Python, we
|
||
can use the <code>withPackages</code> function.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell -p "python3.withPackages (ps: with ps; [ build ])"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note that we’re now inside a temporary shell inside the previous
|
||
temporary shell! To get back to the original shell, we have to <code>exit</code>
|
||
twice.
|
||
Alternatively, we could have done <code>exit</code> followed by the
|
||
second <code>nix-shell</code> command.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ python -m build</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>After a lot of output messages, the build succeeds.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="python-flake">9.2.5. The Nix flake</h4>
|
||
<div class="paragraph">
|
||
<p>Now we should write <code>flake.nix</code>.
|
||
We already know how to write most of the flake from the examples we did earlier.
|
||
The two parts that will be different are the development shell and the package builder.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s start with the development shell. It seems logical to write
|
||
something like the following.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap"> devShells = forAllSupportedSystems (system:
|
||
let
|
||
pkgs = nixpkgsFor.${system};
|
||
pythonEnv = pkgs.python3.withPackages (ps: [ ps.build ]);
|
||
in {
|
||
default = pkgs.mkShell {
|
||
packages = [ pythonEnv ];
|
||
};
|
||
});</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note that we need the parentheses to prevent <code>python.withPackages</code> and
|
||
the argument from being processed as two separate tokens. Suppose we
|
||
wanted to work with <code>virtualenv</code> and <code>pip</code> instead of <code>build</code>. We could
|
||
write something like the following.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap"> devShells = forAllSupportedSystems (system:
|
||
let
|
||
pkgs = nixpkgsFor.${system};
|
||
pythonEnv = pkgs.python3.withPackages (ps: [ ps.virtualenv ps.pip ]);
|
||
in {
|
||
default = pkgs.mkShell {
|
||
packages = [ pythonEnv ];
|
||
};
|
||
});</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For the package builder, we can use the <code>buildPythonApplication</code>
|
||
function.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap"> packages = forAllSupportedSystems (system:
|
||
let pkgs = nixpkgsFor.${system}; in rec {
|
||
hello-flake-python = pkgs.python3Packages.buildPythonApplication {
|
||
name = "hello-flake-python";
|
||
pyproject = true;
|
||
src = ./.;
|
||
build-system = with pkgs.python3Packages; [ setuptools ];
|
||
};
|
||
});</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If you put all the pieces together, your <code>flake.nix</code> should look
|
||
something like this.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span>
|
||
<span class="normal">28</span>
|
||
<span class="normal">29</span>
|
||
<span class="normal">30</span>
|
||
<span class="normal">31</span>
|
||
<span class="normal">32</span>
|
||
<span class="normal">33</span>
|
||
<span class="normal">34</span>
|
||
<span class="normal">35</span>
|
||
<span class="normal">36</span>
|
||
<span class="normal">37</span>
|
||
<span class="normal">38</span>
|
||
<span class="normal">39</span>
|
||
<span class="normal">40</span>
|
||
<span class="normal">41</span>
|
||
<span class="normal">42</span>
|
||
<span class="normal">43</span>
|
||
<span class="normal">44</span>
|
||
<span class="normal">45</span>
|
||
<span class="normal">46</span>
|
||
<span class="normal">47</span>
|
||
<span class="normal">48</span>
|
||
<span class="normal">49</span>
|
||
<span class="normal">50</span>
|
||
<span class="normal">51</span>
|
||
<span class="normal">52</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">description</span> <span class="tok-o">=</span> <span class="tok-s2">"a very simple and friendly flake written in Python"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs <span class="tok-p">}:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">supportedSystems</span> <span class="tok-o">=</span> nixpkgs<span class="tok-o">.</span>lib<span class="tok-o">.</span>systems<span class="tok-o">.</span>flakeExposed<span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">forAllSupportedSystems</span> <span class="tok-o">=</span> nixpkgs<span class="tok-o">.</span>lib<span class="tok-o">.</span>genAttrs supportedSystems<span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">nixpkgsFor</span> <span class="tok-o">=</span> forAllSupportedSystems <span class="tok-p">(</span>system<span class="tok-p">:</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span>
|
||
<span class="tok-k">inherit</span> system<span class="tok-p">;</span>
|
||
<span class="tok-ss">config</span> <span class="tok-o">=</span> <span class="tok-p">{</span> <span class="tok-p">};</span>
|
||
<span class="tok-ss">overlays</span> <span class="tok-o">=</span> <span class="tok-p">[</span> <span class="tok-p">];</span>
|
||
<span class="tok-p">});</span>
|
||
|
||
<span class="tok-k">in</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">devShells</span> <span class="tok-o">=</span> forAllSupportedSystems <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs</span> <span class="tok-o">=</span> nixpkgsFor<span class="tok-o">.</span><span class="tok-si">${</span>system<span class="tok-si">}</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">pythonEnv</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>python3<span class="tok-o">.</span>withPackages <span class="tok-p">(</span>ps<span class="tok-p">:</span> <span class="tok-p">[</span> ps<span class="tok-o">.</span>build <span class="tok-p">]);</span>
|
||
<span class="tok-k">in</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">packages</span> <span class="tok-o">=</span> <span class="tok-p">[</span> pythonEnv <span class="tok-p">];</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">});</span>
|
||
|
||
<span class="tok-ss">packages</span> <span class="tok-o">=</span> forAllSupportedSystems <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span> <span class="tok-ss">pkgs</span> <span class="tok-o">=</span> nixpkgsFor<span class="tok-o">.</span><span class="tok-si">${</span>system<span class="tok-si">}</span><span class="tok-p">;</span> <span class="tok-k">in</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello-flake-python</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>python3Packages<span class="tok-o">.</span>buildPythonApplication <span class="tok-p">{</span>
|
||
<span class="tok-ss">name</span> <span class="tok-o">=</span> <span class="tok-s2">"hello-flake-python"</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">pyproject</span> <span class="tok-o">=</span> <span class="tok-no">true</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">src</span> <span class="tok-o">=</span> <span class="tok-l">./.</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">build-system</span> <span class="tok-o">=</span> <span class="tok-k">with</span> pkgs<span class="tok-o">.</span>python3Packages<span class="tok-p">;</span> <span class="tok-p">[</span> setuptools <span class="tok-p">];</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">});</span>
|
||
|
||
<span class="tok-ss">apps</span> <span class="tok-o">=</span> forAllSupportedSystems <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span> <span class="tok-ss">pkgs</span> <span class="tok-o">=</span> nixpkgsFor<span class="tok-o">.</span><span class="tok-si">${</span>system<span class="tok-si">}</span><span class="tok-p">;</span> <span class="tok-k">in</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello-flake-python</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">type</span> <span class="tok-o">=</span> <span class="tok-s2">"app"</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">program</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>lib<span class="tok-o">.</span>getExe' self<span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-si">${</span>system<span class="tok-si">}</span><span class="tok-o">.</span>hello-flake-python <span class="tok-s2">"hello"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> hello-flake-python<span class="tok-p">;</span>
|
||
<span class="tok-p">});</span>
|
||
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_building_the_program_2">9.2.6. Building the program</h4>
|
||
<div class="paragraph">
|
||
<p>Let’s try out the new flake.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix build # Fails
|
||
error: Path 'flake.nix' in the repository "/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python" is not tracked by Git.
|
||
|
||
To make it visible to Nix, run:
|
||
|
||
git -C "/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python" add "flake.nix"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Nix flakes only “see” files that are part of the repository.
|
||
We need to add all of the important files to the
|
||
repo before building or running the flake.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ git add flake.nix setup.py hello.py
|
||
fatal: pathspec 'setup.py' did not match any files
|
||
$ nix build
|
||
error: Path 'flake.nix' in the repository "/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python" is not tracked by Git.
|
||
|
||
To make it visible to Nix, run:
|
||
|
||
git -C "/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python" add "flake.nix"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We’ll deal with those warnings later.
|
||
The important thing for now is that the build succeeded.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_running_the_program_2">9.2.7. Running the program</h4>
|
||
<div class="paragraph">
|
||
<p>Now we can run the program.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run
|
||
error: Path 'flake.nix' in the repository "/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python" is not tracked by Git.
|
||
|
||
To make it visible to Nix, run:
|
||
|
||
git -C "/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python" add "flake.nix"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>By the way, we didn’t need to do <code>nix build</code> earlier.
|
||
The <code>nix run</code> command will first build the program for us if needed.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We’d like to share this package with others, but first we should do some
|
||
cleanup.
|
||
It’s time to deal with those warnings.
|
||
When the package was built, Nix created a <code>flake.lock</code> file.
|
||
We need to add this to the repo, and commit all important files.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ git add flake.lock
|
||
fatal: pathspec 'flake.lock' did not match any files
|
||
$ git commit -a -m 'initial commit'
|
||
On branch master
|
||
|
||
Initial commit
|
||
|
||
Untracked files:
|
||
(use "git add <file>..." to include in what will be committed)
|
||
dist/
|
||
flake.nix
|
||
hello.egg-info/
|
||
hello.py
|
||
pyproject.toml
|
||
|
||
nothing added to commit but untracked files present (use "git add" to track)</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>You can test that your package is properly configured by going to
|
||
another directory and running it from there.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ cd ..
|
||
$ nix run ./hello-python
|
||
error: Path 'flake.nix' in the repository "/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python" is not tracked by Git.
|
||
|
||
To make it visible to Nix, run:
|
||
|
||
git -C "/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python" add "flake.nix"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If you move the project to a public repo, anyone can run it. Recall from
|
||
the beginning of the tutorial that you were able to run <code>hello-flake</code>
|
||
directly from my repo with the following command.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">nix run "git+https://codeberg.org/mhwombat/hello-flake"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Modify the URL accordingly and invite someone else to run your new
|
||
Python flake.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_recipes">10. Recipes</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>This chapter provides examples of how to use Nix in a variety of scenarios.
|
||
Multiple types of recipes are provided are provided for some scenarios;
|
||
comparing the different recipes will help you better understand Nix.</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><em>"Ad hoc" shells</em>
|
||
are useful when you want to quickly create an environment
|
||
for a one-off task.</p>
|
||
</li>
|
||
<li>
|
||
<p><em>Nix flakes</em>
|
||
are the recommended approach for development projects,
|
||
including defining environments that you will use more than once.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_running_programs_directly_without_installing_them">10.1. Running programs directly (without installing them)</h3>
|
||
<div class="sect3">
|
||
<h4 id="_run_a_top_level_package_from_the_nixpkgsnixos_repo">10.1.1. Run a top level package from the Nixpkgs/NixOS repo</h4>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run nixpkgs#cowsay "Moo!"
|
||
______
|
||
< Moo! >
|
||
------
|
||
\ ^__^
|
||
\ (oo)\_______
|
||
(__)\ )\/\
|
||
||----w |
|
||
|| ||</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="flakeref">10.1.2. Run a flake</h4>
|
||
<div class="sect4">
|
||
<h5 id="_run_a_flake_defined_in_a_local_file">Run a flake defined in a local file</h5>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run ~/codeberg/hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="_run_a_flake_defined_in_a_remote_git_repo">Run a flake defined in a remote git repo</h5>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run git+https://codeberg.org/mhwombat/hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>To use a package from GitHub, GitLab, or any other public platform,
|
||
modify the URL accordingly.
|
||
To run a specific branch, use the command below.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">nix run git+https://codeberg.org/mhwombat/hello-flake?ref=main</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>To run a specific branch and revision, use the command below.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">nix run git+https://codeberg.org/mhwombat/hello-flake?ref=main&rev=d44728bce88a6f9d1d37dbf4720ece455e997606</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="_run_a_flake_defined_in_a_zip_archive">Run a flake defined in a zip archive</h5>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run https://codeberg.org/mhwombat/hello-flake/archive/main.zip
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="_run_a_flake_defined_in_a_compressed_tar_archive">Run a flake defined in a compressed tar archive</h5>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run https://codeberg.org/mhwombat/hello-flake/archive/main.tar.gz
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="_run_other_types_of_flake_references">Run other types of flake references</h5>
|
||
<div class="paragraph">
|
||
<p>See <a href="https://nix.dev/manual/nix/stable/command-ref/new-cli/nix3-flake#flake-reference-attributes" class="bare">https://nix.dev/manual/nix/stable/command-ref/new-cli/nix3-flake#flake-reference-attributes</a>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_ad_hoc_environments">10.2. Ad hoc environments</h3>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_top_level_package_from_the_nixpkgsnixos_repo">10.2.1. Access a top level package from the Nixpkgs/NixOS repo</h4>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix shell nixpkgs#cowsay
|
||
$ cowsay "moo"
|
||
_____
|
||
< moo >
|
||
-----
|
||
\ ^__^
|
||
\ (oo)\_______
|
||
(__)\ )\/\
|
||
||----w |
|
||
|| ||</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_flake">10.2.2. Access a flake</h4>
|
||
<div class="paragraph">
|
||
<p>In this example, we will use a flake defined in a remote git repo.
|
||
However, you can use any of the flake reference styles defined in <a href="#flakeref">Section 10.1.2, “Run a flake”</a>.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix shell git+https://codeberg.org/mhwombat/hello-flake
|
||
$ hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="shebang">10.3. Scripts</h3>
|
||
<div class="paragraph">
|
||
<p>You can use <code>nix shell</code> to run scripts in arbitrary languages, providing
|
||
the necessary dependencies.
|
||
This is particularly convenient for standalone scripts
|
||
because you don’t need to create a repo and write a separate <code>flake.nix</code>.
|
||
The script should start with two <em>"shebang"</em> (<code>#!</code>) commands.
|
||
The first should invoke <code>nix</code>.
|
||
The second should declares the script interpreter and any dependencies.</p>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_top_level_package_from_the_nixpkgsnixos_repo_2">10.3.1. Access a top level package from the Nixpkgs/NixOS repo</h4>
|
||
<div class="listingblock">
|
||
<div class="title">Script</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="bash"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span></pre></div></td><td class="code"><div><pre><span></span><span class="hll"><span class="tok-ch">#! /usr/bin/env nix</span>
|
||
</span><span class="hll"><span class="tok-c1">#! nix shell nixpkgs#hello nixpkgs#cowsay --command bash</span>
|
||
</span>hello
|
||
cowsay<span class="tok-w"> </span><span class="tok-s2">"Pretty cool, huh?"</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="title">Output</div>
|
||
<div class="content">
|
||
<pre class="nowrap">Hello, world!
|
||
___________________
|
||
< Pretty cool, huh? >
|
||
-------------------
|
||
\ ^__^
|
||
\ (oo)\_______
|
||
(__)\ )\/\
|
||
||----w |
|
||
|| ||</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_flake_2">10.3.2. Access a flake</h4>
|
||
<div class="paragraph">
|
||
<p>In this example, we will use a flake defined in a remote git repo.
|
||
However, you can use any of the flake reference styles defined in <a href="#flakeref">Section 10.1.2, “Run a flake”</a>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Script</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="bash"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><span class="hll"><span class="tok-ch">#! /usr/bin/env nix</span>
|
||
</span><span class="hll"><span class="tok-c1">#! nix shell git+https://codeberg.org/mhwombat/hello-flake --command bash</span>
|
||
</span>hello-flake
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="title">Output</div>
|
||
<div class="content">
|
||
<pre class="nowrap">Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_haskell_library_package_in_the_nixpkgs_repo_without_a_cabal_file">10.3.3. Access a Haskell library package in the nixpkgs repo (without a <code>.cabal</code> file)</h4>
|
||
<div class="paragraph">
|
||
<p>Occasionally you might want to run a short Haskell program that depends on a Haskell library,
|
||
but you don’t want to bother writing a cabal file.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Example: Access the <code>extra</code> package from the <code>haskellPackages</code> set in the nixpkgs repo.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Script</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="haskell"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-o">#!</span><span class="tok-w"> </span><span class="tok-o">/</span><span class="tok-n">usr</span><span class="tok-o">/</span><span class="tok-n">bin</span><span class="tok-o">/</span><span class="tok-n">env</span><span class="tok-w"> </span><span class="tok-n">nix</span><span class="tok-o">-</span><span class="tok-n">shell</span>
|
||
<span class="tok-o">#!</span><span class="tok-w"> </span><span class="tok-n">nix</span><span class="tok-o">-</span><span class="tok-n">shell</span><span class="tok-w"> </span><span class="tok-o">-</span><span class="tok-n">p</span><span class="tok-w"> </span><span class="tok-s">"haskellPackages.ghcWithPackages (p: [p.extra])"</span>
|
||
<span class="tok-o">#!</span><span class="tok-w"> </span><span class="tok-n">nix</span><span class="tok-o">-</span><span class="tok-n">shell</span><span class="tok-w"> </span><span class="tok-o">-</span><span class="tok-n">i</span><span class="tok-w"> </span><span class="tok-n">runghc</span>
|
||
|
||
<span class="tok-kr">import</span><span class="tok-w"> </span><span class="tok-nn">Data.List.Extra</span>
|
||
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">::</span><span class="tok-w"> </span><span class="tok-kt">IO</span><span class="tok-w"> </span><span class="tok-nb">()</span>
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-kr">do</span>
|
||
<span class="tok-w"> </span><span class="tok-n">print</span><span class="tok-w"> </span><span class="tok-o">$</span><span class="tok-w"> </span><span class="tok-n">lower</span><span class="tok-w"> </span><span class="tok-s">"ABCDE"</span>
|
||
<span class="tok-w"> </span><span class="tok-n">print</span><span class="tok-w"> </span><span class="tok-o">$</span><span class="tok-w"> </span><span class="tok-n">upper</span><span class="tok-w"> </span><span class="tok-s">"XYZ"</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="title">Output</div>
|
||
<div class="content">
|
||
<pre class="nowrap">"abcde"
|
||
"XYZ"</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_python_library_package_in_the_nixpkgs_repo_without_using_a_python_builder">10.3.4. Access a Python library package in the nixpkgs repo (without using a Python builder)</h4>
|
||
<div class="paragraph">
|
||
<p>Occasionally you might want to run a short Python program that depends on a Python library,
|
||
but you don’t want to bother configuring a builder.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Example: Access the <code>html_sanitizer</code> package from the <code>python3nnPackages</code> set in the nixpkgs repo.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Script</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="python"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-ch">#! /usr/bin/env nix-shell</span>
|
||
<span class="tok-c1">#! nix-shell -i python3 -p python3Packages.html-sanitizer</span>
|
||
|
||
<span class="tok-kn">from</span> <span class="tok-nn">html_sanitizer</span> <span class="tok-kn">import</span> <span class="tok-n">Sanitizer</span>
|
||
<span class="tok-n">sanitizer</span> <span class="tok-o">=</span> <span class="tok-n">Sanitizer</span><span class="tok-p">()</span> <span class="tok-c1"># default configuration</span>
|
||
|
||
<span class="tok-n">original</span><span class="tok-o">=</span><span class="tok-s1">'<span style="font-weight:bold">some text</span>'</span>
|
||
<span class="tok-nb">print</span><span class="tok-p">(</span><span class="tok-s1">'original: '</span><span class="tok-p">,</span> <span class="tok-n">original</span><span class="tok-p">)</span>
|
||
|
||
<span class="tok-n">sanitized</span><span class="tok-o">=</span><span class="tok-n">sanitizer</span><span class="tok-o">.</span><span class="tok-n">sanitize</span><span class="tok-p">(</span><span class="tok-n">original</span><span class="tok-p">)</span>
|
||
<span class="tok-nb">print</span><span class="tok-p">(</span><span class="tok-s1">'sanitized: '</span><span class="tok-p">,</span> <span class="tok-n">sanitized</span><span class="tok-p">)</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="title">Output</div>
|
||
<div class="content">
|
||
<pre class="nowrap">original: <span style="font-weight:bold">some text</span>
|
||
sanitized: <strong>some text</strong></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_development_environments">10.4. Development environments</h3>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_top_level_package_from_the_nixpkgsnixos_repo_3">10.4.1. Access a top level package from the Nixpkgs/NixOS repo</h4>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils <span class="tok-p">}:</span>
|
||
flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs</span> <span class="tok-o">=</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span> <span class="tok-k">inherit</span> system<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">devShells</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>mkShell <span class="tok-p">{</span>
|
||
<span class="hll"> <span class="tok-ss">packages</span> <span class="tok-o">=</span> <span class="tok-p">[</span> pkgs<span class="tok-o">.</span>cowsay <span class="tok-p">];</span>
|
||
</span> <span class="tok-p">};</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the shell.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ cowsay "Moo!" # Fails; dependency not available
|
||
bash: line 17: cowsay: command not found
|
||
$ nix develop
|
||
$ cowsay "Moo!" # Works in development environment
|
||
______
|
||
< Moo! >
|
||
------
|
||
\ ^__^
|
||
\ (oo)\_______
|
||
(__)\ )\/\
|
||
||----w |
|
||
|| ||</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_flake_3">10.4.2. Access a flake</h4>
|
||
<div class="paragraph">
|
||
<p>In this example, we will use a flake defined in a remote git repo.
|
||
However, you can use any of the flake reference styles defined in <a href="#flakeref">Section 10.1.2, “Run a flake”</a>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="hll"> hello-flake<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"git+https://codeberg.org/mhwombat/hello-flake"</span><span class="tok-p">;</span>
|
||
</span> <span class="tok-p">};</span>
|
||
|
||
<span class="hll"> <span class="tok-ss">outputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils<span class="tok-p">,</span> hello-flake <span class="tok-p">}:</span>
|
||
</span> flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs</span> <span class="tok-o">=</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span> <span class="tok-k">inherit</span> system<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">devShells</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>mkShell <span class="tok-p">{</span>
|
||
<span class="hll"> <span class="tok-ss">buildInputs</span> <span class="tok-o">=</span> <span class="tok-p">[</span> hello-flake<span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-si">${</span>system<span class="tok-si">}</span><span class="tok-o">.</span>hello <span class="tok-p">];</span>
|
||
</span> <span class="tok-p">};</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Line 5 adds <code>hello-flake</code> as an input to this flake.
|
||
Line 8 allows the output function to reference <code>hello-flake</code>.
|
||
Line 16 adds <code>hello-flake</code> as a build input for this flake.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s take a closer look at the <code>buildInputs</code> expression from line 16.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">hello-flake.packages.${system}.hello</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Why is the first part <code>hello-flake</code> and the last part <code>hello</code>?
|
||
The first part refers to the name we assigned in the input section of our flake,
|
||
and the last part is the name of the package or app we want.
|
||
(See <a href="#_flake_outputs">Section 4.1, “Flake outputs”</a> for how to identify flake outputs.)</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the shell.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ hello-flake # Fails; dependency not available
|
||
bash: line 35: hello-flake: command not found
|
||
$ nix develop
|
||
$ hello-flake # Works in development environment
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_haskell_library_package_in_the_nixpkgs_repo_without_using_a_cabal_file">10.4.3. Access a Haskell library package in the nixpkgs repo (without using a <code>.cabal</code> file)</h4>
|
||
<div class="paragraph">
|
||
<p>Occasionally you might want to run a short Haskell program that depends on a Haskell library,
|
||
but you don’t want to bother writing a cabal file.
|
||
In this example, we will access the <code>extra</code> package from the <code>haskellPackages</code> set in the nixpkgs repo.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>For non-trivial Haskell development projects,
|
||
it’s usually more convenient to use <code>haskell-flake</code> as described in <a href="#haskell-flake">Section 9.1.5, “The Nix flake”</a>,
|
||
together with the <em>high-level workflow</em> described in <a href="#_development_workflows">[_development_workflows]</a>.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils <span class="tok-p">}:</span>
|
||
flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs</span> <span class="tok-o">=</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span> <span class="tok-k">inherit</span> system<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="hll"> <span class="tok-ss">customGhc</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>haskellPackages<span class="tok-o">.</span>ghcWithPackages <span class="tok-p">(</span>p<span class="tok-p">:</span> <span class="tok-k">with</span> p<span class="tok-p">;</span> <span class="tok-p">[</span> p<span class="tok-o">.</span>extra <span class="tok-p">]);</span>
|
||
</span> <span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">devShells</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>mkShell <span class="tok-p">{</span>
|
||
<span class="hll"> <span class="tok-ss">buildInputs</span> <span class="tok-o">=</span> <span class="tok-p">[</span> customGhc <span class="tok-p">];</span>
|
||
</span> <span class="tok-p">};</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Line 12 makes a custom GHC that knows about <code>extra</code>,
|
||
and line 16 makes that custom GHC available in the development environment.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a short Haskell program that uses the new flake.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Main.hs</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="haskell"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span>
|
||
<span class="normal">5</span>
|
||
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-kr">import</span><span class="tok-w"> </span><span class="tok-nn">Data.List.Extra</span>
|
||
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">::</span><span class="tok-w"> </span><span class="tok-kt">IO</span><span class="tok-w"> </span><span class="tok-nb">()</span>
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-kr">do</span>
|
||
<span class="tok-w"> </span><span class="tok-n">print</span><span class="tok-w"> </span><span class="tok-o">$</span><span class="tok-w"> </span><span class="tok-n">lower</span><span class="tok-w"> </span><span class="tok-s">"ABCDE"</span>
|
||
<span class="tok-w"> </span><span class="tok-n">print</span><span class="tok-w"> </span><span class="tok-o">$</span><span class="tok-w"> </span><span class="tok-n">upper</span><span class="tok-w"> </span><span class="tok-s">"XYZ"</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the program.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ runghc Main.hs # Fails; dependency not available
|
||
|
||
Main.hs:1:1: error: [GHC-87110]
|
||
Could not find module ‘Data.List.Extra’.
|
||
Use :set -v to see a list of the files searched for.
|
||
|
|
||
1 | import Data.List.Extra
|
||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||
$ nix develop
|
||
$ runghc Main.hs # Works in development environment
|
||
"abcde"
|
||
"XYZ"</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_set_an_environment_variable">10.4.4. Set an environment variable</h4>
|
||
<div class="paragraph">
|
||
<p>Set the value of the environment variable FOO to “bar”.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils <span class="tok-p">}:</span>
|
||
flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs</span> <span class="tok-o">=</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span> <span class="tok-k">inherit</span> system<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">devShells</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">shellHook</span> <span class="tok-o">=</span> <span class="tok-s tok-s-Multiline">''</span>
|
||
<span class="tok-s tok-s-Multiline"> export FOO="bar"</span>
|
||
<span class="tok-s tok-s-Multiline"> ''</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the shell.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ echo "FOO=${FOO}"
|
||
FOO=
|
||
$ nix develop
|
||
$ echo "FOO=${FOO}"
|
||
FOO=bar</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="devshell-nix-non-flake">10.4.5. Access a non-flake package (not in nixpkgs)</h4>
|
||
<div class="paragraph">
|
||
<p>In this example, we will use a nix package (not a flake) defined in a remote git repo.
|
||
However, you can use any of the flake reference styles defined in <a href="#flakeref">Section 10.1.2, “Run a flake”</a>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>hello-nix</code> <a href="https://codeberg.org/mhwombat/hello-nix">repo</a> provides a <code>default.nix</code>.
|
||
If the derivation in that file allows us to supply our own package set,
|
||
then our flake can call it to build <code>hello nix</code>.
|
||
If instead it requires <code><nixpkgs></code>, it is not pure and we cannot use it.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For example, if the file begins with an expression such as</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-k">with</span> <span class="tok-p">(</span><span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{});</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>then it requires <code>nixpkgs</code> so we cannot use it.
|
||
Instead, we have to write our own derivation (see <a href="#devshell-impure">Section 10.4.5.2, “If the nix derivation requires <code>nixpkgs</code>”</a>).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Fortunately the file begins with</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-p">{</span> pkgs <span class="tok-o">?</span> <span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{}</span> <span class="tok-p">}:</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>then it accepts a package set as an argument,
|
||
only using <code><nixpkgs></code> if no argument is provided.
|
||
We can use it directly to build <code>hello-nix</code> (see <a href="#devshell-pure">Section 10.4.5.1, “If the nix derivation does not require nixpkgs”</a>).</p>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="devshell-pure">If the nix derivation does not require nixpkgs</h5>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="hll"> <span class="tok-ss">hello-nix</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
</span><span class="hll"> <span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"git+https://codeberg.org/mhwombat/hello-nix"</span><span class="tok-p">;</span>
|
||
</span><span class="hll"> <span class="tok-ss">flake</span> <span class="tok-o">=</span> <span class="tok-no">false</span><span class="tok-p">;</span>
|
||
</span><span class="hll"> <span class="tok-p">};</span>
|
||
</span> <span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils<span class="tok-p">,</span> hello-nix <span class="tok-p">}:</span>
|
||
flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs</span> <span class="tok-o">=</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span>
|
||
<span class="tok-k">inherit</span> system<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="hll"> <span class="tok-ss">helloNix</span> <span class="tok-o">=</span> <span class="tok-nb">import</span> hello-nix <span class="tok-p">{</span> <span class="tok-k">inherit</span> pkgs<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
</span> <span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">devShells</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">packages</span> <span class="tok-o">=</span> <span class="tok-p">[</span> helloNix <span class="tok-p">];</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Lines 5-8 fetches the git repo for <code>hello-nix</code>.
|
||
However, it is not a flake, so we have to build it;
|
||
this is done in line 15.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the shell.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ hello-nix # Fails outside development shell
|
||
bash: line 53: hello-nix: command not found
|
||
$ nix develop
|
||
$ hello-nix
|
||
Hello from your nix package!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="devshell-impure">If the nix derivation requires <code>nixpkgs</code></h5>
|
||
<div class="paragraph">
|
||
<p>In this case, we need to write the derivation ourselves.
|
||
We can use <code>default.nix</code> (from the hello-nix repo) as a model.
|
||
Line 15 should be replaced with:</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span> <span class="tok-ss">helloNix</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>stdenv<span class="tok-o">.</span>mkDerivation <span class="tok-p">{</span>
|
||
<span class="tok-ss">name</span> <span class="tok-o">=</span> <span class="tok-s2">"hello-nix"</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">src</span> <span class="tok-o">=</span> hello-nix<span class="tok-p">;</span>
|
||
<span class="tok-ss">installPhase</span> <span class="tok-o">=</span>
|
||
<span class="tok-s tok-s-Multiline">''</span>
|
||
<span class="tok-s tok-s-Multiline"> mkdir -p $out/bin</span>
|
||
<span class="tok-s tok-s-Multiline"> cp $src/hello-nix $out/bin/hello-nix</span>
|
||
<span class="tok-s tok-s-Multiline"> chmod +x $out/bin/hello-nix</span>
|
||
<span class="tok-s tok-s-Multiline"> ''</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_buildruntime_environments">10.5. Build/runtime environments</h3>
|
||
<div class="paragraph">
|
||
<p>sh: line 1: run-code-inline: command not found</p>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_flake_4">10.5.1. Access a flake</h4>
|
||
<div class="paragraph">
|
||
<p>In this example, we will use a flake defined in a remote git repo.
|
||
However, you can use any of the flake reference styles defined in <a href="#flakeref">Section 10.1.2, “Run a flake”</a>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">hello-again</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="bash"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-ch">#!/usr/bin/env sh</span>
|
||
|
||
<span class="tok-nb">echo</span><span class="tok-w"> </span><span class="tok-s2">"I'm a flake, and I'm running a command defined in a another flake."</span>
|
||
hello-flake
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span>
|
||
<span class="normal">28</span>
|
||
<span class="normal">29</span>
|
||
<span class="normal">30</span>
|
||
<span class="normal">31</span>
|
||
<span class="normal">32</span>
|
||
<span class="normal">33</span>
|
||
<span class="normal">34</span>
|
||
<span class="normal">35</span>
|
||
<span class="normal">36</span>
|
||
<span class="normal">37</span>
|
||
<span class="normal">38</span>
|
||
<span class="normal">39</span>
|
||
<span class="normal">40</span>
|
||
<span class="normal">41</span>
|
||
<span class="normal">42</span>
|
||
<span class="normal">43</span>
|
||
<span class="normal">44</span>
|
||
<span class="normal">45</span>
|
||
<span class="normal">46</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="hll"> hello-flake<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"git+https://codeberg.org/mhwombat/hello-flake"</span><span class="tok-p">;</span>
|
||
</span> <span class="tok-p">};</span>
|
||
|
||
<span class="hll"> <span class="tok-ss">outputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils<span class="tok-p">,</span> hello-flake <span class="tok-p">}:</span>
|
||
</span> flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs</span> <span class="tok-o">=</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span> <span class="tok-k">inherit</span> system<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">packages</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>stdenv<span class="tok-o">.</span>mkDerivation <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">name</span> <span class="tok-o">=</span> <span class="tok-s2">"hello-again"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">src</span> <span class="tok-o">=</span> <span class="tok-l">./.</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">unpackPhase</span> <span class="tok-o">=</span> <span class="tok-s2">"true"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">buildPhase</span> <span class="tok-o">=</span> <span class="tok-s2">":"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">installPhase</span> <span class="tok-o">=</span>
|
||
<span class="tok-s tok-s-Multiline">''</span>
|
||
<span class="tok-s tok-s-Multiline"> mkdir -p $out/bin</span>
|
||
<span class="tok-s tok-s-Multiline"> cp $src/hello-again $out/bin</span>
|
||
<span class="tok-s tok-s-Multiline"> chmod +x $out/bin/hello-again</span>
|
||
|
||
<span class="hll"><span class="tok-s tok-s-Multiline"> # modify the hello-again script so it can find hello-flake</span>
|
||
</span><span class="hll"><span class="tok-s tok-s-Multiline"> HELLO=$(type -p hello-flake)</span>
|
||
</span><span class="hll"><span class="tok-s tok-s-Multiline"> sed "s_hello-flake_"$HELLO"_" --in-place $out/bin/hello-again</span>
|
||
</span><span class="tok-s tok-s-Multiline"> ''</span><span class="tok-p">;</span>
|
||
|
||
<span class="hll"> <span class="tok-ss">buildInputs</span> <span class="tok-o">=</span> <span class="tok-p">[</span> hello-flake<span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-si">${</span>system<span class="tok-si">}</span><span class="tok-o">.</span>hello <span class="tok-p">];</span>
|
||
</span> <span class="tok-p">};</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">apps</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello</span> <span class="tok-o">=</span> flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>mkApp <span class="tok-p">{</span> <span class="tok-ss">drv</span> <span class="tok-o">=</span> self<span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-si">${</span>system<span class="tok-si">}</span><span class="tok-o">.</span>hello<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Line 5 adds <code>hello-flake</code> as an input to this flake,
|
||
Line 8 allows the output function to reference <code>hello-flake</code>.
|
||
As expected, we need to add <code>hello-flake</code> as a build input, which we do in line 35.
|
||
Let’s take a closer look at the <code>buildInputs</code> expression from line 35.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">hello-flake.packages.${system}.hello</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Why is the first part <code>hello-flake</code> and the last part <code>hello</code>?
|
||
The first part refers to the name we assigned in the input section of our flake,
|
||
and the last part is the name of the package or app we want.
|
||
(See <a href="#_flake_outputs">Section 4.1, “Flake outputs”</a> for how to identify flake outputs.)</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Line 35 does make <code>hello-flake</code> available at build and runtime,
|
||
but it doesn’t put it on the path,
|
||
so our <code>hello-again</code> script won’t be able to find it.
|
||
There are various ways to deal with this problem.
|
||
In this case we simply edited the script (lines 30-32) as we install it,
|
||
by specifying the full path to <code>hello-nix</code>.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>When you’re packaging a program written in a more powerful language such as
|
||
Haskell, Python, Java, C, C#, or Rust,
|
||
the language build system will usually do all that is required
|
||
to make the dependencies visible to the program at runtime.
|
||
In that case, adding the dependency to <code>buildInputs</code> is sufficient.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the flake.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run
|
||
I'm a flake, and I'm running a command defined in a another flake.
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_haskell_library_package_in_the_nixpkgs_repo">10.5.2. Access a Haskell library package in the nixpkgs repo</h4>
|
||
<div class="paragraph">
|
||
<p>If you use <code>haskell-flake</code> (see <a href="#haskell-flake">Section 9.1.5, “The Nix flake”</a>)
|
||
nothing special needs to be added to <code>flake.nix</code>.
|
||
Simply list your Haskell package dependencies to your cabal file as you normally would.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_to_a_haskell_package_defined_in_a_flake">10.5.3. Access to a Haskell package defined in a flake</h4>
|
||
<div class="paragraph">
|
||
<p>In this example we will access three Haskell packages
|
||
(<code>pandoc-linear-table</code>, <code>pandoc-logic-proof</code>, and <code>pandoc-columns</code>)
|
||
that are defined as flakes on my hard drive.
|
||
We are using <code>haskell-flake</code>, so the development environment is
|
||
set up automatically; no need to define <code>devShells</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span>
|
||
<span class="normal">28</span>
|
||
<span class="normal">29</span>
|
||
<span class="normal">30</span>
|
||
<span class="normal">31</span>
|
||
<span class="normal">32</span>
|
||
<span class="normal">33</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">description</span> <span class="tok-o">=</span> <span class="tok-s2">"Pandoc build system for maths web"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:nixos/nixpkgs/nixpkgs-unstable"</span><span class="tok-p">;</span>
|
||
flake-parts<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:hercules-ci/flake-parts"</span><span class="tok-p">;</span>
|
||
haskell-flake<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:srid/haskell-flake"</span><span class="tok-p">;</span>
|
||
<span class="hll"> pandoc-linear-table<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"/home/amy/github/pandoc-linear-table"</span><span class="tok-p">;</span>
|
||
</span><span class="hll"> pandoc-logic-proof<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"/home/amy/github/pandoc-logic-proof"</span><span class="tok-p">;</span>
|
||
</span><span class="hll"> pandoc-columns<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"/home/amy/github/pandoc-columns"</span><span class="tok-p">;</span>
|
||
</span><span class="hll"> pandoc-query<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"/home/amy/codeberg/pandoc-query"</span><span class="tok-p">;</span>
|
||
</span> <span class="tok-p">};</span>
|
||
<span class="hll"> <span class="tok-ss">outputs</span> <span class="tok-o">=</span> inputs<span class="tok-p">@{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-parts<span class="tok-p">,</span> pandoc-linear-table<span class="tok-p">,</span> pandoc-logic-proof<span class="tok-p">,</span> pandoc-columns<span class="tok-p">,</span> pandoc-query<span class="tok-p">,</span> <span class="tok-o">...</span> <span class="tok-p">}:</span>
|
||
</span> flake-parts<span class="tok-o">.</span>lib<span class="tok-o">.</span>mkFlake <span class="tok-p">{</span> <span class="tok-k">inherit</span> inputs<span class="tok-p">;</span> <span class="tok-p">}</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">systems</span> <span class="tok-o">=</span> nixpkgs<span class="tok-o">.</span>lib<span class="tok-o">.</span>systems<span class="tok-o">.</span>flakeExposed<span class="tok-p">;</span>
|
||
<span class="tok-ss">imports</span> <span class="tok-o">=</span> <span class="tok-p">[</span> inputs<span class="tok-o">.</span>haskell-flake<span class="tok-o">.</span>flakeModule <span class="tok-p">];</span>
|
||
|
||
<span class="tok-ss">perSystem</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self'<span class="tok-p">,</span> pkgs<span class="tok-p">,</span> <span class="tok-o">...</span> <span class="tok-p">}:</span> <span class="tok-p">{</span>
|
||
haskellProjects<span class="tok-o">.</span><span class="tok-ss">default</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
<span class="tok-c1"># use my versions of some Haskell pagkages instead of the nixpkgs versions</span>
|
||
<span class="hll"> <span class="tok-ss">packages</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
</span><span class="hll"> pandoc-linear-table<span class="tok-o">.</span><span class="tok-ss">source</span> <span class="tok-o">=</span> inputs<span class="tok-o">.</span>pandoc-linear-table<span class="tok-p">;</span>
|
||
</span><span class="hll"> pandoc-logic-proof<span class="tok-o">.</span><span class="tok-ss">source</span> <span class="tok-o">=</span> inputs<span class="tok-o">.</span>pandoc-logic-proof<span class="tok-p">;</span>
|
||
</span><span class="hll"> pandoc-columns<span class="tok-o">.</span><span class="tok-ss">source</span> <span class="tok-o">=</span> inputs<span class="tok-o">.</span>pandoc-columns<span class="tok-p">;</span>
|
||
</span><span class="hll"> pandoc-query<span class="tok-o">.</span><span class="tok-ss">source</span> <span class="tok-o">=</span> inputs<span class="tok-o">.</span>pandoc-query<span class="tok-p">;</span>
|
||
</span><span class="hll"> <span class="tok-p">};</span>
|
||
</span> <span class="tok-p">};</span>
|
||
|
||
<span class="tok-c1"># haskell-flake doesn't set the default package, but you can do it here.</span>
|
||
packages<span class="tok-o">.</span><span class="tok-ss">default</span> <span class="tok-o">=</span> self'<span class="tok-o">.</span>packages<span class="tok-o">.</span>pandoc-maths-web<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_access_a_non_flake_package_not_in_nixpkgs">10.5.4. Access a non-flake package (not in nixpkgs)</h4>
|
||
<div class="paragraph">
|
||
<p>In this example, we will use a nix package (not a flake) defined in a remote git repo.
|
||
However, you can use any of the flake reference styles defined in <a href="#flakeref">Section 10.1.2, “Run a flake”</a>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We already covered how to add a non-flake input to a flake and build it in <a href="#devshell-nix-non-flake">Section 10.4.5, “Access a non-flake package (not in nixpkgs)”</a>;
|
||
here we will focus on making it available at runtime.
|
||
We will write a flake to package a very simple shell script.
|
||
All it does is invoke <code>hello-nix</code>, which is the input we added <a href="#devshell-nix-non-flake">earlier</a>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">hello-again</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="bash"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-ch">#!/usr/bin/env sh</span>
|
||
|
||
<span class="tok-nb">echo</span><span class="tok-w"> </span><span class="tok-s2">"I'm a flake, but I'm running a command defined in a non-flake package."</span>
|
||
hello-nix
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span>
|
||
<span class="normal">28</span>
|
||
<span class="normal">29</span>
|
||
<span class="normal">30</span>
|
||
<span class="normal">31</span>
|
||
<span class="normal">32</span>
|
||
<span class="normal">33</span>
|
||
<span class="normal">34</span>
|
||
<span class="normal">35</span>
|
||
<span class="normal">36</span>
|
||
<span class="normal">37</span>
|
||
<span class="normal">38</span>
|
||
<span class="normal">39</span>
|
||
<span class="normal">40</span>
|
||
<span class="normal">41</span>
|
||
<span class="normal">42</span>
|
||
<span class="normal">43</span>
|
||
<span class="normal">44</span>
|
||
<span class="normal">45</span>
|
||
<span class="normal">46</span>
|
||
<span class="normal">47</span>
|
||
<span class="normal">48</span>
|
||
<span class="normal">49</span>
|
||
<span class="normal">50</span>
|
||
<span class="normal">51</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">inputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="hll"> <span class="tok-ss">hello-nix</span> <span class="tok-o">=</span> <span class="tok-p">{</span>
|
||
</span><span class="hll"> <span class="tok-ss">url</span> <span class="tok-o">=</span> <span class="tok-s2">"git+https://codeberg.org/mhwombat/hello-nix"</span><span class="tok-p">;</span>
|
||
</span><span class="hll"> <span class="tok-ss">flake</span> <span class="tok-o">=</span> <span class="tok-no">false</span><span class="tok-p">;</span>
|
||
</span><span class="hll"> <span class="tok-p">};</span>
|
||
</span> <span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs</span> <span class="tok-o">=</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils<span class="tok-p">,</span> hello-nix <span class="tok-p">}:</span>
|
||
flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs</span> <span class="tok-o">=</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span> <span class="tok-k">inherit</span> system<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="hll"> <span class="tok-ss">helloNix</span> <span class="tok-o">=</span> <span class="tok-nb">import</span> hello-nix <span class="tok-p">{</span> <span class="tok-k">inherit</span> pkgs<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
</span> <span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">packages</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello</span> <span class="tok-o">=</span> pkgs<span class="tok-o">.</span>stdenv<span class="tok-o">.</span>mkDerivation <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">name</span> <span class="tok-o">=</span> <span class="tok-s2">"hello-again"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">src</span> <span class="tok-o">=</span> <span class="tok-l">./.</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">unpackPhase</span> <span class="tok-o">=</span> <span class="tok-s2">"true"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">buildPhase</span> <span class="tok-o">=</span> <span class="tok-s2">":"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">installPhase</span> <span class="tok-o">=</span>
|
||
<span class="tok-s tok-s-Multiline">''</span>
|
||
<span class="tok-s tok-s-Multiline"> mkdir -p $out/bin</span>
|
||
<span class="tok-s tok-s-Multiline"> cp $src/hello-again $out/bin</span>
|
||
<span class="tok-s tok-s-Multiline"> chmod +x $out/bin/hello-again</span>
|
||
|
||
<span class="hll"><span class="tok-s tok-s-Multiline"> # modify the hello-again script so it can find hello-nix</span>
|
||
</span><span class="hll"><span class="tok-s tok-s-Multiline"> HELLO=$(type -p hello-nix)</span>
|
||
</span><span class="hll"><span class="tok-s tok-s-Multiline"> sed "s_hello-nix_"$HELLO"_" --in-place $out/bin/hello-again</span>
|
||
</span><span class="tok-s tok-s-Multiline"> ''</span><span class="tok-p">;</span>
|
||
|
||
|
||
<span class="hll"> <span class="tok-ss">buildInputs</span> <span class="tok-o">=</span> <span class="tok-p">[</span> helloNix <span class="tok-p">];</span>
|
||
</span> <span class="tok-p">};</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">apps</span> <span class="tok-o">=</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello</span> <span class="tok-o">=</span> flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>mkApp <span class="tok-p">{</span> <span class="tok-ss">drv</span> <span class="tok-o">=</span> self<span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-si">${</span>system<span class="tok-si">}</span><span class="tok-o">.</span>hello<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-ss">default</span> <span class="tok-o">=</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Lines 5-8 and 15 were explained in <a href="#devshell-nix-non-flake">Section 10.4.5, “Access a non-flake package (not in nixpkgs)”</a>.
|
||
As expected, we need to add <code>helloNix</code> as a build input, which we do in line 40.
|
||
That does make it available at build and runtime, but it doesn’t put it on the path,
|
||
so our <code>hello-again</code> script won’t be able to find it.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>There are various ways to deal with this problem.
|
||
In this case we simply edited the script (lines 34-36) as we install it,
|
||
by specifying the full path to <code>hello-nix</code>.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>When you’re packaging a program written in a more powerful language such as
|
||
Haskell, Python, Java, C, C#, or Rust,
|
||
the language build system will usually do all that is required
|
||
to make the dependencies visible to the program at runtime.
|
||
In that case, adding the dependency to <code>buildInputs</code> is sufficient.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the flake.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run
|
||
I'm a flake, but I'm running a command defined in a non-flake package.
|
||
Hello from your nix package!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_an_old_style_nix_shell_with_access_to_a_flake">10.6. An (old-style) Nix shell with access to a flake</h3>
|
||
<div class="paragraph">
|
||
<p>If you are maintaining legacy code,
|
||
you may need to provide access to a flake in a <code>nix-shell</code>.
|
||
Here’s how.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">shell.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-k">with</span> <span class="tok-p">(</span><span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{});</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">hello-flake</span> <span class="tok-o">=</span> <span class="tok-p">(</span> <span class="tok-nb">builtins</span><span class="tok-o">.</span>getFlake
|
||
<span class="tok-l">git+https://codeberg.org/mhwombat/hello-flake?ref=main&rev=3aa43dbe7be878dde7b2bdcbe992fe1705da3150</span>
|
||
<span class="tok-p">)</span><span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-si">${</span><span class="tok-nb">builtins</span><span class="tok-o">.</span>currentSystem<span class="tok-si">}</span><span class="tok-o">.</span>default<span class="tok-p">;</span>
|
||
<span class="tok-k">in</span>
|
||
mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">buildInputs</span> <span class="tok-o">=</span> <span class="tok-p">[</span>
|
||
hello-flake
|
||
<span class="tok-p">];</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the shell.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell
|
||
$ hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="footer">
|
||
<div id="footer-text">
|
||
Last updated 2025-10-14 11:02:03 IST
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html> |