From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp10.migadu.com ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id oKjEJLY9nmMLDgAAbAwnHQ (envelope-from ) for ; Sat, 17 Dec 2022 23:07:50 +0100 Received: from aspmx1.migadu.com ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp10.migadu.com with LMTPS id qEDpI7Y9nmOERAEAG6o9tA (envelope-from ) for ; Sat, 17 Dec 2022 23:07:50 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 509B316805 for ; Sat, 17 Dec 2022 23:07:50 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p6fKr-0001dB-Q4; Sat, 17 Dec 2022 17:07:13 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p6fKp-0001cy-UC for guix-devel@gnu.org; Sat, 17 Dec 2022 17:07:11 -0500 Received: from knopi.disroot.org ([178.21.23.139]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p6fKm-0006Zd-0p; Sat, 17 Dec 2022 17:07:11 -0500 Received: from localhost (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 1DF7C41451; Sat, 17 Dec 2022 23:07:02 +0100 (CET) X-Virus-Scanned: SPAM Filter at disroot.org Received: from knopi.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FWOXYA-q2g_z; Sat, 17 Dec 2022 23:06:59 +0100 (CET) From: "(" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1671314819; bh=98lDUa5AezTzHU3uU3DG6p1Gw+X2j0G9BkdB+hP4mpE=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=MJyrkgWsnfVyFPos2Pxg4uIfI/NazVX/b2klYtRkzTwX94cTgYumK5/QmtvhW+xDC hpf62TrmYObWHKwDjZTIpuFuOAR7lYbWOlOWCPDOrpiQkLwQ5ldjCh4Cp415ueXK5l O2G6JN3XW0MQOZUA8ahOJhRGbpR2ZgcXRI9IM2bG4ks9RL0h8k0pSmDGOzFOhsMBNZ Xz7qwgsrfKpeI0O/0EdXjQ7pLBoTdeaUS355sBykMBke5uaWqRF7/a+R8kxHZgGRZ/ BYpTyhOxbNeDgrbAW47RHoRBLLOSdzaIUTcFo41zMMs0qsz4YccEgQrjUTh5HItAqQ 1iSKZ8O7NLAsQ== To: guix-devel@gnu.org Cc: mekeor@posteo.de, ludo@gnu.org, "(" Subject: [PATCH guix-artwork v4] website: posts: Add Dissecting Guix, Part 1: Derivations. Date: Sat, 17 Dec 2022 22:06:52 +0000 Message-Id: <20221217220652.1947-1-paren@disroot.org> In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Received-SPF: pass client-ip=178.21.23.139; envelope-from=paren@disroot.org; helo=knopi.disroot.org X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, WEIRD_QUOTING=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: guix-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Development of GNU Guix and the GNU System distribution." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-devel-bounces+larch=yhetil.org@gnu.org Sender: guix-devel-bounces+larch=yhetil.org@gnu.org X-TUID: vOzzmS3r6+ns * website/posts/dissecting-guix-1-derivations.md: New blog post. --- Heya, Here, I've addressed Ludo's criticisms. I do still think we should use LOWER-OBJECT rather than ,LOWER most of the = time, but there is now a paragraph noting that it exists. .../posts/dissecting-guix-1-derivations.md | 450 ++++++++++++++++++ 1 file changed, 450 insertions(+) create mode 100644 website/posts/dissecting-guix-1-derivations.md diff --git a/website/posts/dissecting-guix-1-derivations.md b/website/posts= /dissecting-guix-1-derivations.md new file mode 100644 index 0000000..7226029 --- /dev/null +++ b/website/posts/dissecting-guix-1-derivations.md @@ -0,0 +1,450 @@ +title: Dissecting Guix, Part 1: Derivations +date: TBC +author: ( +tags: Dissecting Guix, Functional package management, Programming interfac= es, Scheme API +--- +To a new user, Guix's functional architecture can seem quite alien, and po= ssibly +offputting. With a combination of extensive `#guix`-querying, determined +manual-reading, and plenty of source-perusing, they may eventually figure = out +how everything fits together by themselves, but this can be frustrating and +often takes a fairly long time. + +However, once you peel back the layers, the "Nix way" is actually rather +elegant, if perhaps not as simple as the mutable, imperative style impleme= nted +by the likes of [`dpkg`](https://wiki.debian.org/dpkg) and +[`pacman`](https://wiki.archlinux.org/title/pacman). +This series of blog posts will cover basic Guix concepts, taking a "ground= -up" +approach by dealing with lower-level concepts first, and hopefully make th= ose +months of information-gathering unnecessary. + +Before we dig in to Guix-specific concepts, we'll need to learn about one +inherited from [Nix](https://nixos.org), the original functional package m= anager +and the inspiration for Guix; the idea of a +[_derivation_](https://guix.gnu.org/manual/devel/en/html_node/Derivations.= html) +and its corresponding _store items_. + +These concepts were originally described by Eelco Dolstra, the original au= thor +of Nix, in their [PhD thesis](https://edolstra.github.io/pubs/phd-thesis.p= df); +see _=C2=A7 2.1 The Nix store_ and _=C2=A7 2.4 Store Derivations_. + +# Store Items + +As you probably know, everything that Guix builds is stored in the _store_, +which is almost always the `/gnu/store` directory. It's the job of the +[`guix-daemon`](https://guix.gnu.org/manual/en/html_node/Invoking-guix_002= ddaemon.html) +to manage the store and build things. If you run +[`guix build PKG`](https://guix.gnu.org/manual/en/html_node/Invoking-guix-= build.html), +`PKG` will be built or downloaded from a substitute server if available, a= nd a +path to an item in the store will be displayed. + +``` +$ guix build irssi +/gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-irssi-1.4.3 +``` + +This item contains the final result of building [`irssi`](https://irssi.or= g). +Let's peek inside: + +``` +$ ls $(guix build irssi) +bin/ etc/ include/ lib/ share/ +$ ls $(guix build irssi)/bin +irssi* +``` + +`irssi` is quite a simple package. What about a more complex one, like +[`glib`](https://docs.gtk.org/glib)? + +``` +$ guix build glib +/gnu/store/bx8qq76idlmjrlqf1faslsq6zjc6f426-glib-2.73.3-bin +/gnu/store/j65bhqwr7qq7l77nj0ahmk1f1ilnjr3a-glib-2.73.3-debug +/gnu/store/3pn4ll6qakgfvfpc4mw89qrrbsgj3jf3-glib-2.73.3-doc +/gnu/store/dvsk6x7d26nmwsqhnzws4iirb6dhhr1d-glib-2.73.3 +/gnu/store/4c8ycz501n2d0xdi4blahvnbjhd5hpa8-glib-2.73.3-static +``` + +`glib` produces five `/gnu/store` items, because it's possible for a packa= ge to +produce multiple [outputs](https://guix.gnu.org/manual/en/html_node/Packag= es-with-Multiple-Outputs.html). +Each output can be referred to separately, by prefixing a package's name w= ith +`:OUTPUT` where supported. For example, this +[`guix install`](https://guix.gnu.org/manual/en/html_node/Invoking-guix-pa= ckage.html) +invocation will add `glib`'s `bin` output to your profile: + +``` +$ guix install glib:bin +``` + +The default output is `out`, so when you pass `glib` by itself to that com= mand, +it will actually install `glib:out` to the profile. + +`guix build` also provides the `--source` flag, which produces the store i= tem +corresponding to the given package's downloaded source code. + +``` +$ guix build --source irssi +/gnu/store/cflbi4nbak0v9xbyc43lamzl4a539hhb-irssi-1.4.3.tar.xz +$ guix build --source glib +/gnu/store/d22wzjq3xm3q8hwnhbgk2xd3ph7lb6ay-glib-2.73.3.tar.xz +``` + +But how does Guix know how to build these store outputs in the first place? +That's where derivations come in. + +# `.drv` Files + +You've probably seen these being printed by the Guix program now and again. +Derivations, represented in the daemon's eyes by `.drv` files, contain +instructions for building store items. We can retrieve the paths of these +`.drv` files with the `guix build --derivations` command: + +``` +$ guix build --derivations irssi +/gnu/store/zcgmhac8r4kdj2s6bcvcmhh4k35qvihx-irssi-1.4.3.drv +``` + +`guix build` can actually also accept derivation paths as an argument, in = lieu +of a package, like so: + +``` +$ guix build /gnu/store/zcgmhac8r4kdj2s6bcvcmhh4k35qvihx-irssi-1.4.3.drv +/gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-irssi-1.4.3 +``` + +Let's look inside this derivation file. + +``` +Derive([("out","/gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-irssi-1.4.3","= ","")],[("/gnu/store/9mv9xg4kyj4h1cvsgrw7b9x34y8yppph-glib-2.70.2.drv",["ou= t"]),("/gnu/store/baqpbl4wck7nkxrbyc9nlhma7kq5dyfl-guile-2.0.14.drv",["out"= ]),("/gnu/store/bfirgq65ndhf63nn4q6vlkbha9zd931q-openssl-1.1.1l.drv",["out"= ]),("/gnu/store/gjwpqzvfhz13shix6a6cs2hjc18pj7wy-module-import-compiled.drv= ",["out"]),("/gnu/store/ij8651x4yh53hhcn6qw2644nhh2s8kcn-glib-2.70.2.drv",[= "out"]),("/gnu/store/jg2vv6yc2yqzi3qzs82dxvqmi5k21lhy-irssi-1.4.3.drv",["ou= t"]),("/gnu/store/qggpjl9g6ic3cq09qrwkm0dfsdjf7pyr-glibc-utf8-locales-2.33.= drv",["out"]),("/gnu/store/zafabw13yyhz93jwrcz7axak1kn1f2cx-openssl-1.1.1s.= drv",["out"])],["/gnu/store/af18nrrsk98c5a71h3fifnxg1zi5mx7y-module-import"= ,"/gnu/store/qnrwmby5cwqdqxyiv1ga6azvakmdvgl7-irssi-1.4.3-builder"],"x86_64= -linux","/gnu/store/hnr4r2d0h0xarx52i6jq9gvsrlc3q81a-guile-2.0.14/bin/guile= ",["--no-auto-compile","-L","/gnu/store/af18nrrsk98c5a71h3fifnxg1zi5mx7y-mo= dule-import","-C","/gnu/store/6rkkvvb7pl1l9ng8vvywvwf357vhm3va-module-impor= t-compiled","/gnu/store/qnrwmby5cwqdqxyiv1ga6azvakmdvgl7-irssi-1.4.3-builde= r"],[("allowSubstitutes","0"),("guix properties","((type . graft) (graft (c= ount . 2)))"),("out","/gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-irssi-1.4= .3"),("preferLocalBuild","1")]) +``` + +It's... not exactly human-readable. We could try to format it and break it +down, but it'd still be pretty hard to understand, since `.drv` files cont= ain no +labels for the fields or any other human-readable indicators. Instead, we'= re +going to explore derivations in a Guile REPL. + +# Exploring Guix Interactively + +Before we continue, we'll want to start a REPL, so that we can try out the= Guix +Guile API interactively. To run a REPL in the terminal, simply +[call `guix repl`](https://guix.gnu.org/manual/devel/en/html_node/Using-Gu= ix-Interactively.html). + +If you're using Emacs, you can instead install +[Geiser](https://nongnu.org/geiser), which provides a comfortable Emacs UI= for +various Lisp REPLs, invoke `guix repl --listen=3Dtcp:37146 &`, and type +`M-x geiser-connect RET RET RET` to connect to the running Guile instance. + +Your `.guile` file may contain code for enabling colours and readline bind= ings +that Geiser will choke on. The default Guix System `.guile` contains code= to +suppress these features when `INSIDE_EMACS` is set, so you'll need to run +`guix repl` like this: + +```sh +INSIDE_EMACS=3D1 guix repl --listen=3Dtcp:37146 & +``` + +There are a few Guix modules we'll need. Run this Scheme code to import t= hem: + +```scheme +(use-modules (guix) + (guix derivations) + (guix gexp) + (guix packages) + (guix store) + (gnu packages glib) + (gnu packages irc)) +``` + +We now have access to the store, G-expression, package, and derivation API= s, +along with the `irssi` and `glib` `` objects. + +# Creating a `` + +The Guix API for derivations revolves around the `` record, wh= ich is +the Scheme representation of that whole block of text surrounded by +`Derive(...)`. If we look in `guix/derivations.scm`, we can see that it's +defined like this: + +```scheme +(define-immutable-record-type + (make-derivation outputs inputs sources system builder args env-vars + file-name) + derivation? + (outputs derivation-outputs) ; list of name/ pa= irs + (inputs derivation-inputs) ; list of + (sources derivation-sources) ; list of store paths + (system derivation-system) ; string + (builder derivation-builder) ; store path + (args derivation-builder-arguments) ; list of strings + (env-vars derivation-builder-environment-vars) ; list of name/value pai= rs + (file-name derivation-file-name)) ; the .drv file name +``` + +With the exception of `file-name`, each of those fields corresponds to a f= ield +in the `Derive(...)` form. Before we can examine them, though, we need to +figure out how to _lower_ that `irssi` `` object into a derivatio= n. + +`guix repl` provides the `,lower` command to create derivations quickly: + +```scheme +,lower irssi +(pk $1) ;use the $N variable automatically bound by the REPL +;;; (# /gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-irssi-1.4.3 7f3bff4a63= 70>) +``` + +Since `,lower` is a REPL command, however, we can't use it in proper Scheme +code. It's quite useful for exploring specific derivations interactively,= but +since the purpose of this blog post is to explain how things work inside, = we're +going to use the pure-Scheme approach here. + +The procedure we need to use to turn a high-level object like `` = into a +derivation is called `lower-object`; more on that in a future post. Howev= er, +this doesn't initially produce a derivation: + +```scheme +(pk (lower-object irssi)) +;;; (#) +``` + +`pk` is an abbreviation for the procedure `peek`, which takes the given ob= ject, +writes a representation of it to the output, and returns it. It's especia= lly +handy when you want to view an intermediate value in a complex expression. + +The returned object is a monadic value (more on those in the next post on +monads) that needs to be evaluated in the context of a store connection. = We do +this by first using `with-store` to connect to the store and bind the conn= ection +to a name, then wrapping the `lower-object` call with `run-with-store`: + +```scheme +(define irssi-drv + (pk (with-store %store + (run-with-store %store + (lower-object irssi))))) +;;; (# /gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-irssi-1.4.3 7fe1902b61= 40>) + +(define glib-drv + (pk (with-store %store + (run-with-store %store + (lower-object glib))))) +;;; (# /gnu/store/lp7k9ygvpwxgxjvmf8bix8d2aar0azr7-glib-2.70.2-bin /gnu/s= tore/22mkp8cr6rxg6w8br9q8dbymf51b44m8-glib-2.70.2-debug /gnu/store/a6qb5arv= ir4vm1zlkp4chnl7d8qzzd7x-glib-2.70.2 /gnu/store/y4ak268dcdwkc6lmqfk9g1dgk2j= r9i34-glib-2.70.2-static 7fe17ca13b90>) +``` + +And we have liftoff! Now we've got two `` records to play wit= h. + +# Exploring `` + +## `` + +The first "argument" in the `.drv` file is `outputs`, which tells the Guix +daemon about the outputs that this build can produce: + +```scheme +(define irssi-outputs + (pk (derivation-outputs irssi-drv))) +;;; ((("out" . #< path: "/gnu/store/v5pd69j3hjs1fck4b5p= 9hd91wc8yf5qx-irssi-1.4.3" hash-algo: #f hash: #f recursive?: #f>))) + +(pk (assoc-ref irssi-outputs "out")) + +(define glib-outputs + (pk (derivation-outputs glib-drv))) +;;; ((("bin" . #< path: "/gnu/store/lp7k9ygvpwxgxjvmf8b= ix8d2aar0azr7-glib-2.70.2-bin" hash-algo: #f hash: #f recursive?: #f>) ("de= bug" . #< path: "/gnu/store/22mkp8cr6rxg6w8br9q8dbymf51b= 44m8-glib-2.70.2-debug" hash-algo: #f hash: #f recursive?: #f>) ("out" . #<= path: "/gnu/store/a6qb5arvir4vm1zlkp4chnl7d8qzzd7x-glib= -2.70.2" hash-algo: #f hash: #f recursive?: #f>) ("static" . #< path: "/gnu/store/y4ak268dcdwkc6lmqfk9g1dgk2jr9i34-glib-2.70.2-stat= ic" hash-algo: #f hash: #f recursive?: #f>))) + +(pk (assoc-ref glib-outputs "bin")) +;;; (#< path: "/gnu/store/lp7k9ygvpwxgxjvmf8bix8d2aar0a= zr7-glib-2.70.2-bin" hash-algo: #f hash: #f recursive?: #f>) +``` + +It's a simple association list mapping output names to `` +records, and it's equivalent to the first "argument" in the `.drv` file: + +``` +[ ("out", "/gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-irssi-1.4.3", "", "= ") +] +``` + +The `hash-algo` and `hash` fields are for storing the content hash and the +algorithm used with that hash for what we term a _fixed-output derivation_, +which is essentially a derivation where we know what the hash of the conte= nt +will be in advance. For instance, `origin`s produce fixed-output derivati= ons: + +```scheme +(define irssi-src-drv + (pk (with-store %store + (run-with-store %store + (lower-object (package-source irssi)))))) +;;; (# /gnu/store/cflbi4nbak0v9xbyc43lamzl4a539hhb-irssi-1.4.3.tar= .xz 7fe17b3c8d70>) + +(define irssi-src-outputs + (pk (derivation-outputs irssi-src-drv))) +;;; ((("out" . #< path: "/gnu/store/cflbi4nbak0v9xbyc43= lamzl4a539hhb-irssi-1.4.3.tar.xz" hash-algo: sha256 hash: #vu8(185 63 113 8= 2 35 163 34 230 127 66 182 26 8 165 18 174 41 227 75 212 165 61 127 34 55 1= 02 102 10 170 90 4 52) recursive?: #f>))) +=20=20 +(pk (assoc-ref irssi-src-outputs "out")) +;;; (#< path: "/gnu/store/cflbi4nbak0v9xbyc43lamzl4a539= hhb-irssi-1.4.3.tar.xz" hash-algo: sha256 hash: #vu8(185 63 113 82 35 163 3= 4 230 127 66 182 26 8 165 18 174 41 227 75 212 165 61 127 34 55 102 102 10 = 170 90 4 52) recursive?: #f>) +``` + +Note how the `hash` and `hash-algo` now have values. + +Perceptive readers may note that the `` has four fields, +whereas the tuple in the `.drv` file only has three (minus the label). The +serialisation of `recursive?` is done by adding the prefix `r:` to the +`hash-algo` field, though its actual purpose is difficult to explain, and = is out +of scope for this post. + +## `` + +The next field is `inputs`, which corresponds to the second field in the `= .drv` +file format: + +``` +[ ("/gnu/store/9mv9xg4kyj4h1cvsgrw7b9x34y8yppph-glib-2.70.2.drv", ["out"]), + ("/gnu/store/baqpbl4wck7nkxrbyc9nlhma7kq5dyfl-guile-2.0.14.drv", ["out"]= ), + ("/gnu/store/bfirgq65ndhf63nn4q6vlkbha9zd931q-openssl-1.1.1l.drv", ["out= "]), + ("/gnu/store/gjwpqzvfhz13shix6a6cs2hjc18pj7wy-module-import-compiled.drv= ", ["out"]), + ("/gnu/store/ij8651x4yh53hhcn6qw2644nhh2s8kcn-glib-2.70.2.drv", ["out"]), + ("/gnu/store/jg2vv6yc2yqzi3qzs82dxvqmi5k21lhy-irssi-1.4.3.drv", ["out"]), + ("/gnu/store/qggpjl9g6ic3cq09qrwkm0dfsdjf7pyr-glibc-utf8-locales-2.33.dr= v", ["out"]), + ("/gnu/store/zafabw13yyhz93jwrcz7axak1kn1f2cx-openssl-1.1.1s.drv", ["out= "]) +] +``` + +Here, each tuple specifies a derivation that needs to be built before this +derivation can be built, and the outputs of the derivation that the build +process of this derivation uses. Let's grab us the Scheme equivalent: + +```scheme +(define irssi-inputs + (pk (derivation-inputs irssi-drv))) +;;; [a fairly large amount of output] + +(pk (car irssi-inputs)) +;;; (#< drv: # /gnu/store/2jj2mxn6wfrcw7i85nywk71mmqbnh= zps-glib-2.70.2 7fe1902b6640> sub-derivations: ("out")>) +``` + +Unlike `derivation-outputs`, `derivation-inputs` maps 1:1 to the `.drv` +form; the `drv` field is a `` to be built, and the +`sub-derivations` field is a list of outputs. + +## Builder Configuration + +The other fields are simpler; none of them involve new records. The third= is +`derivation-sources`, which contains a list of all store items used in the= build +which aren't themselves built using derivations, whereas `derivation-input= s` +contains the dependencies which are. + +This list usually just contains the path to the Guile _build script_ that +realises the store items when run, which we'll examine in a later post, and +the path to a directory containing extra modules to add to the build scrip= t's +`%load-path`, called `/gnu/store/...-module-import`. + +The next field is `derivation-system`, which specifies the system type (su= ch as +`x86_64-linux`) we're building for. Then we have `derivation-builder`, po= inting +to the `guile` executable that runs the build script; and the second-to-la= st is +`derivation-builder-arguments`, which is a list of arguments to pass to +`derivation-builder`. Note how we use `-L` and `-C` to extend the Guile +`%load-path` and `%load-compiled-path` to include the `module-import` and +`module-import-compiled` directories: + +```scheme +(pk (derivation-system irssi-drv)) +;;; ("x86_64-linux") + +(pk (derivation-builder irrsi-drv)) +;;; ("/gnu/store/hnr4r2d0h0xarx52i6jq9gvsrlc3q81a-guile-2.0.14/bin/guile") + +(pk (derivation-builder-arguments irrsi-drv)) +;;; (("--no-auto-compile" "-L" "/gnu/store/af18nrrsk98c5a71h3fifnxg1zi5mx7= y-module-import" "-C" "/gnu/store/6rkkvvb7pl1l9ng8vvywvwf357vhm3va-module-i= mport-compiled" "/gnu/store/qnrwmby5cwqdqxyiv1ga6azvakmdvgl7-irssi-1.4.3-bu= ilder")) +``` + +The final field contains a list of environment variables to set before we = start +the build process: + +```scheme +(pk (derivation-builder-environment-vars irssi-drv)) +;;; ((("allowSubstitutes" . "0") ("guix properties" . "((type . graft) (gr= aft (count . 2)))") ("out" . "/gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-i= rssi-1.4.3") ("preferLocalBuild" . "1"))) +``` + +The last record field, `derivation-file-name` contains the path to the `.d= rv` +file, and so isn't represented in a serialised derivation. + +# Utilising `` + +Speaking of serialisation, to convert between the `.drv` text format and t= he +Scheme `` record, you can use `write-derivation`, `read-deriva= tion`, +and `read-derivation-from-file`: + +```scheme +(define manual-drv + (with-store %store + (derivation %store "manual" + "/bin/sh" '()))) + +(write-derivation drv (current-output-port)) +;;; -| Derive([("out","/gnu/store/kh7fais2zab22fd8ar0ywa4767y6xyak-example= ","","")],[],[],"x86_64-linux","/bin/sh",[],[("out","/gnu/store/kh7fais2zab= 22fd8ar0ywa4767y6xyak-example")]) + +(pk (read-derivation-from-file (derivation-file-name irssi-drv))) +;;; (# /gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-irssi-1.4.3 7fb3798788= c0>) + +(call-with-input-file (derivation-file-name irssi-drv) + read-derivation) +;;; (# /gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-irssi-1.4.3 7fb37ad19e= 10>) +``` + +You can realise ``s as store items using the `build-derivation= s` +procedure: + +```scheme +(use-modules (ice-9 ftw)) + +(define irssi-drv-out + (pk (derivation-output-path + (assoc-ref (derivation-outputs irssi-drv) "out")))) +;;; ("/gnu/store/v5pd69j3hjs1fck4b5p9hd91wc8yf5qx-irssi-1.4.3") + +(pk (scandir irssi-drv-out)) +;;; (#f) + +(pk (with-store %store (build-derivations %store (list irssi-drv)))) +;;; (#t) + +(pk (scandir irssi-drv-out)) +;;; (("." ".." "bin" "etc" "include" "lib" "share")) +``` + +# Conclusion + +Derivations are one of Guix's most important concepts, but are fairly easy= to +understand once you get past the obtuse `.drv` file format. They provide = the +Guix daemon with the initial instructions that it uses to build store items +like packages, origins, and other file-likes such as `computed-file` and +`local-file`, which will be discussed in a future post! + +To recap, a derivation contains the following fields: + +1. `derivation-outputs`, describing the various output paths that the deri= vation + builds +2. `derivation-inputs`, describing the other derivations that need to be b= uilt + before this one is +3. `derivation-sources`, listing the non-derivation store items that the + derivation depends on +4. `derivation-system`, specifying the system type a derivation will be co= mpiled + for +5. `derivation-builder`, the executable to run the build script with +6. `derivation-builder-arguments`, arguments to pass to the builder +7. `derivation-builder-environment-vars`, variables to set in the builder's + environment + +#### About GNU Guix + +[GNU Guix](https://guix.gnu.org) is a transactional package manager and +an advanced distribution of the GNU system that [respects user +freedom](https://www.gnu.org/distros/free-system-distribution-guidelines.h= tml). +Guix can be used on top of any system running the Hurd or the Linux +kernel, or it can be used as a standalone operating system distribution +for i686, x86_64, ARMv7, AArch64 and POWER9 machines. + +In addition to standard package management features, Guix supports +transactional upgrades and roll-backs, unprivileged package management, +per-user profiles, and garbage collection. When used as a standalone +GNU/Linux distribution, Guix offers a declarative, stateless approach to +operating system configuration management. Guix is highly customizable +and hackable through [Guile](https://www.gnu.org/software/guile) +programming interfaces and extensions to the +[Scheme](http://schemers.org) language. --=20 2.38.1