├── .envrc ├── .github └── workflows │ ├── main.yml │ └── pull_request.yml ├── .gitignore ├── LICENSE ├── README.md ├── book.toml ├── flake.lock ├── flake.nix ├── nix ├── book.nix └── overlay.nix └── src ├── SUMMARY.md ├── ch00-00-the-nix-package-manager.md ├── ch01-00-preface.md ├── ch02-00-introduction.md ├── ch03-00-getting-started.md ├── ch03-00-installation.md ├── ch04-00-derivations.md ├── ch04-01-create-a-derivation.md ├── ch04-02-realise-a-derivation.md ├── ch04-03-using-derivations-from-nix.md ├── ch05-00-the-nix-language.md ├── ch05-01-language-basics.md ├── ch05-02-functions.md ├── ch05-03-imports-and-callpackage.md ├── ch05-04-best-practices.md ├── ch05-05-common-mistakes.md ├── ch06-00-building-a-nix-package.md ├── ch06-01-simple-c-program.md ├── ch06-02-simple-c-program.md ├── ch06-02-stdenv.md ├── ch06-03-phases.md ├── ch06-04-build-dependencies.md ├── ch06-05-runtime-dependencies.md ├── ch06-06-building-packages-for-other-toolchains.md ├── ch06-07-building-packages-for-other-languages.md ├── ch06-08-patching.md ├── ch06-09-multiple-outputs.md ├── chXY-AA-shellhooks.md └── chXZ-AB-multi-output-derivations.md /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | name: CI on main 3 | 4 | on: 5 | push: 6 | branches: [ main ] 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout 🛎️ 14 | uses: actions/checkout@v2 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly. 15 | with: 16 | persist-credentials: false 17 | 18 | - name: Install Nix 19 | uses: cachix/install-nix-action@v13 20 | with: 21 | nix_path: nixpkgs=channel:nixos-21.05 22 | 23 | - name: Build book 24 | run: | 25 | nix-env -iA mdbook -f '' 26 | mdbook build 27 | - name: Deploy 🚀 28 | uses: JamesIves/github-pages-deploy-action@releases/v3 29 | with: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | BRANCH: gh-pages # The branch the action should deploy to. 32 | FOLDER: book # The folder the action should deploy. 33 | CLEAN: true # Automatically remove deleted files from the deploy branch 34 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request CI 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Checkout 🛎️ 12 | uses: actions/checkout@v2 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly. 13 | with: 14 | persist-credentials: false 15 | 16 | - name: Install Nix 17 | uses: cachix/install-nix-action@v13 18 | with: 19 | nix_path: nixpkgs=channel:nixos-unstable 20 | 21 | - name: Build book 22 | run: | 23 | nix-shell '' -p mdbook --command 'mdbook build' 24 | 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | result* 2 | .direnv/ 3 | 4 | # This is the output directory of mdbook 5 | book 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nix-book 2 | The Nix Package Manager 3 | 4 | Rendered book can be found at https://book.divnix.com/ 5 | 6 | This book is heavily inspired by the [rust-lang/book](https://doc.rust-lang.org/stable/book/) and serves to provide new Nix users a quick introduction to fundamental Nix concepts. 7 | 8 | It's recommended to use this resource as a precursor to [nix-pills](https://nixos.org/guides/nix-pills/) which is much more in-depth on details, but a much longer read. 9 | 10 | ## Contributing 11 | 12 | For a dev environment with `mdbook` on your shell: 13 | 14 | Use `nix develop` or `direnv allow` 15 | 16 | Run `mdbook serve` to launch a local webserver hosting the contents 17 | 18 | Run `mdbook build` to build nix-book. 19 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["jonringer", "nrdxp"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "Nix-Book" 7 | 8 | [output.html] 9 | git-repository-url = "https://github.com/divnix/nix-book" 10 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1628320020, 6 | "narHash": "sha256-4xBEb+TOHyIGpK37EVsZx6dGPwNMf5YWNBJaQ4VyZws=", 7 | "owner": "nixos", 8 | "repo": "nixpkgs", 9 | "rev": "67c80531be622641b5b2ccc3a7aff355cb02476b", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "nixos", 14 | "ref": "nixpkgs-unstable", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "root": { 20 | "inputs": { 21 | "nixpkgs": "nixpkgs", 22 | "utils": "utils" 23 | } 24 | }, 25 | "utils": { 26 | "locked": { 27 | "lastModified": 1623875721, 28 | "narHash": "sha256-A8BU7bjS5GirpAUv4QA+QnJ4CceLHkcXdRp4xITDB0s=", 29 | "owner": "numtide", 30 | "repo": "flake-utils", 31 | "rev": "f7e004a55b120c02ecb6219596820fcd32ca8772", 32 | "type": "github" 33 | }, 34 | "original": { 35 | "owner": "numtide", 36 | "repo": "flake-utils", 37 | "type": "github" 38 | } 39 | } 40 | }, 41 | "root": "root", 42 | "version": 7 43 | } 44 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Nix-Book: The Nix Package Manager"; 3 | 4 | inputs = { 5 | utils.url = "github:numtide/flake-utils"; 6 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 7 | }; 8 | 9 | outputs = { self, nixpkgs, utils }: 10 | let 11 | systems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin"]; 12 | localOverlay = import ./nix/overlay.nix; 13 | forSystem = system: rec { 14 | legacyPackages = import nixpkgs { 15 | inherit system; 16 | overlays = [localOverlay]; 17 | }; 18 | packages = utils.lib.flattenTree { 19 | inherit (legacyPackages) devShell nix-book; 20 | }; 21 | defaultPackage = packages.nix-book; 22 | apps.nix-book = utils.lib.mkApp {drv = packages.nix-book;}; 23 | hydraJobs = {inherit (legacyPackages) nix-book;}; 24 | checks = {inherit (legacyPackages) nix-book;}; 25 | }; 26 | in 27 | utils.lib.eachSystem systems forSystem // { overlay = localOverlay; }; 28 | } 29 | -------------------------------------------------------------------------------- /nix/book.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , nix-gitignore 3 | , mdbook 4 | }: 5 | 6 | let 7 | additionalFilters = [ "*.nix" "nix/" "build/" ]; 8 | filterSource = nix-gitignore.gitignoreSource additionalFilters; 9 | cleanedSource = filterSource ../.; 10 | in stdenv.mkDerivation { 11 | pname = "nix-book"; 12 | version = "0.0.1"; 13 | 14 | src = cleanedSource; 15 | 16 | nativeBuildInputs = [ mdbook ]; 17 | 18 | buildPhase = "mdbook build"; 19 | 20 | installPhase = '' 21 | mkdir $out 22 | cp -r book/* $out 23 | ''; 24 | } 25 | -------------------------------------------------------------------------------- /nix/overlay.nix: -------------------------------------------------------------------------------- 1 | final: prev: { 2 | nix-book = prev.callPackage ./book.nix { }; 3 | 4 | devShell = final.nix-book; 5 | } 6 | -------------------------------------------------------------------------------- /src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [The Nix Package Manager](./ch00-00-the-nix-package-manager.md) 4 | 5 | [Preface](./ch01-00-preface.md) 6 | 7 | [Introduction](./ch02-00-introduction.md) 8 | 9 | - [Installation](./ch03-00-installation.md) 10 | 11 | - [Derivations](./ch04-00-derivations.md) 12 | - [Create a Derivation](./ch04-01-create-a-derivation.md) 13 | - [Realise a Derivation](./ch04-02-realise-a-derivation.md) 14 | - [Using Derivations from Nix](./ch04-03-using-derivations-from-nix.md) 15 | 16 | - [The Nix Language](./ch05-00-the-nix-language.md) 17 | - [Language Basics](./ch05-01-language-basics.md) 18 | - [Functions](./ch05-02-functions.md) 19 | - [Imports and callPackage](./ch05-03-imports-and-callpackage.md) 20 | - [Best Practices](./ch05-04-best-practices.md) 21 | - [Common Mistakes](./ch05-05-common-mistakes.md) 22 | 23 | - [Building a Nix Package](./ch06-00-building-a-nix-package.md) 24 | - [Simple C program](./ch06-01-simple-c-program.md) 25 | - [Stdenv](./ch06-02-stdenv.md) 26 | - [Phases](./ch06-03-phases.md) 27 | - [Build Dependencies](./ch06-04-build-dependencies.md) 28 | - [Runtime Dependencies](./ch06-05-runtime-dependencies.md) 29 | - [Building Packages for Other Toolchains](./ch06-06-building-packages-for-other-toolchains.md) 30 | - [Building Packages for Other Languages](./ch06-07-building-packages-for-other-languages.md) 31 | - [Patching](./ch06-08-patching.md) 32 | - [Multiple Outputs](./ch06-09-multiple-outputs.md) 33 | -------------------------------------------------------------------------------- /src/ch00-00-the-nix-package-manager.md: -------------------------------------------------------------------------------- 1 | # The Nix Package Manager 2 | 3 | *by Jonathan Ringer and Tim Deherra* 4 | 5 | This book assumes usage of the nix 3.0 cli. 6 | 7 | This can be enabled in nix 2.4 by [following these instructions](https://nixos.wiki/wiki/Flakes#Enable_flakes). 8 | 9 | This book is available on the web at [https://book.divnix.com/](https://book.divnix.com/). 10 | 11 | For changes to the book, please see the [https://github.com/divnix/nix-book](https://github.com/divnix/nix-book). 12 | -------------------------------------------------------------------------------- /src/ch01-00-preface.md: -------------------------------------------------------------------------------- 1 | # Preface 2 | 3 | My journey to learn Nix was only made possible by my extreme desire to master it. 4 | The path was anything but easy and predictable. And it is still a considerable 5 | hurdle for many who try to learn Nix. 6 | 7 | The goal of this book is to provide newcomers with a more approachable 8 | document than the [nix-pills series](https://nixos.org/guides/nix-pills). 9 | Although nix-pills is a very good resource 10 | with many years of refinement, it is extensive and hard to follow without 11 | some prior knowledge of Nix. This book hopes to 12 | provide a more recent account of Nix with more of a focus on giving the user 13 | intuition around what Nix is doing rather than a deep understanding like nix-pills. 14 | 15 | The motivation for writing this is to provide a "Nix equivalent of the [rust-lang book](https://doc.rust-lang.org/book/)": 16 | one resource that can be read end-to-end in an afternoon that is able to equip the reader with the 17 | knowledge necessary to thrive in the Nix ecosystem. The goal is not to replace any existing Nix 18 | guides or documentation, but rather provide a good starting place for new users. 19 | 20 |
– Jonathan Ringer
21 | -------------------------------------------------------------------------------- /src/ch02-00-introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | # The Nix Package Manager 4 | 5 | Nix is a package manager that focuses on 6 | capturing all inputs which contribute to building software. 7 | The result of factoring all of the information about building 8 | the software is called a *derivation*. This information includes from where 9 | the source code is downloaded, configuration flags, patches, 10 | dependencies, build steps, installation steps, and many other potential inputs. 11 | 12 | This information is hashed, which allows Nix to 13 | describe and reference the exact software which is intended to use. 14 | This enables Nix to be used on any system because its assumptions 15 | do not collide with the assumptions of a host system. This means that 16 | Nix does not adhere to the traditional [File Hierarchical System (FHS)][fhs] 17 | but it also means that it's not limited to FHS's restriction of only having 18 | a single variant of a piece of software: You can have multiple versions of 19 | the same software installed, or the same version installed twice compiled with 20 | two different set of compile flags without conflict. 21 | 22 | [fhs]: https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard 23 | 24 | # Who is Nix For 25 | 26 | ## Teams of Developers 27 | 28 | Each developer on a team needs access to the same development environment. 29 | 30 | Development environments need to reflect the build and production environments. 31 | 32 | When these diverge, software may fail to build or run properly after a software delivery was made. 33 | Having divergent development, build and production environments is a major cause of regressions 34 | in software development. Nix can help mitigate this by allowing environments to be version 35 | controlled and maintained along with a project. Nix can also lower the onboarding time of new 36 | developers by automating installation instructions. 37 | 38 | ## DevOps 39 | 40 | Nix allows you to precisely describe the software you intend to use. Nix packages 41 | are defined by their dependencies, so they inherently retain their SBOM (Software Bill of Materials) 42 | by default. By leveraging NixOS modules, one can also create configurable services and compose 43 | them into coherent systems. The combination of Nix + NixOS allows you to have declarative configuration 44 | of both services and systems of multiple machines and architectures. 45 | 46 | ## System Administrators (home to enterprise) 47 | 48 | Nix allows you to maintain dozens to hundreds of systems: Placing a system's configuration as code 49 | in version control enables a new paradigm of system configuration management. Atomically apply or 50 | rollback system updates for each system. Nixpkgs can be freely extended to include private additions 51 | to software. 52 | 53 | Nix largely replaces the need for Docker. However, Nix can also be used to produce Docker images 54 | if there is a downstream technology which consumes OCI images as an interface (e.g. Kubernetes). 55 | 56 | ## Power Users 57 | 58 | Nix allows for incredibly specific or opinionated environments. Nix allows you to declare projects 59 | (flakes), user directory configuration ([home-manager][hm]), or system environments (NixOS) with the exact 60 | same software. Whether you're a software developer, or you're tweaking the appearance of your desktop 61 | system, Nix will allow you to control and specify configuration exactly as you intend, and persist 62 | this across multiple machines. 63 | 64 | [hm]: https://github.com/nix-community/home-manager 65 | 66 | # The Nix Ecosystem 67 | 68 | There's roughly four layers of abstractions in the official Nix ecosystem, these are: 69 | 70 | - Nix - The domain-specifc language used to write Nix expressions 71 | - Nix - The package manager 72 | - Nixpkgs - The official Nix package repository 73 | - NixOS - A Linux distribution built on Nixpkgs 74 | 75 | There are also a several unofficial projects commonly used within the community. Some of these are: 76 | 77 | - [home-manager][hm] - NixOS-like user configuration for Linux or MacOS built on Nixpkgs 78 | - [Nix-darwin](https://github.com/LnL7/nix-darwin) - NixOS-like configuration, but for MacOS 79 | 80 | These topics will be discussed in greater detail in later sections, but a 81 | quick summary of official projects are provided below. 82 | 83 | ## Nix: The Language 84 | 85 | The Nix language is a Domain-Specific Language (DSL) which is designed to 86 | handle package configuration. Nix can be thought of [JSON](https://en.wikipedia.org/wiki/JSON) + 87 | functions + imports + some syntax sugar. Its main goal is to provide *effect-free evaluation* of 88 | package configuration. For that reason, Nix is restricted in many ways and lacks 89 | many features from generic programming languages. There is very limited input and 90 | output possible to the system, there are no loops, no concurrency primitives, and 91 | no types. What is left is a small functional programming language. After all, 92 | Nix's goal is to take a few inputs such as a system platform, and produce a build 93 | graph which can be used as a recipe to build software. 94 | 95 | ## Nix: The Package Manager 96 | 97 | The Nix Package Manager began its life as the [PhD thesis work](https://edolstra.github.io/pubs/phd-thesis.pdf) 98 | of Eelco Dolstra. The goal was to bring discipline to the software landscape. Similar to 99 | how structured programming helped tame the complexity of goto through introducing constructs such 100 | as loops and logic flow; so too does Nix attempt to tame the chaos of package management 101 | through explicit descriptions of software and their dependencies. The truly novel idea 102 | of Nix is that of the *derivation*. It encapsulates everything about a piece of software, 103 | and these derivations can be referenced from other derivations constituting a *directed, acyclic 104 | graph* (DAG) of how to built that software from source. 105 | 106 | ## Nixpkgs: The Package Repository 107 | 108 | Nixpkgs is the official package repository for the Nix community. It contains the logic 109 | on how to build over 60,000+ software packages. Nixpkgs can be thought of as an 110 | expert body-of-knowledge on the subject of how to build software. When a user 111 | asks for the "firefox" package, the Nix package manager is able to query Nixpkgs 112 | and produce a build graph on how to build Firefox and all of its dependencies down 113 | to the C compiler, for that user's platform. 114 | This allows for a great deal of freedom: Nix can be used on any Linux distribution and MacOS as 115 | first class supported OS'es, and to a lesser degree on many other UNIX-like OS'es. 116 | 117 | Nixpkgs is also supported by [Hydra](https://hydra.nixos.org/), which provides 118 | pre-built binaries of libre software for Linux and MacOS. 119 | 120 | ## NixOS: The Operating System 121 | 122 | NixOS is a [non-FHS][fhs] Linux distribution which leverages Nixpkgs to provide a wealth 123 | of software ready to be combined into a system environment. The concept of a Nix 124 | derivation is extended here to include service configuration and system creation. 125 | The entirety of the system is represented as a derivation which gives it many of 126 | its defining qualities such as atomic rollbacks, system-as-a-configuration-file, and 127 | extensive user configuration potential. 128 | -------------------------------------------------------------------------------- /src/ch03-00-getting-started.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/divnix/nix-book/e20150b5e4c613fddff125097dbea0cecbd64999/src/ch03-00-getting-started.md -------------------------------------------------------------------------------- /src/ch03-00-installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Linux and MacOS 4 | 5 | The guided installer is the preferred way to install nix, please run the following in a shell: 6 | ``` 7 | sh <(curl -L https://nixos.org/nix/install) --daemon 8 | ``` 9 | 10 | ## Other Installation Methods 11 | 12 | There are many ways to leverage nix, for more installation options, please visit 13 | the [official download page](https://nixos.org/download.html). 14 | 15 | -------------------------------------------------------------------------------- /src/ch04-00-derivations.md: -------------------------------------------------------------------------------- 1 | # Derivations 2 | 3 | Derivations are the defining feature of nix. Derivations attempt to capture everything 4 | that it would take to build a package. This includes, but is not limited to: source code, 5 | dependencies, build flags, build and installation steps, tests, and environment variables. 6 | The culmination of all direct and transitive build depdencies 7 | is commonly refered to as the derivations's "build closure". More dependencies that a 8 | package refers to, more package will need to be created in order to attempt a 9 | build. Generally, dependencies of a derivation are other derivations. 10 | 11 | ## Types of Derivations 12 | 13 | ### Fixed Output Derivations (FODs) 14 | 15 | These are the "leaves" of any build closure, in that, they do not refer to other 16 | derivations. These derivations are defined by 17 | their content. These derivations are easily differientiated because they 18 | will contain a sha256 (or other hash) which is used to enforce that an artifact 19 | is reproducible. 20 | 21 | One critical difference from evaluated derivations is that Fixed-Output derivations 22 | are able to have access to the network while fetching contents. This "impurity" 23 | is offset by enforcing that the hash matches, and reproducibility is delegated to 24 | the process which fetchs the assets. 25 | 26 | Many of the `fetch*` utilities in nixpkgs and nix's builtins will create FODs. 27 | 28 | ### Input-Addressed Derivations 29 | 30 | Input-Addressed derivations are generally what are referred to when the term derivation is used. These 31 | derivations are defined by all of the dependencies, build phases, and flags 32 | present during a build. Nix captures all of the variables which constitute a 33 | derivation and uses a cryptographic hash to give each derivation a unique name. 34 | 35 | `stdenv.mkDerivation` and related `build*` helpers will create an input-addressed derivation. 36 | 37 | ### Content-Addressable Derivations (CA Derivations) 38 | 39 | **NOTE**: CA Derivations are still considered experimental at the time of writing 40 | 41 | Content-Addressable (CA) derivations are a hybrid of both FOD and IA derivations. 42 | The problem which CA derivations address are rebuilds. In the IA derivation model, a patch 43 | to openssl will cause all downstream packages to rebuild since that derivation will 44 | propagate the patch change across all consumers. Under CA derivations, nix can determine 45 | that a consuming package which was built before the openssl patch has remained unchanged 46 | with the only exception being where openssl is located in the nix store. In this case 47 | the package which uses openssl is "the same" in usage, the only thing which has changed is what 48 | variant of openssl it uses. Nix is then free to assert an equivalence of the 49 | package before and after the openssl patch; thus, it doesn't need to rebuild all packages, 50 | just update the references of openssl. 51 | 52 | The name Content-Addressable comes from the fact that the implementation will stub out nix store 53 | paths and use this normalized content to compare against other builds. Now nix can deduplicate 54 | builds which were done previously. In the openssl example, the build of curl will likely be 55 | exactly the same; thus any package which just consumes curl will not have to be rebuilt. Only 56 | the references to the new variant of curl needs to be updated. 57 | 58 | CA derivations are an opt-in experimental feature, but don't require the user to alter their 59 | existing workflows. 60 | -------------------------------------------------------------------------------- /src/ch04-01-create-a-derivation.md: -------------------------------------------------------------------------------- 1 | # Create a Derivation 2 | 3 | Before a package is built, a derivation must be created. The derivation can 4 | be thought of as the unamiguous definition of how to build a package. 5 | The process of creating a derivation is called "instantiatiation", 6 | or sometimes also refered to as evaluation (although this is more general). Every package in 7 | nixpkgs has a corresponding derivation. This means that we can 8 | create and inspect the derivation for anything exposed in nixpkgs. An example 9 | would be: 10 | 11 | ``` 12 | $ nix-instantiate '' -A hello 13 | /nix/store/byqskk0549v1zz1b2a61lb7llfn4h5bw-hello-2.10.drv 14 | 15 | # or using flakes, nix>=2.4 16 | 17 | $ nix eval nixpkgs#hello.drvPath 18 | "/nix/store/byqskk0549v1zz1b2a61lb7llfn4h5bw-hello-2.10.drv" 19 | ``` 20 | 21 | ## Inspect the contents of a derivation 22 | 23 | To inspect the contents of the drv, one can use the `nix show-derivation` utility. 24 | 25 | ``` 26 | $ nix show-derivation /nix/store/byqskk0549v1zz1b2a61lb7llfn4h5bw-hello-2.10.drv 27 | { 28 | "/nix/store/byqskk0549v1zz1b2a61lb7llfn4h5bw-hello-2.10.drv": { 29 | "outputs": { 30 | "out": { 31 | "path": "/nix/store/f4bywv8hjwl0ckv7l077pnap81h6qxw4-hello-2.10" 32 | } 33 | ... 34 | ``` 35 | 36 | ## Defining characteristics of a derivation 37 | 38 | There's a few important features of a derivation: 39 | - It's a description of how to build the package from source 40 | - The output paths are determined before the build begins 41 | - All dependencies are resolved as part of instantiation, and may have a similar derivation description of their builds 42 | - Any additional flags (makeFlags, configuration flags, cflags, or ld flags) are explicitly stated 43 | - There's no ambiguity. The system, architecture, and other options have been resolved. 44 | - It's immutable. If you want to change a derivation, you need to evaluate a new one. 45 | - It's unique. The hashing scheme ensures that there should only ever be one derivation; if two derivations match, then they are exactly the same in every way. 46 | -------------------------------------------------------------------------------- /src/ch04-02-realise-a-derivation.md: -------------------------------------------------------------------------------- 1 | # Realise a derivation 2 | 3 | Building a derivation is referred to as "realisation". A derivation is just an abstract 4 | description of a package, based upon what it requires to build. Derivations can be thought 5 | of as constructing a blueprint, but realisation is the construction of the desired object. 6 | Taking from the previous example, one can build a derivations like so: 7 | 8 | ``` 9 | $ nix-store --realise /nix/store/byqskk0549v1zz1b2a61lb7llfn4h5bw-hello-2.10.drv 10 | ... 11 | /nix/store/f4bywv8hjwl0ckv7l077pnap81h6qxw4-hello-2.10 12 | 13 | # or in nix flakes: 14 | 15 | $ nix build nixpkgs#hello 16 | ... 17 | /nix/store/f4bywv8hjwl0ckv7l077pnap81h6qxw4-hello-2.10 18 | ``` 19 | 20 | Here, the gnu hello project was built and installed at the output path. This 21 | includes: the executable binary, documenation, and locale info. 22 | 23 | ``` 24 | $ tree -L 2 /nix/store/f4bywv8hjwl0ckv7l077pnap81h6qxw4-hello-2.10 25 | /nix/store/f4bywv8hjwl0ckv7l077pnap81h6qxw4-hello-2.10 26 | ├── bin 27 | │   └── hello 28 | └── share 29 | ├── info 30 | ├── locale 31 | └── man 32 | ``` 33 | 34 | The `nix-build` and `nix build` commands will perform both instantiation and realisation. 35 | These are the most common commands used when iterating on packages. One could also do: 36 | 37 | ``` 38 | $ nix-build '' -A hello 39 | # these are the same, nix build is just much more concise 40 | $ nix-store --realise $(nix-instantiate '' -A hello) 41 | ``` 42 | 43 | *Note:* Many other commands also will realise a derivation 44 | as part of a workflow. Some examples are: 45 | `nix-shell`, `nix shell`, `nix-env`, `nix run`, and `nix profile`. 46 | These commands are very goal oriented and will differ 47 | significantly in how they leverage nix, often realisation 48 | is an side-effect to achieve that goal. 49 | -------------------------------------------------------------------------------- /src/ch04-03-using-derivations-from-nix.md: -------------------------------------------------------------------------------- 1 | # Using Derivations from Nix 2 | 3 | The derivation is the main abstraction of nix. All of 4 | Nixpkgs and NixOS is created by leveraging derivations 5 | to create new derivations, scripts, services, and even 6 | entire linux distributions. The ability to compose these 7 | usecases with uniquely named packages allows nix the 8 | freedom to aggressively share common dependencies, meanwhile 9 | allowing the flexibility to have potentially incompatible 10 | packages available on the system. 11 | 12 | The nix language allows for consumption of derivations 13 | to be quite transparent. For example: 14 | 15 | ``` 16 | $ cat hello.nix 17 | let 18 | pkgs = import { }; 19 | in 20 | pkgs.writeScriptBin "greet.sh" '' 21 | ${pkgs.hello}/bin/hello -g "Hello $USER!" 22 | '' 23 | 24 | $ nix-build hello.nix 25 | this derivation will be built: 26 | /nix/store/xd9qpwnvybm9p8k2szhkvpd2ym85is9p-greet.sh.drv 27 | building '/nix/store/xd9qpwnvybm9p8k2szhkvpd2ym85is9p-greet.sh.drv'... 28 | /nix/store/h8yxaciazc8basn9l335bmdrpfak0aqk-greet.sh 29 | 30 | $ cat ./result/bin/greet.sh 31 | /nix/store/mg35qkhk7wqbhhykpakds4fsm1riy8ga-hello-2.12.1/bin/hello -g "Hello $USER!" 32 | 33 | $ ./result/bin/greet.sh 34 | Hello jon! 35 | ``` 36 | 37 | We created a `greet.sh` script which will greet the user. 38 | Nix first created the "derivation" (build plan) of our script at 39 | `/nix/store/-greet.sh.drv`, and then realised (built) the derivation as 40 | `/nix/store/-greet.sh`. 41 | We can see from the contents of the resulting file that 42 | `pkgs.hello` was substituted for the realised output path. 43 | This allows for us to not worry about what the unique name 44 | of the derivation will be, but rather worry about the 45 | contents post realisation. 46 | 47 | Although this may not seem markedly better than other package 48 | management workflows such as: please install these tools, then run 49 | this script. There is quite a lot of benefit to leveraging nix whether 50 | it's to create scripts or build more software: 51 | - Use of exact versions which you control 52 | - For example, which version of python or node do you have? 53 | - No longer dependent on the state of the consuming system 54 | - For example, do you have python installed? 55 | - Use of multiple versions of the same software 56 | - Want to use NodeJS v14 in one script, but NodeJS v16 in another? No problem. 57 | 58 | Although many ecosystems will have ecosystem specific solutions to these solutions 59 | (e.g. tox for python, nvm for node), nix provides a universal abstraction for 60 | native dependencies and any downstream dependencies. 61 | 62 | ### Use of "outPath" as a toString 63 | 64 | This is one of the oddities of nix, but stringification of 65 | an object which contains a key "outPath" will return 66 | the contents of the "outPath" key. Since all derivations 67 | will have an outPath, any usage of them in a string 68 | will yeild the store path that they create. 69 | 70 | ```nix 71 | nix-repl> a = { outPath = "foo"; } 72 | 73 | nix-repl> "${a} bar" 74 | "foo bar" 75 | ``` 76 | -------------------------------------------------------------------------------- /src/ch05-00-the-nix-language.md: -------------------------------------------------------------------------------- 1 | # The Nix Language 2 | 3 | Nix is a pure, lazy, functional language which serves a domain-specific language (DSL) 4 | for writing nix derivations and expressions. In general, nix can be thought of as 5 | JSON with functions. 6 | 7 | The goal of Nix is to facilitate the creation of a derivation. In most situations 8 | nix is given a small amount input and expected to produce a result (usually a derivation). 9 | In the case of nixpkgs, the workflow is generally, "given the user has an x86_64-linux 10 | device and the information held within nixpkgs then the desired package will be 11 | `/nix/store/-`. This is also why the word evaluation is used commonly 12 | when refering to nix packages, the nix expression which describes how to build 13 | software can evaluate to it's final reduced state given just a system platform. 14 | 15 | -------------------------------------------------------------------------------- /src/ch05-01-language-basics.md: -------------------------------------------------------------------------------- 1 | # Nix Language Basics 2 | 3 | ## Primitive Values 4 | 5 | These values are mostly similar to JSON: 6 | 7 | | Type | Description | Example 8 | |---|---|---| 9 | | integer | Whole number | 1 | 10 | | float | Floating point number | 1.054 | 11 | | string | UTF-8 string | "hello!" | 12 | | path | File or url | ./default.nix | 13 | 14 | *NOTE*: Paths are special. They will be resolved relative to the file. 15 | The value must contain a "/" to be considered a path, however, 16 | it's common to construct the value starting with "." to avoid confusion 17 | (e.g. ./foo/bar vs foo/bar). 18 | If a path is referenced as part of a package, that path will be added to the 19 | nix store, and all references to that path will be substituted with the nix store path. 20 | 21 | ## Strings 22 | 23 | Nix exposes two ways to express strings. Strings are enclosed with double quotes: `"hello"`. 24 | This works well for small strings, such as simple flags. However, it's common to write a 25 | block of commands which need to be executed; for this, nix also has multi-line support with 26 | the "lines" construct. "lines" are denoted by two single quotes. 27 | 28 | Example usage of lines: 29 | ``` 30 | postPatch = '' 31 | ./autogen.sh 32 | mkdir build 33 | cd build 34 | ''; 35 | ``` 36 | 37 | Here, we have postPatch being assigned a series of commands to be ran as part of a build. 38 | 39 | Another quality of lines, is that all shared leading whitespace will be truncated. 40 | This allows for the the lines blocks to be adjusted to the indention of the parent nix expression 41 | without influencing the contents of the string. 42 | 43 | ``` 44 | $ cat lines.nix 45 | '' 46 | 2 spaces 47 | 3 spaces 48 | 4 spaces 49 | '' 50 | $ nix eval -f lines.nix 51 | "2 spaces\n 3 spaces\n 4 spaces\n" 52 | ``` 53 | 54 | ## Lists 55 | 56 | Lists work similarly to most other languages, but are whitespace delimited. `[ 1 2 ]` is an 57 | array with elements `1` and `2`. 58 | 59 | **Note**: For oddities around lists and elements which use whitespace, please see [list common mistakes](./ch05-05-common-mistakes.html#lists). 60 | 61 | ## Attribute Set (Attr set) 62 | 63 | This can be thought of as a dictionary or map in most other languages. The important distinct is that the 64 | keys are always ordered, so that the order doesn't influence how a derivation will produce a hash. Attr sets 65 | values do not need to be of the same type. Attr sets are constructed using an `=` sign which denotes key value 66 | pairs which are separated with semicolons `;`, the attr set is enclosed with curly braces `{ }`. Selection 67 | of an attribute is done through dot-notation `.`. 68 | 69 | ``` 70 | nix-repl> a = { foo = "bar"; count = 5; flags = ''-g -O3''; } 71 | nix-repl> a.count 72 | 5 73 | 74 | # Shorthand for nested attribute sets 75 | nix-repl> :p { foo.bar.baz = 1; foo.bar.buzz = 2; } 76 | { foo = { bar = { baz = 1; buzz = 2; }; }; } 77 | ``` 78 | 79 | You will commonly see empty attr sets in nixpkgs, an example being: 80 | ``` 81 | hello = callPackage ../applications/misc/hello { }; 82 | ``` 83 | 84 | ## Derivations 85 | 86 | Technically, a derivation is just an attr set which has a few special attributes 87 | set to valid values which then nix can later realise into a build. Promotion 88 | from an attr set to derivation is facilitated through the `builtins.derivation` 89 | function. However directly calling the builtin is highly discouraged within 90 | nixpkgs. Instead people are encouraged to use stdenv.mkDerivation and other 91 | established builders which provide many good defaults to achieve their packaging goals. 92 | 93 | ## If / Else logic 94 | 95 | Like many other functional programming languages, you cannot 96 | use `if` without an accompanying `else` clause. This is because 97 | the expression needs to return a value, not just follow a code 98 | path. 99 | 100 | ``` 101 | extension = if stdenv.isDarwin then 102 | ".dylib" 103 | else 104 | ".so"; 105 | ``` 106 | 107 | **Note**: The proper way to find the shared library extension 108 | within nixpkgs is `hostPlatform.extensions.sharedLibrary`. 109 | 110 | ## Let expressions 111 | 112 | Let expressions are a way to define values to be used later in a given 'in' scope. 113 | Generally these are used to alter a given value to conform to a 114 | slightly different format. Let expressions can refer 115 | to other values defined in the same let scope. For haskell users, 116 | let expressions work similarly to how they work in Haskell. 117 | 118 | ``` 119 | src = let 120 | # e.g. 3.1-2 -> 3_1_2 121 | srcVersion = lib.strings.replaceStrings [ "." "-" ] [ "_" "_"] version; 122 | srcUrl = "https://example.com/download/${pname}-${srcVersion}.tar.gz"; 123 | in fetchurl { 124 | url = srcUrl; 125 | sha256 = "..."; 126 | }; 127 | ``` 128 | 129 | ## With expressions 130 | 131 | With expressions allows for many values on an attr set to be 132 | exposed by their key names. 133 | 134 | ``` 135 | # before 136 | meta = { 137 | licenses = lib.licenses.cc0; 138 | maintainers = [ lib.maintainers.jane lib.maintainers.joe ]; 139 | platforms = lib.platforms.unix; 140 | }; 141 | ``` 142 | 143 | ``` 144 | # after 145 | meta = with lib; { 146 | licenses = licenses.cc0; 147 | maintainers = with maintainers; [ jane joe ]; 148 | platforms = platforms.unix; 149 | }; 150 | ``` 151 | 152 | ## Laziness 153 | 154 | Many pure functional programming languages also have the feature that the 155 | evaluation model of the language is lazy. This means that the values 156 | of a data structure aren't computed until needed. 157 | The benefits for nix is that evaluating a package doesn't mean computing 158 | all packages, but only computing the dependency graph for the packages 159 | requested. In practice this means limiting the scope of an action from 160 | 80,000+ possible dependencies to just the dependencies explicitly mentioned 161 | by the nix expressions. 162 | 163 | Although laziness isn't a hard requirement for nix to work. The purity 164 | model of nix makes laziness more a symptom rather than an explicit design goal. 165 | However, It does enable many implicit benefits such as [memoization](https://en.wikipedia.org/wiki/Memoization). 166 | 167 | -------------------------------------------------------------------------------- /src/ch05-02-functions.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | 3 | Nix only has unary functions: unary functions are functions which 4 | only accept one parameter. However, in combination with 5 | [uncurrying](https://en.wikipedia.org/wiki/currying), you can 6 | create functions which take an arbitrary number of parameters. 7 | 8 | Functions can be treated as values, and freely passed to other 9 | functions as such. To name a function, it just needs to be assigned 10 | to variable, much as you would do to a literal. 11 | 12 | Function examples: 13 | ``` 14 | # creation, and immediate application of a nameless function 15 | nix-repl> (x: x + 2) 3 16 | 5 17 | 18 | # assigning a function to a variable, then later applying it 19 | nix-repl> addTwo = x: x + 2 20 | 21 | nix-repl> addTwo 3 22 | 5 23 | 24 | # two parameters 25 | nix-repl> sumBoth = x: y: x + y 26 | 27 | nix-repl> sumBoth 2 5 28 | 7 29 | ``` 30 | 31 | ## Attr sets as inputs 32 | Nix also heavily uses attr sets to pass around many arguments. 33 | In nixpkgs, this is most commonly used to express what subset of 34 | packages and utilities should be used for a nix expression. It's 35 | also useful when a large context for a function is needed, and 36 | an ordered list of parameters is a poor fit. 37 | 38 | Attr sets as inputs are also particular good when the function 39 | can provide good defaults, and only a small subset of inputs are 40 | expected to be edited. 41 | 42 | Function examples: 43 | ```nix 44 | # function which takes an attr set 45 | nix-repl> addTwo = { x }: x + 2 46 | 47 | nix-repl> addTwo { x = 3; } 48 | 5 49 | 50 | # function which takes optional attr set values 51 | nix-repl> addTwoOptional = { x ? 4 }: x + 2 52 | 53 | nix-repl> addTwoOptional { } 54 | 6 55 | 56 | nix-repl> addTwoOptional { x = 5; } 57 | 7 58 | 59 | # same as above, but binding the entire attr set to another variable 60 | nix-repl> addTwoOptional = { x ? 4 }@args: args.x + 2 61 | 62 | nix-repl> addTwoOptional { x = 6; } 63 | 8 64 | ``` 65 | 66 | **Note**: The `@` syntax is not very common for most nix expressions. 67 | Its most common use case are "helpers", which only care about a 68 | subset of arguments, and will then call another function with some 69 | of the inputs pruned. A good example of this is the `pkgs.fetchFromGithub` 70 | fetcher; which will know how to translate owner, repo, rev, and 71 | other options into a call to `builtsin.fetchzip` or `builtins.fetchgit`. 72 | -------------------------------------------------------------------------------- /src/ch05-03-imports-and-callpackage.md: -------------------------------------------------------------------------------- 1 | # Imports and callPackage 2 | 3 | ## Import 4 | 5 | `import` is one of the few keywords in nix. It allows for a file to be read and evaluated. If a directory is passed to `import`, 6 | then it will assume `/default.nix` was the desired file. 7 | 8 | ``` 9 | $ cat data.nix 10 | { a = "foo"; b = "bar"; } 11 | 12 | nix-repl> :p import ./data.nix 13 | { a = "foo"; b = "bar"; } 14 | 15 | $ cat expression.nix 16 | 5+2 17 | 18 | nix-repl> :p import ./expression.nix 19 | 7 20 | ``` 21 | 22 | This still extends to functions: 23 | ``` 24 | $ cat function.nix 25 | { x, y }: x + y 26 | 27 | nix-repl> :p import ./function.nix { x = 2; y = 9; } 28 | 11 29 | ``` 30 | 31 | ### Imports for packages 32 | 33 | In nixpkgs, each package usually has a corresponding 34 | file associated with the packaging and related concerns of just that package. 35 | Early in nix's history, `import` was used to integrate the files with other expressions and allow for greater organization of code. 36 | However, the import model is quite explicit, and requires users 37 | to declare the dependencies twice. 38 | 39 | Below is an example expression for `openssl`: 40 | ``` 41 | # pkgs/libraries/openssl/default.nix 42 | { lib, stdenv, fetchurl, perl }: 43 | 44 | stdenv.mkDerivation { 45 | ... 46 | } 47 | ``` 48 | 49 | In the `import` paradigm, the calling site would look: 50 | ``` 51 | openssl = import ../libraries/openssl { 52 | inherit lib stdenv fetchurl perl; 53 | }; 54 | ``` 55 | 56 | Obviously this isn't ideal. The dependencies need to be referred to 57 | three times, once at the call site, as inputs to the expression, 58 | and then within the expression at the appropriate section. 59 | The tediousness of passing the values will be solved by `callPackage`. 60 | 61 | ## CallPackage 62 | 63 | `callPackage` is a function which will call a function with the 64 | appropriate dependencies. The package set will generally expose 65 | a `callPackage` function with the current package set already bound. 66 | 67 | A minimal callPackage implementation can be thought of as: 68 | ``` 69 | # /lib/customisation.nix 70 | # callPackageWith :: Attr Set -> (Attr Set -> drv) -> Attr Set -> drv 71 | callPackageWith = autoArgs: fn: args: 72 | # autoArgs - Attr set of "defaults", for nixpkgs this would be all top-level packages 73 | # fn - A nix expression which uses an attr set as in input. 74 | # args - Overrides to the defaults in autoArgs 75 | let 76 | # if a file is passed, import it 77 | f = if lib.isFunction fn then fn else import fn; 78 | 79 | # find what attrs are shared from expression and package set 80 | # then override the values by anything passed explicitly through args 81 | fargs = builtins.intersectAttrs (lib.functionArgs f) autoArgs // args; 82 | in 83 | f fargs; # With nix, creation of a derivation is just function application 84 | ``` 85 | 86 | Usage of `callPackage` would look something like this: 87 | ``` 88 | # /pkgs/top-level/all-packages.nix 89 | { lib, ... }: 90 | 91 | let 92 | self = with self; { 93 | ... 94 | 95 | callPackage = lib.callPackageWith self; 96 | 97 | openssl = callPackage ../libraries/openssl { }; 98 | }; 99 | in self 100 | ``` 101 | 102 | With `callPackage` we only need to explicitly pass an attr set 103 | if we need to override the default values that would have been 104 | present in the package set. 105 | 106 | In nixpkgs, `callPackage` has been extended to include helpful 107 | package hints, and thus the complexity has grown, but the 108 | underlying intuition has remained the same. 109 | 110 | In javascript, `callPackage` would be an example of a curried function, 111 | where there's an implicit package set bound to it. 112 | -------------------------------------------------------------------------------- /src/ch05-04-best-practices.md: -------------------------------------------------------------------------------- 1 | # Best Practices 2 | 3 | ## Avoid excessive `with` usage 4 | 5 | Although `with` can be useful in small scopes. Doing something such as 6 | `with pkgs;` is usually discouraged. This is most dramatic with `pkgs`, 7 | in which you will introduce 15,000+ variables into your namespace. Although 8 | you may be aware of what is coming from where when you first write the code, 9 | this implicit context is much harder to re-create each time the expression 10 | is visited in the future. This is compounded with multiple `with` expressions, 11 | as later `with`'s will shadow previously defined values. 12 | 13 | This is not to say that all usage of `with` is discouraged, it's often 14 | encouraged with certain tasks such as defining the `meta` section of 15 | a package; as most attributes of a meta section will be pulling from 16 | `lib`. So a `meta = with lib; { ... }` can dramatically reduce how 17 | many `lib.` need to be explicitly added. Also, it's very common for 18 | NixOS modules to use `with lib;` for the whole file as many of the 19 | module building blocks are exposed through `lib`. 20 | 21 | In general, `with` should be scoped as much as possible: 22 | ```nix 23 | # good 24 | stdenv.mkDerivation { 25 | ... 26 | buildInputs = [ openssl ] 27 | ++ (with xorg; [ libX11 libX11randar xinput ]); 28 | } 29 | 30 | # also good, just repetitive 31 | stdenv.mkDerivation { 32 | ... 33 | buildInputs = [ openssl xorg.libX11 xorg.libX11randar xorg.xinput ]; 34 | } 35 | 36 | # discouraged, now all of xorg is exposed everywhere 37 | with xorg; 38 | 39 | stdenv.mkDerivation { 40 | ... 41 | buildInputs = [ openssl libX11 libX11randar xinput ]; 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /src/ch05-05-common-mistakes.md: -------------------------------------------------------------------------------- 1 | # Common Mistakes 2 | 3 | ## Functions 4 | 5 | The space after `:` is required. Without a space, nix will 6 | parse the value as an url, and represent it as a string 7 | 8 | ``` 9 | nix-repl> :t x: x 10 | a function 11 | 12 | nix-repl> :t x:x 13 | a string 14 | ``` 15 | 16 | ## Lists 17 | 18 | Functions and lists use whitespace to do funcation application, 19 | however, list element delimination takes precedence over function application. 20 | 21 | For example, if someone were to try and use optional python 22 | integration on a package, they may write something like: 23 | ```nix 24 | extraPackages = [ 25 | somePackage.override { withPython = true; } 26 | ]; 27 | ``` 28 | 29 | In this example, it's an array of two elements, `somePackage.override` is a function, and the other element 30 | is an attr set. This is more accurately represented as: 31 | ```nix 32 | extraPackages = [ 33 | (somePackage.override) # type: Attr -> drv 34 | ({ withPython = true; }) # type: Attr 35 | ]; 36 | ``` 37 | 38 | The correct usage of this would be: 39 | ```nix 40 | extraPackages = [ 41 | (somePackage.override { withPython = true; }) # type: drv 42 | ]; 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /src/ch06-00-building-a-nix-package.md: -------------------------------------------------------------------------------- 1 | # Building a Nix Package 2 | 3 | Building a package for nix can range from trivial to near impossible. 4 | Generally the difference between the two experiences is 5 | determined by how many assumptions the build process makes. 6 | Toolchains which have strong integrity guarantees (e.g. lock files) 7 | , and allow for offline builds are generally more nix compatible. 8 | 9 | Nix is language and toolchain agnostic. Support for many 10 | toolchains have been added to nixpkgs, but the nix build 11 | environment is very constrained so many `2nix` tools have 12 | arisen to try and bridge the gap in expectations. 13 | -------------------------------------------------------------------------------- /src/ch06-01-simple-c-program.md: -------------------------------------------------------------------------------- 1 | # Simple C program 2 | 3 | Many fundamental unix tools are written in C, as it provides many 4 | benefits to system programmers. In this section we will cover 5 | how to compile and package a simple C application to demonstrate 6 | how the nix build process works. 7 | 8 | ## Impure build and install 9 | 10 | Given the example C program: 11 | ``` 12 | $ cat simple.c 13 | #include 14 | 15 | void main() { 16 | printf("Hello from Nix!"); 17 | } 18 | ``` 19 | 20 | The build and installation of which on a traditional FHS 21 | system may look like: 22 | ``` 23 | # build 24 | $ gcc simple.c -o hello_nix 25 | # install 26 | $ sudo cp hello_nix /usr/bin/hello_nix 27 | ``` 28 | However, let's see how this would be done in nix 29 | 30 | ## Nix build 31 | 32 | Implicit to the previous workflow, was the availability of the GNU C Compiler and 33 | the usage of the `cp` command. In many package repositories, usage of these tools 34 | is near universal; and forms the foundation for how to build most other software. 35 | 36 | Although C compilers and GNU's `coreutils` (where `cp` comes from) have their 37 | own specific packages in nixpkgs, generally they are aggregated into a pseudo-package 38 | called `stdenv` in nixpkgs. The function `stdenv.mkDerivation` provides: 39 | - A nixpkgs-compatible wrapped C compiler (GCC on linux, Clang on MacOS) 40 | - GNU coreutils 41 | - A default "builder" script 42 | 43 | `stdenv` will be covered in more detail in [the next section](./ch06-02-stdenv.md). 44 | 45 | A nixified version of the build would look like: 46 | ``` 47 | # simple.nix 48 | let 49 | pkgs = import { }; 50 | in 51 | pkgs.stdenv.mkDerivation { 52 | name = "hello-nix"; 53 | 54 | src = ./.; 55 | 56 | # Use $CC as it allows for stdenv to reference the correct C compiler 57 | buildPhase = '' 58 | $CC simple.c -o hello_nix 59 | ''; 60 | } 61 | ``` 62 | 63 | Nix defaults to a Makefile workflow unless specified otherwise. 64 | So stdenv will default to calling `make install` for the `installPhase` which will 65 | fail with `No rule to make target 'install'` so we need 66 | to also fix how nix will install the package. 67 | 68 | ``` 69 | $ nix-build simple.nix 70 | this derivation will be built: 71 | /nix/store/dbavzdq1idb0hvwdh7r9gfn2l52kvycf-hello-nix.drv 72 | ... 73 | install flags: SHELL=/nix/store/3j918i1nbwhby0y38bn2r438rjhh8f4d-bash-5.1-p16/bin/bash install 74 | make: *** No rule to make target 'install'. Stop. 75 | error: builder for '/nix/store/dbavzdq1idb0hvwdh7r9gfn2l52kvycf-hello-nix.drv' failed with exit code 2; 76 | ``` 77 | 78 | ## Nix install 79 | 80 | The second glaring problem in the old workflow, is that 81 | we had a convention as to where to install the executable in /usr/bin/. 82 | But installing software in a central location is one the issues that 83 | nix is trying to solve. Instead, nix needs to install files on a per-package 84 | basis, thus where we need to install files will change for every package. 85 | So how do we know where to install files with nix? 86 | 87 | Nix will bind the values defined in the derivation to environment variables 88 | inside of the nix build. The default "output" of a package is `out`, which will be bound 89 | to the hashed nix store path mentioned in [the derivation section](./ch04-01-create-a-derivation.md). 90 | 91 | So an adjusted workflow would be: 92 | ``` 93 | # build 94 | $ gcc simple.c -o hello_nix 95 | # install 96 | $ mkdir -p $out/bin 97 | $ cp hello_nix $out/bin/hello_nix 98 | ``` 99 | 100 | Extending the example above, the easiest solution would be to write our own `installPhase`. The 101 | resulting expression would be: 102 | 103 | ``` 104 | # simple.nix 105 | let 106 | pkgs = import { }; 107 | in 108 | pkgs.stdenv.mkDerivation { 109 | name = "hello-nix"; 110 | 111 | src = ./.; 112 | 113 | buildPhase = '' 114 | $CC simple.c -o hello_nix 115 | ''; 116 | 117 | installPhase = '' 118 | mkdir -p $out/bin 119 | cp hello_nix $out/bin/hello_nix 120 | ''; 121 | } 122 | ``` 123 | Now when we build the package, nix is able to realize it. After which we can use the executable: 124 | ``` 125 | $ nix-build simple.nix 126 | this derivation will be built: 127 | /nix/store/9j274i4wckn0ksxpj7asd8vbk67kfz4p-hello-nix.drv 128 | ... 129 | /nix/store/giwy9rwzwsdvh86pvdpv37lkwms7xcx9-hello-nix 130 | 131 | $ ./result/bin/hello_nix 132 | Hello from Nix! 133 | ``` 134 | -------------------------------------------------------------------------------- /src/ch06-02-simple-c-program.md: -------------------------------------------------------------------------------- 1 | # Simple C program 2 | 3 | *Write a small, trivial C program example, with just stdenv.mkDerivation* 4 | -------------------------------------------------------------------------------- /src/ch06-02-stdenv.md: -------------------------------------------------------------------------------- 1 | # Stdenv 2 | 3 | `stdenv` provides a foundation for building C/C++ software with nixpkgs. It includes, but is not limited to 4 | containing tools such as: a c compiler and related tools, GNU coreutils, GNU awk, GNU sed, findutils, strip, bash, GNUmake, bzip2, gzip, 5 | and many more tools. Stdenv also provides a default "builder.sh" script which will perform the build of a package. The default builder script 6 | is comprised of many smaller "phases" which package maintainers can alter slightly as needed. The goal of `stdenv` is to enable most C/C++ + `Makefile` workflows; in theory, if a software 7 | package has these installation: 8 | ``` 9 | ./configure # configurePhase, optional 10 | make # buildPhase 11 | make install # installPhase 12 | ``` 13 | Then the only necessary changes for it to work with `stdenv.mkDerivation` would be the inclusion of 14 | `installFlags = [ "PREFIX=$(out)" ];` to communicate where the package should be installed with nix. 15 | 16 | ## Unique qualities of Nixpkgs' Stdenv 17 | 18 | ### Wrapped C Compiler 19 | 20 | `stdenv` exposes a wrapped compiler to help communicate nix-specific to the compiler without 21 | having to rely on the upstream maintainer to expose such allowances in configuration. For example, 22 | let's assume that a package doesn't officially support MacOS, so all testing and building 23 | occurs with Linux + GCC. Trying to package this for MacOS might be difficult because the logic 24 | may call `gcc` directly, and assume 25 | - Nix differences 26 | - Wrapped compiler 27 | - stdenv [shell functions](https://nixos.org/manual/nixpkgs/stable/#ssec-stdenv-functions) 28 | -------------------------------------------------------------------------------- /src/ch06-03-phases.md: -------------------------------------------------------------------------------- 1 | # Phases 2 | -------------------------------------------------------------------------------- /src/ch06-04-build-dependencies.md: -------------------------------------------------------------------------------- 1 | # Build Dependencies 2 | 3 | How to add build dependencies for a packages 4 | - Difference between nativeBuildInputs and buildInputs 5 | - Difference between propagated and non-propagated inputs 6 | - Demonstrate some common usage patterns around dependencies 7 | 8 | How do packages find dependencies when building? 9 | - They don't, nix attempts to fulfill assumptions made by the toolchain 10 | - Generally delegated to tooling which specializes in dependency discovery 11 | - `PKG_CONFIG_PATH`? for `pkg-config` 12 | - `CMAKE_MODULE_PATH`? for `cmake` 13 | - `PYTHONPATH` for `python` when using `buildPythonPackage` 14 | - etc. 15 | 16 | Explain difference between out, dev, lib, and other outputs 17 | - It's a common use case to reference one or more outputs 18 | - Mention the lib's `getDev`, `getDev`, `getLib`, and `getMan` helpers 19 | - TODO: Link to another section expanding on multi-output derivations 20 | -------------------------------------------------------------------------------- /src/ch06-05-runtime-dependencies.md: -------------------------------------------------------------------------------- 1 | # Runtime Dependencies 2 | 3 | - Explain how nix finds runtime dependencies (essentially greps for valid /nix/store/... paths) 4 | - TODO: link to another section on how to reduce closure sizes 5 | - TODO: link to another section on how to ensure runtime dependencies are correctly picked up 6 | - E.g. jar files are compressed, but may reference another package which needs to be present on the host 7 | - Generally this is done by doing `echo ${dependency} > $out/nix-support` 8 | 9 | - How to determine a runtime depdency (e.g. `nix-store -q --requisites`) 10 | 11 | - How to wrap programs so that certain dependencies are present on PATH or in other ways 12 | 13 | - Mention that patching is sometimes required (e.g. python), as there's not always a 14 | deterministic way to define how a package will be consumed (e.g. python module importing another) 15 | -------------------------------------------------------------------------------- /src/ch06-06-building-packages-for-other-toolchains.md: -------------------------------------------------------------------------------- 1 | # Building Packages for Other Toolchains 2 | 3 | - Introduce the concept of shellhooks 4 | - Provide links to documentation for: 5 | - Cmake 6 | - Meson 7 | - Bazel 8 | -------------------------------------------------------------------------------- /src/ch06-07-building-packages-for-other-languages.md: -------------------------------------------------------------------------------- 1 | # Building Nix packages for non-C programming languages 2 | 3 | - Almost all support for other programming languages are built 4 | upon stdenv.mkDerivation 5 | 6 | - Provide links to official documentation on a given programming language 7 | -------------------------------------------------------------------------------- /src/ch06-08-patching.md: -------------------------------------------------------------------------------- 1 | # Patching Packages 2 | 3 | - Common scenario where a pull request hasn't been merged or a new release hasn't 4 | been cut, but a change should be applied to a given package. 5 | 6 | - Cover `patches` attr for mkDerivation 7 | 8 | - Introduce `fetchpatch` utility 9 | - Show example 10 | - Make note that fetchpatch does it's own sanitization, meaning that fetchpatch 11 | and `nix-prefetch-url` will generally create different FODs 12 | - Make note that generally a comment should be added to explain why a patch is being 13 | added, and when is it an appropriate time to remove it 14 | -------------------------------------------------------------------------------- /src/ch06-09-multiple-outputs.md: -------------------------------------------------------------------------------- 1 | # Multiple Outputs 2 | 3 | - Why multiple outputs 4 | - Closure size 5 | - Cross Compilation 6 | - How to Leverage 7 | - Any footguns 8 | - `placeholder` 9 | -------------------------------------------------------------------------------- /src/chXY-AA-shellhooks.md: -------------------------------------------------------------------------------- 1 | # Shellhooks 2 | 3 | example of a shellHook passed to mkDerivation 4 | - Can also be used with nix-shell to execute some code when opening the shell 5 | 6 | Example of packages which add their own shellhooks: 7 | - cmake 8 | - meson 9 | - qtbase 10 | 11 | How to write your own shellHook for a package 12 | -------------------------------------------------------------------------------- /src/chXZ-AB-multi-output-derivations.md: -------------------------------------------------------------------------------- 1 | # Multi-Output Derivations 2 | 3 | - Explain reasoning behind multiple output derivations 4 | - Do the expensive build once, but allow for the artifacts to be 5 | divided between many use-case dependent outputs 6 | 7 | - Common outputs that you would see and what should be contained in them: 8 | - out 9 | - bin 10 | - dev 11 | - lib 12 | - share 13 | - man 14 | 15 | - Limitations of multiple output derivations: 16 | - Can't contain circular dependencies between outputs 17 | --------------------------------------------------------------------------------