<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>(literatelisp)</title><id>https://me.literatelisp.eu/feeds/tags/guix.xml</id><subtitle>Tag: guix</subtitle><updated>2026-05-05T17:03:30Z</updated><link href="https://me.literatelisp.eu/feeds/tags/guix.xml" rel="self" /><link href="https://me.literatelisp.eu" /><entry><title>Hacklog: Diffing and Comparing Guix Derivations Using Breadth-first Search &amp; Jaccard</title><id>https://me.literatelisp.eu/hacklog-diffing-and-comparing-guix-derivations-using-breadth-first-search--jaccard.html</id><author><name>Wilko</name><email>w@wmeyer.eu</email></author><updated>2026-02-22T22:00:00Z</updated><link href="https://me.literatelisp.eu/hacklog-diffing-and-comparing-guix-derivations-using-breadth-first-search--jaccard.html" rel="alternate" /><content type="html">&lt;p&gt;A cool thing about Guix (and probably functional package managers in
general) is, that derivations form a directed acyclic graph, which
means that all packages with their dependencies or system
configurations can be represented as such. Another, even cooler, thing
is, that Guix provides a graphing utility called `guix graph` which
helps visualising these DAGs in Graphviz (if you ever wanted to frame
a picture of your favorite package graph or play a game of &amp;quot;is this
the dependency graph of a rust package or the visualization of a
Mandelbrot set?&amp;quot; this &lt;strong&gt;should&lt;/strong&gt; be the tool of your choice).&lt;/p&gt;&lt;p&gt;This post is me thinking out loud about my &lt;code&gt;diff-drv&lt;/code&gt; utility that
helps comparing these DAGs and my current approach in comparing the
depth of changes. I plan to write a more regular hacklog, so feedback
on this kind of posts is pretty much welcome!&lt;/p&gt;&lt;p&gt;The utility itself can be found &lt;a href=&quot;https://codeberg.org/theesm/diff-drv&quot;&gt;on Codeberg as theesm/diff-drv&lt;/a&gt;.&lt;/p&gt;&lt;h1&gt;SRFI-1, Guix Graph ...&lt;/h1&gt;&lt;p&gt;As someone who a. exclusively uses Guix System on their personal/work
computers and servers and b. from time to time contributes to the
packaging side of Guix in their spare time, I sometimes want to know:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;why the hash of a package changes if the semver of the package
itself didn't change and what down the dependency graph caused this
change.&lt;/li&gt;&lt;li&gt;how similiar the dependency graph of two derivations of the same
package is.&lt;/li&gt;&lt;li&gt;if the dependency graph grew over time for a specific package.&lt;/li&gt;&lt;li&gt;how to measure how big of a change my system rebuild was and how
much two system derivations still share.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;and up until two years ago I did so by:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;graphing the visual graphs and visually comparing changes (having
two Graphviz graphs open in split and figuring out what the heck
changed between those two)&lt;/li&gt;&lt;li&gt;firing up a REPL and gluing together &lt;code&gt;(srfi srfi-1)&lt;/code&gt; for set
operatings and &lt;code&gt;(ice-9 pretty-print)&lt;/code&gt; for pretty-printing to
somewhat get a superficial human-readable output of how .drv files
differ.&lt;/li&gt;&lt;/ul&gt;&lt;h1&gt;... And The My REPL Hackery Should Actually Be A Program Pipeline&lt;/h1&gt;&lt;p&gt;I shared my second approach on StackOverflow in a question on &lt;a href=&quot;https://stackoverflow.com/a/77856283&quot;&gt;how to
find build information of a guix store item&lt;/a&gt; two years ago. If I find
myself doing something repetitive often enough on a REPL I usually
come up with a program, which is why I wrote my first draft of
&lt;code&gt;diff-drv&lt;/code&gt; around the same time. The output looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    diff-drv /gnu/store/7z3ij54rnhff65wa6byg0rrycrh5442g-system.drv /gnu/store/5s0y5c3fxkxrdak5n5knv0pp2wx6g8q2-system.drv
      outputs  (  -1  +1  U0)
               - (&amp;quot;out&amp;quot; . &amp;quot;ysnz14g7drrmddwp0vdqyy0dvvrh9wv5-system&amp;quot;)
               + (&amp;quot;out&amp;quot; . &amp;quot;dsz5sb6ccvb2yfpjmz6a6hs9nwraj5pb-system&amp;quot;)

       inputs  (  -4  +4  U7)
               - &amp;quot;0aqfbi51i9l1pa1h2f83kb45add9iy86-provenance.drv&amp;quot;
               - &amp;quot;hnaqz9r5b2sp1556fck3c3gka541a5w2-etc.drv&amp;quot;
               - &amp;quot;mq5ypn7f5cmb70nmaww65w2hzzqm8gvj-boot.drv&amp;quot;
               - &amp;quot;ys9axwc1w8v6jpfqgr0p6zxp8blnqzgp-activate.scm.drv&amp;quot;
               + &amp;quot;2il6si89psh41265j6y9lapwqb9v8w55-activate.scm.drv&amp;quot;
               + &amp;quot;fn8pg1jg664zbak6lz2id3dw0fr57153-boot.drv&amp;quot;
               + &amp;quot;j3wj6yqqz35xbxkbp63vh7cjcdahpl1m-provenance.drv&amp;quot;
               + &amp;quot;v3m0vrrgbix8nb2q7i085l1jakbndvjz-etc.drv&amp;quot;
               u &amp;quot;09qcqgni16z3hpv98hlvg5506iyzyy87-profile.drv&amp;quot;
               u &amp;quot;2l9815zdbf5nm4r5ia1njcl6yvrwyrda-module-import-compiled.drv&amp;quot;
               u &amp;quot;b5flkz0fxnprg9qhb38mp91b87n6c2ar-raw-initrd.drv&amp;quot;
               u &amp;quot;hcll0jzfrikv9km83799xqkcl25vx5vc-parameters.drv&amp;quot;
               u &amp;quot;lmw8m5hqr5x476scw4gmc5qdxqlfx56p-locale-multiple-versions.drv&amp;quot;
               u &amp;quot;lvwn6apbaanyiqq1n3ivcypf6b9pvnay-profile.drv&amp;quot;
               u &amp;quot;rhmvzpzk4qc33h0nhd15swfrh7155qsv-guile-3.0.9.drv&amp;quot;

      sources  (  -2  +2  U2)
               - &amp;quot;nr7h7kgdzgdpbqpnrpc9rkzx65giajin-configuration.scm&amp;quot;
               - &amp;quot;v8rw1dvznmc89qvr8lnb633cnrdzwah1-system-builder&amp;quot;
               + &amp;quot;av2ag8gj3k6m09lx17vf53p053h5znwn-configuration.scm&amp;quot;
               + &amp;quot;yl1i65cvxq2ng6570midxar0ziryc52w-system-builder&amp;quot;
               u &amp;quot;c6cf35bavqqs5mqsffl45izqaf0qn4dg-module-import&amp;quot;
               u &amp;quot;qq9fwykdm519k5rqx9j8c8h97x2l39p7-channels.scm&amp;quot;

       system  (  -0  +0  U1)
               u &amp;quot;aarch64-linux&amp;quot;

      builder  (  -0  +0  U1)
               u #f

         args  (  -1  +1  U5)
               - &amp;quot;v8rw1dvznmc89qvr8lnb633cnrdzwah1-system-builder&amp;quot;
               + &amp;quot;yl1i65cvxq2ng6570midxar0ziryc52w-system-builder&amp;quot;
               u &amp;quot;--no-auto-compile&amp;quot;
               u &amp;quot;-L&amp;quot;
               u &amp;quot;c6cf35bavqqs5mqsffl45izqaf0qn4dg-module-import&amp;quot;
               u &amp;quot;-C&amp;quot;
               u &amp;quot;hxbq4i5516rrfhmfjhwfhvlray9gbjmx-module-import-compiled&amp;quot;

     env-vars  (  -1  +1  U2)
               - (&amp;quot;out&amp;quot; . &amp;quot;ysnz14g7drrmddwp0vdqyy0dvvrh9wv5-system&amp;quot;)
               + (&amp;quot;out&amp;quot; . &amp;quot;dsz5sb6ccvb2yfpjmz6a6hs9nwraj5pb-system&amp;quot;)
               u (&amp;quot;LC_CTYPE&amp;quot; . &amp;quot;C.UTF-8&amp;quot;)
               u (&amp;quot;preferLocalBuild&amp;quot; . &amp;quot;1&amp;quot;)

    file-name  (  -1  +1  U0)
               - &amp;quot;7z3ij54rnhff65wa6byg0rrycrh5442g-system.drv&amp;quot;
               + &amp;quot;5s0y5c3fxkxrdak5n5knv0pp2wx6g8q2-system.drv&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and it already tells us superficially what has changed between to
derivations. We're able to answer wether or not a direct dependency
has changed, has been added/removed, if builder args/env-vars have
changed, if output has changed (which is more useful for packages with
multiple outputs).&lt;/p&gt;&lt;h1&gt;Down this Weekends Rabbit Hole&lt;/h1&gt;&lt;p&gt;However, this doesn't give us any clue how deep the changes go, how
much of the DAG has changed, and where down the graph the cause for
the change appeared. While I solved my REPL shenanigans with
&lt;code&gt;diff-drv&lt;/code&gt;, I still found myself looking at visualized graphs to
figure out what exactly has changed.&lt;/p&gt;&lt;p&gt;A mail written by me to guix-devel on possibly introducing a &lt;code&gt;guix store&lt;/code&gt; command (that would cover store plumbing commands such as
diffing and pretty-printing items) and this brief IRC conversation:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; ieure: wonders if there's a .drv file pretty-printer lurking in Guix somewhere
&amp;gt; Rutherther: https://codeberg.org/guix/guix/pulls/6199 :)
&amp;gt; theesm: Rutherther: almost forgot about the mail regarding the drv/store interactions commands i wanted to send to guix devel as there's been several codeberg issues discussing the same thing (mentioned in 6199 that i wanted to write one, maybe now's a good time to do so)
&amp;gt; Rutherther: theesm: yeah, this is a recurring topic for sure
&amp;gt; theesm: think i'll write the mail now^^ (especially as i'm looking for a reason to finally retire my hacky awful aterm .drv files diff thing (&amp;lt;https://codeberg.org/theesm/diff-drv&amp;gt;) if stuff regarding store commands land in guix proper one day)
&amp;gt; civodul: theesm: diff-drv, i’ve always wanted that!
&amp;gt; civodul: ah but i think it’s not quite what i want: i’d want a recursive diff, that finds the “deepest” differing input&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;led me to spend parts of this weekend improving &lt;code&gt;diff-drv&lt;/code&gt; to be
actually (and not just superficially) useful. And of course, there's
an &lt;a href=&quot;https://xkcd.com/356&quot;&gt;XKCD&lt;/a&gt; to explain my weekend shenenigans!&lt;/p&gt;&lt;p&gt;The new, additional, output regarding depth and similiarty &lt;code&gt;diff-drv&lt;/code&gt;
provides looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    theesm@minty ~/diff-drv [env]$ diff-drv --bfs /gnu/store/89d1x358yq6flynsq29kdgfrzlyaz7p5-linux-libre-arm64-mnt-reform-6.18.7.drv /gnu/store/wfmv6z3bblly1akwa4hml4jp43csdi2h-linux-libre-arm64-mnt-reform-6.18.10.drv
    Similarity (Jaccard): 0.9240  (92.40%)
    A (linux-libre-arm64-mnt-reform-6.18.7.drv): 420 (only A: 19, shared: 401 = 95.48%)
    B (linux-libre-arm64-mnt-reform-6.18.10.drv): 415 (only B: 14, shared: 401 = 96.63%)
    A ∪ B: 434 |  A ∩ B: 401 |  Diff: 33

    paths only present in /gnu/store/89d1x358yq6flynsq29kdgfrzlyaz7p5-linux-libre-arm64-mnt-reform-6.18.7.drv:
     * 89d1x358yq6flynsq29kdgfrzlyaz7p5-linux-libre-arm64-mnt-reform-6.18.7.drv
      * 7laq0xpvkwixyj8yghv2iap9l7qyia68-dwarves-1.29.drv
        * az4im9jak383yfmivk0nd0h5r0sm26g2-cmake-minimal-3.31.10.drv
          * hy51f0d74f8jxqwpgb5k729z5j1w67bx-jsoncpp-1.9.6.drv
            * wx3w3szw60f7wbdx0kymmn3bakyg7gly-meson-1.9.0.drv
              * 3c1rpfvx101cikrxn8pm58nw8ciaj2rk-python-3.11.14.drv
              * ad8sr2mrd3kah317sb6cs8f0ij5dbq4j-python-setuptools-80.9.0.drv
              * bb1xi2z3rdg8nfx82i25lias7n9n045n-guile-json-4.7.3.drv
                * g934s5hvgh39371kcld10q1hmvs6chzz-guile-json-4.7.3.tar.gz.drv
              * h32mzli797v881bccxyqhkiqk59y3w9x-python-wrapper-3.11.14.drv
              * jjadn60fv200w7i224d7inad2z3nmh30-module-import-compiled.drv
          * rmmlcn20a28ba6kgvax5qa6skca84vkd-cmake-bootstrap-3.31.10.drv
      * a0jpykjbgn45w8i98r31z69shmx8gfkc-reform-debian-packages-2023-07-10-515-gc527a1d.drv
        * rirbz073z6g5l2w5n1v43l0wp341k9ya-reform-debian-packages-2023-07-10-515-gc527a1d-checkout.drv
      * xia4jsdqvq3776106v7372nks2y2yhm4-linux-libre-6.18.7-guix.tar.zst.drv
        * ap3916dn6ql87il8iqbcmhbfgmysx5v5-linux-libre-6.18.7-guix.tar.xz.drv
          * fgk7agjgd291nhrb03zgwz63qp9c94b1-linux-libre-deblob-6.18.7-gnu.drv
          * mnsa49q6dln255lhcg6vqnz6pcd55si6-linux-6.18.7.tar.xz.drv
          * vvha80z5g5ij8r0cznlhcz6v6xkvqh80-linux-libre-deblob-check-6.18.7-gnu.drv

    paths only present in /gnu/store/wfmv6z3bblly1akwa4hml4jp43csdi2h-linux-libre-arm64-mnt-reform-6.18.10.drv:
     * wfmv6z3bblly1akwa4hml4jp43csdi2h-linux-libre-arm64-mnt-reform-6.18.10.drv
      * 8jcjzpik7q2lay8hl4r342bpmh7s82sa-reform-debian-packages-2023-07-10-525-g7e8a95c.drv
        * pm06jz5fbdyb5dwwbwmzlj69i4lhkjh1-reform-debian-packages-2023-07-10-525-g7e8a95c-checkout.drv
      * rdc9x694chl1gjyzhls0hwrsama2b50j-dwarves-1.29.drv
        * s4rqk30j1wpzjn79hfqyglkqfmsrc13i-cmake-minimal-3.31.10.drv
          * 9avyw2v2q8m8mr4d6v3sxnx32524hipa-jsoncpp-1.9.6.drv
            * 41pxa9sv01v5gp0sdg1l1zjqmpydqibw-meson-1.9.0.drv
              * 1h7k8vhd33h0kq1kwfc3rgyyjwjspycr-python-setuptools-bootstrap-80.9.0.drv
          * wbvkvaxf46jxjr001hiqnp983s0mkixa-cmake-bootstrap-3.31.10.drv
      * z6rdck21vbpvci6kqa85ibl510hy0vxp-linux-libre-6.18.10-guix.tar.zst.drv
        * hxyfxbc9b9bra3l3akasm7cs2n6s8s8n-linux-libre-6.18.10-guix.tar.xz.drv
          * 53b2d046s5jfa5wvryry1j6jf80821vs-linux-libre-deblob-6.18.10-gnu.drv
          * i01ykrczzklch882hy0yrwamv0ja1byg-linux-6.18.10.tar.xz.drv
          * mp0825xk3vcvsrjp7jbzygzchfwp3r13-linux-libre-deblob-check-6.18.10-gnu.drv&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Meaning that we now have a Jaccard index as a means to describe the
similiarty of both DAGs, stats on how many nodes both derivations have
and how they differ:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    Similarity (Jaccard): 0.9240  (92.40%)
    A (linux-libre-arm64-mnt-reform-6.18.7.drv): 420 (only A: 19, shared: 401 = 95.48%)
    B (linux-libre-arm64-mnt-reform-6.18.10.drv): 415 (only B: 14, shared: 401 = 96.63%)
    A ∪ B: 434 |  A ∩ B: 401 |  Diff: 33&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and listings of the actual paths that differ between both
graphs. Let's talk about how it works next, so sit back, grab a cup of
coffee, and put on some &lt;a href=&quot;https://www.youtube.com/watch?v=SOaWApniIN8&quot;&gt;Lucy Dacus&lt;/a&gt;.&lt;/p&gt;&lt;h1&gt;Bread(th) &amp;amp; Roses&lt;/h1&gt;&lt;p&gt;My first step in this was to come up with a reasonable way to build
the input graph of a derivation. Luckily, guixes &lt;code&gt;(guix derivations)&lt;/code&gt;
module provides us with functions to make this task easier. I also
took some inspiration from what guix graph is doing especially in
&lt;code&gt;derivation-dependencies&lt;/code&gt; but didn't got to wrap my head around what
&lt;code&gt;lift1&lt;/code&gt; is doing and how &lt;code&gt;(guix monads)&lt;/code&gt; works, which it utilized, so
I decided to roll my own.&lt;/p&gt;&lt;p&gt;I used Breadth-first search to get the set of all reachable
derivations and a path from root to each derivation.&lt;/p&gt;&lt;p&gt;For this I:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;defined a &lt;code&gt;children&lt;/code&gt; helper for the outgoing edges.&lt;/li&gt;&lt;li&gt;put a good old BFS (as famously seen in probably every introductory
algorithm university course) to work starting at the root derivation.&lt;/li&gt;&lt;li&gt;record, for each discovered node, from where it was first reached.&lt;/li&gt;&lt;li&gt;I also tried to be smart about handling .drv files if they appear on
multiple occasions within the DAG, but in retrospect this falls in
premature optimization land and shouldn't have been necessary at all.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;    (define (build-derivation-graph root)
      (let ((parent-map (make-hash-table))
            (queue      (make-q))
            (child-cache (make-hash-table)))

        (define (children drv-path)
          (or (hash-ref child-cache drv-path #f)
              (let* ((drv  (read-derivation-from-file drv-path))
                     (deps (map (lambda (input)
                                  (derivation-file-name
                                   (derivation-input-derivation input)))
                                (derivation-inputs drv))))
                (hash-set! child-cache drv-path deps)
                deps)))

        (hash-set! parent-map root #f)
        (enq! queue root)

        (let bfs ()
          (if (q-empty? queue)
              parent-map
              (let ((node (deq! queue)))
                (for-each
                 (lambda (child)
                   (unless (hash-get-handle parent-map child)
                     (hash-set! parent-map child node)
                     (enq! queue child)))
                 (children node))
                (bfs))))))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A simplification this implementation makes is that, as BFS explores
the DAG layer by layer, we construct a shortest-path spanning tree of
all reachable derivations, which I consider a &amp;quot;good enough&amp;quot;
approach.&lt;/p&gt;&lt;p&gt;The only &amp;quot;downside&amp;quot; of this becomes apparent when a deeper-lying
dependency changes: because derivation input hashes propagate upwards,
a single change will most likely result in many nodes along different
branches to appear modified, resulting in a pretty verbose diff output
which can become pretty hard to read.&lt;/p&gt;&lt;p&gt;To make this more readable, we could probably build something to
filter for a list of the deepest lying changes and only display a list
of those, but that's for another time.&lt;/p&gt;&lt;h1&gt;Printing The Diff Dance&lt;/h1&gt;&lt;p&gt;So if A, B and C all depend on libfoo somewhere down their dependency
chain, we would see the full paths leading to all three changes
wherever the hash of the store items differ. I think it would be
better UX to just isolate the cause and just print that, but that's
for another weekend, right now we're doing this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    (define (print-diff-tree root parents only)
      (format #t &amp;quot;paths only present in ~a:\n&amp;quot; root)
      (let ((mark (make-hash-table))
            (keep (make-hash-table))
            (kids (make-hash-table)))

        (hash-set! keep root #t)
        (for-each
         (lambda (n)
           (hash-set! mark n #t)
           (let loop ((cur n))
             (when (and cur (not (hash-ref keep cur #f)))
               (hash-set! keep cur #t)
               (loop (hash-ref parents cur #f)))))
         only)

        (hash-for-each
         (lambda (node _)
           (let ((p (hash-ref parents node #f)))
             (when (and p (hash-ref keep p #f))
               (hash-set! kids p (cons node (hash-ref kids p '()))))))
         keep)

        (hash-for-each (lambda (p xs) (hash-set! kids p (sort xs string&amp;lt;?))) kids)

        (let walk ((node root) (depth 0))
          (format #t &amp;quot;~a~c ~a\n&amp;quot;
                  (make-string (* 2 depth) #\space)
                  (if (hash-ref mark node #f) #\* #\space)
                  (store-path-base node))
          (for-each (lambda (c) (walk c (+ depth 1)))
                    (hash-ref kids node '())))
        (newline)))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;to get to our diff tree. It is currently dependent on the
&lt;code&gt;report-jaccard+diffs&lt;/code&gt; function I'll introduce next for data as that's
where &lt;code&gt;only&lt;/code&gt; is coming from, see:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    (call-with-values
            (lambda () (report-jaccard+diffs a b parentsA parentsB))
          (lambda (only-a only-b)
            (print-diff-tree a parentsA only-a)
            (print-diff-tree b parentsB only-b)))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;print-diff-tree&lt;/code&gt; mostly does really ugly plumbing to get printable
pruned tree with formatted nodes, as I'm hopefully rewriting this part
soon to fit the exiting formatting of &lt;code&gt;diff-drv&lt;/code&gt; better I won't go
into detail for now.&lt;/p&gt;&lt;h1&gt;Jaccard et al&lt;/h1&gt;&lt;p&gt;I have the awful tendency to use single/dual-letter variable names
when hacking things on a REPL and to come up with abstractions that
sounded more useful than they turned out to be in the end (hence
&lt;code&gt;walky!&lt;/code&gt;). I'll ignore the rough edges for now, and will focus on
&lt;code&gt;report-jaccard+diffs&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    ;; don't know if i shoot myself in the foot with this abstraction
    ;; PRs suggesting a better name for this welcome
    (define* (walky! src other
                     #:key
                     (on-key    (lambda (_k) #t))
                     (on-shared (lambda (_k) #t))
                     (on-only   (lambda (_k) #t)))
      (hash-for-each
       (lambda (k _)
         (on-key k)
         (if (hash-get-handle other k)
             (on-shared k)
             (on-only k)))
       src))

    (define (report-jaccard+diffs a b A B)
      (let ((sa 0) (sb 0) (i 0) (only-a '()) (only-b '()))

        (walky! A B
                #:on-key    (lambda (_k) (set! sa (+ sa 1)))
                #:on-shared (lambda (_k) (set! i  (+ i 1)))
                #:on-only   (lambda (k)  (set! only-a (cons k only-a))))

        (walky! B A
                #:on-key  (lambda (_k) (set! sb (+ sb 1)))
                #:on-only (lambda (k)  (set! only-b (cons k only-b))))

        (let* ((u (- (+ sa sb) i))
               (j (if (= u 0) 1.0 (/ (exact-&amp;gt;inexact i) (exact-&amp;gt;inexact u))))
               (only-a (sort only-a string&amp;lt;?))
               (only-b (sort only-b string&amp;lt;?))
               (da (- sa i))
               (db (- sb i))
               (pU (if (= u 0) 100.0 (* 100.0 j)))
               (pA (if (= sa 0) 100.0 (* 100.0 (/ (exact-&amp;gt;inexact i) (exact-&amp;gt;inexact sa)))))
               (pB (if (= sb 0) 100.0 (* 100.0 (/ (exact-&amp;gt;inexact i) (exact-&amp;gt;inexact sb))))))

          (format #t &amp;quot;Similarity (Jaccard): ~,4f  (~,2f%)\n&amp;quot; j pU)
          (format #t &amp;quot;A (~a): ~a (only A: ~a, shared: ~a = ~,2f%)\n&amp;quot;
                  (store-path-package-name a) sa da i pA)
          (format #t &amp;quot;B (~a): ~a (only B: ~a, shared: ~a = ~,2f%)\n&amp;quot;
                  (store-path-package-name b) sb db i pB)
          (format #t &amp;quot;A ∪ B: ~a |  A ∩ B: ~a |  Diff: ~a\n\n&amp;quot;
                  u i (+ da db))

          (values only-a only-b))))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Basically, we've got:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;sa representing number of nodes in A&lt;/li&gt;&lt;li&gt;sb doing the same for B&lt;/li&gt;&lt;li&gt;i which is the intersection size of A and B&lt;/li&gt;&lt;li&gt;only-a: nodes in A but not B&lt;/li&gt;&lt;li&gt;only-b: nodes in B but not A&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;at this point, which allows us to calculate the union size (sa + sb -
i) as well as the Jaccard similiarty (which is IoU) and percentages,
so we're able to include a simple summary in our output:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    Similarity (Jaccard): 0.9240  (92.40%)
    A (linux-libre-arm64-mnt-reform-6.18.7.drv): 420 (only A: 19, shared: 401 = 95.48%)
    B (linux-libre-arm64-mnt-reform-6.18.10.drv): 415 (only B: 14, shared: 401 = 96.63%)
    A ∪ B: 434 |  A ∩ B: 401 |  Diff: 33&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;that gives us an idea of how similiar two derivations are, how much of
the dependency graph is shared, wether the dependency graph of A fits
in B, you get the gist.&lt;/p&gt;&lt;h1&gt;Things You Most Likely Didn't Ask Yourself About Derivation Similiarty&lt;/h1&gt;&lt;p&gt;Now we're able to put this to good use. I bet you've always been
wondering if you can fit the dependency tree of &lt;code&gt;hello&lt;/code&gt; inside the
dependency tree of a kernel variant such as
&lt;code&gt;linux-libre-arm64-mnt-pocket-reform&lt;/code&gt; and how similiar that tree is:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    theesm@minty ~/diff-drv [env]$ diff-drv /gnu/store/fxy567lyimwkxxi23brf8y8g2106anlx-linux-libre-arm64-mnt-pocket-reform-6.17.12.drv /gnu/store/qzh7rvz609rm845xxf3jsasxzgbp208x-hello-2.12.2.drv
    Similarity (Jaccard): 0.3957  (39.57%)
    A (linux-libre-arm64-mnt-pocket-reform-6.17.12.drv): 420 (only A: 253, shared: 167 = 39.76%)
    B (hello-2.12.2.drv): 169 (only B: 2, shared: 167 = 98.82%)
    	A ∪ B: 422 |  A ∩ B: 167 |  Diff: 255&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;turns out: it fits (well, except for the source package):&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    paths only present in /gnu/store/qzh7rvz609rm845xxf3jsasxzgbp208x-hello-2.12.2.drv:
     * qzh7rvz609rm845xxf3jsasxzgbp208x-hello-2.12.2.drv
      * kbr9zcwsln63dlr0217ir7any1dcb2ss-hello-2.12.2.tar.gz.drv/store&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Comparing System Reconfigurations&lt;/h2&gt;&lt;p&gt;We're also now able to tell how similiar two system configurations
are, so we're able to tell wether something has been a small change
like this one:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    theesm@minty ~/diff-drv [env]$ diff-drv --bfs $(guix gc --derivers /var/guix/profiles/system-12-link) $(guix gc --derivers /var/guix/profiles/system-11-link)
    Similarity (Jaccard): 0.9906  (99.06%)
    A (system.drv): 4441 (only A: 13, shared: 4428 = 99.71%)
    B (system.drv): 4457 (only B: 29, shared: 4428 = 99.35%)
    A ∪ B: 4470 |  A ∩ B: 4428 |  Diff: 42

    paths only present in /gnu/store/2fm780820z78knqn1r6hnsgc6q8ppfj6-system.drv:
     * 2fm780820z78knqn1r6hnsgc6q8ppfj6-system.drv
      * 4nyvgv999pxixffrm5jnk5fznvrvg6h7-activate.scm.drv
        * sncv8fq3dcjcz4n4n69k54iqar43li4b-activate-service.scm.drv
      * 787rdicqj5amcpdxgba95zjryv5n9j3z-etc.drv
        * dn7zij6x594c2np0g7pv8yrrz6cpfpbd-udev.drv
          * 5rj188vvgrrsd76i5c7fzz68k1csbjjx-udev-rules.d.drv
          * ic9vasgj8bfl6xhcpvbw2nfawya0jf4j-hwdb.bin.drv
            * rvqwppv5aqg3wh9v29kdlmkzqm0q7w14-udev-hwdb.d.drv
        * xm1fcyckiqhampwcvyzvn77mmnb3bg1j-dbus-configuration.drv
          * 17v8dln6lisjz0svdzx3nyja5j4i5nnm-dbus-system-services.drv
      * d5nagfkl8zh21mh6dhbyklinapybdwgh-boot.drv
        * qk1936p5qz4fknsawlk3iln0v68jdmk8-shepherd.conf.drv
      * wn8bnk0ljxjazy82ck0rdyfgrn6kb2gz-provenance.drv

    paths only present in /gnu/store/8b9ng0l6jybb9fv76kp4pfw5hpdgndja-system.drv:
     * 8b9ng0l6jybb9fv76kp4pfw5hpdgndja-system.drv
      * 3x4hnlkpphw0w12dv9xpfb2l7rhkrza5-etc.drv
        * 1mdxg10na89hz0njnz96v54ki0df31nw-dbus-configuration.drv
          * f4s0y8wha0zhgi8kkvh8pk61przxfy3w-dbus-system-services.drv
          * nmdlx1g3j09vcvbynrkvcv248j10dfhb-blueman-2.4.6.drv
            * 66fmbrkqf74v2sv8bp1pszq614r7s567-blueman-2.4.6.tar.xz.drv
            * crhnzh1fv1z0a6ag8qvvck95p69s6jgp-libappindicator-12.10.1-0-298.drv
              * 5mj32f343083kz5v9ahli49fx6mz5v4z-dbus-test-runner-19.04.0.drv
                * 38mwiq495v802y7p9chkp413ymyh6j6m-python-dbusmock-0.37.2.drv
                  * 6bzwp0gddzipd2p4fvxic409bfh8ps0b-python-dbusmock-0.37.2-checkout.drv
                  * drs86vgpcflg0p5xfhdi4klm1041zcww-upower-1.90.2.drv
                    * ppd9aq1byjw9mc8921fbq4845skvi4rn-umockdev-0.17.13.drv
                      * 02iyj43k38k58nrw3g77dg9xfdj36iwf-umockdev-0.17.13.tar.xz.drv
                    * rzamla8y0dswyx60f85cks4r8yyjwn81-upower-1.90.2-checkout.drv
                      * k6299ri40k1bzlagvl3z1059x340zz1p-upower-1.90.2-checkout.drv
                * gy4df8aqrw0m6v3b7fxg36phagnijbnf-dbus-test-runner-19.04.0.tar.gz.drv
              * klsks181ljvbllvzf8kxrn51qv4d1rd8-libappindicator-12.10.1-0-298-checkout.drv
        * 66clmb1rmmf4lhmaqbpdbfx6dinpkbzb-etc-bluetooth.drv
        * px16kpgqsfqlyv9djqn9yb78njkp02aw-udev.drv
          * bika5wj6qsw41q1jsqvn07dswqb38cxx-hwdb.bin.drv
            * zz6bhc26mr99pf0j3cldvwxn6swq9p4b-udev-hwdb.d.drv
          * lgw3qpm1x942wwz7605dwkg0jxdpkjhs-udev-rules.d.drv
      * bdby9zxazgqnhh5fnslfp2g0bs556fb3-activate.scm.drv
        * 0377sfp2h3b04wkgc8467f7i7ckyiicl-activate-service.scm.drv
      * bqrd2fxkfvrcxccnmsrnlql62zbp9ccd-boot.drv
        * cx33w99s4i8y29awsbdgfbkl2fhqi8v2-shepherd.conf.drv
          * 0vcgmxz7dw33y3ib29xndnn9khyifxkn-shepherd-bluetooth.go.drv
            * wyqbs6rhg616hb0hlpxy78rn3mjfm2dq-shepherd-bluetooth.scm.drv
      * rkyd816vsa59gycv0q9bnkqjp5s9wqlw-provenance.drv&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;or a rather big change like this one between the 16th and 14th system
generation:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    diff-drv --bfs $(guix gc --derivers /var/guix/profiles/system-16-link) $(guix gc --derivers /var/guix/profiles/system-14-link)
    Similarity (Jaccard): 0.5509  (55.09%)
    A (system.drv): 4441 (only A: 1242, shared: 3199 = 72.03%)
    B (system.drv): 4565 (only B: 1366, shared: 3199 = 70.08%)
    A ∪ B: 5807 |  A ∩ B: 3199 |  Diff: 2608&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and what impact a reconfiguration has had. I won't paste the full tree
output here, but this has been a major upgrade for a lot of packages.&lt;/p&gt;&lt;h2&gt;Analyzing Dependency Hells&lt;/h2&gt;&lt;p&gt;This also helps figuring out why the hash of a package changed even if
the semver of a package didn't change and the package definition
stayed the same. I use &lt;code&gt;senpai&lt;/code&gt; as my IRC client as it works well with
&lt;code&gt;soju&lt;/code&gt; (which is the bouncer I use). During one upgrade the hash of
senpai did change while the semver stayed at 0.4.1. So &lt;code&gt;diff-drv&lt;/code&gt; can
also be used as fuel for my confirmation bias to stay away from Go and
Rust and stay in C/PHP/Perl (which I write at my job) and Guile/Elisp
happyland:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    theesm@minty ~/diff-drv [env]$ diff-drv --bfs /gnu/store/6ghn9zl05p9jrjps2idzd8lka44s8gwl-senpai-0.4.1.drv /gnu/store/10vwgxsy3hb434kdazgyskm4yh0kh2cf-senpai-0.4.1.drv
    Similarity (Jaccard): 0.7470  (74.70%)
    A (senpai-0.4.1.drv): 570 (only A: 80, shared: 490 = 85.96%)
    B (senpai-0.4.1.drv): 576 (only B: 86, shared: 490 = 85.07%)
    A ∪ B: 656 |  A ∩ B: 490 |  Diff: 166&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;even though I again won't include the 166 paths diff in this post for
readabilities sake. System derivation can be dissected further and the
output of &lt;code&gt;diff-drv&lt;/code&gt; could probably be optimized for this scenario, to
get a summary wether packages, services, users, file-systems, the
kernel etc. changed between derivations, but that would be a whole
different tool in my book (even though the idea of this seems worth
exploring).&lt;/p&gt;&lt;h1&gt;Wrapping Up&lt;/h1&gt;&lt;p&gt;As stated before, &lt;code&gt;diff-drv&lt;/code&gt; can be found on &lt;a href=&quot;https://codeberg.org/theesm/diff-drv&quot;&gt;on Codeberg as
theesm/diff-drv&lt;/a&gt;. My approach in
using BFS and Jaccard similiarity is somewhat useful in answering
questions I have regarding the comparison of derivations, even though
the output could probably be a bit more ergonomical. Either way, it
was a fun hack session and fun to implement!&lt;/p&gt;</content></entry><entry><title>Guix On MNT Pocket Reform: What's Still Missing?</title><id>https://me.literatelisp.eu/guix-on-mnt-pocket-reform-whats-still-missing.html</id><author><name>Wilko</name><email>w@wmeyer.eu</email></author><updated>2026-02-03T22:00:00Z</updated><link href="https://me.literatelisp.eu/guix-on-mnt-pocket-reform-whats-still-missing.html" rel="alternate" /><content type="html">&lt;p&gt;There was a
  &lt;a href=&quot;https://social.coop/@cwebber/116000903605117749&quot;&gt;session on running guix on weird computers
  &lt;/a&gt; during this
years Guix Days, and five people brought their purple colored MNT
  Pocket Reform laptops with them, which proves two things in my book:
&lt;/p&gt;&lt;ul&gt;
  &lt;li&gt;that purple undoubtedly is the best color! (all cool tech is purple, the gameboy advance, gamecube, the pocket reform!)
  &lt;/li&gt;
  &lt;li&gt;… and that there's definitely growing interest in running Guix
    System on aarch64 machines (such as MNT laptops).
  &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;more than a week ago I wrote
  &lt;a href=&quot;https://me.literatelisp.eu/installing-and-running-guix-system-on-rk3588-mnt-pocket-reform.html&quot;&gt;a post on how to install and run Guix
    System on the rk3588 pocket reform
  &lt;/a&gt;, so let's write another one and
focus on what's still missing and what could be improved, to make
  running Guix System on these machines as easy as possible.
&lt;/p&gt;&lt;h1&gt;Status Overview TLDR Thingy(TM)
&lt;/h1&gt;&lt;p&gt;I had a status table living in my
  &lt;a href=&quot;https://protesilaos.com/emacs/denote&quot;&gt;denote Zettelkasten
  &lt;/a&gt; for a while now to keep track the rk3588 pocket reform guix system efforts, this is a slightly modified version of it:
&lt;/p&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Component
  &lt;/th&gt;
  &lt;th&gt;Description
  &lt;/th&gt;
  &lt;th&gt;Upstreamable in Guix
  &lt;/th&gt;
  &lt;th&gt;Available in Guix Proper
  &lt;/th&gt;
  &lt;th&gt;Issues
  &lt;/th&gt;
  &lt;th&gt;Workaround
  &lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;Barebones Image
  &lt;/td&gt;
  &lt;td&gt;System Image for MNT Laptops
  &lt;/td&gt;
  &lt;td&gt;yes
  &lt;/td&gt;
  &lt;td&gt;not yet, but a &lt;a href=&quot;https://codeberg.org/guix/guix/pulls/5973&quot;&gt;PR for inclusion&lt;/a&gt; has been made.
  &lt;/td&gt;
  &lt;td&gt;FBCON rotation doesn't work yet
  &lt;/td&gt;
  &lt;td&gt;
  &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;Kernel
  &lt;/td&gt;
  &lt;td&gt;Kernel with Patches for MNT Laptops
  &lt;/td&gt;
  &lt;td&gt;yes
  &lt;/td&gt;
  &lt;td&gt;yes, as linux-libre-arm64-mnt-reform
  &lt;/td&gt;
  &lt;td&gt;FBCON specific options required for rotation and font size on framebuffer console aren't enable yet
  &lt;/td&gt;
  &lt;td&gt;
  &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;reform2-lpc
  &lt;/td&gt;
  &lt;td&gt;DKMS module for system controller interaction
  &lt;/td&gt;
  &lt;td&gt;yes
  &lt;/td&gt;
  &lt;td&gt;yes, as reform2-lpc-module
  &lt;/td&gt;
  &lt;td&gt;
  &lt;/td&gt;
  &lt;td&gt;
  &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;rk3588 u-boot
  &lt;/td&gt;
  &lt;td&gt;Bootloader without display support
  &lt;/td&gt;
  &lt;td&gt;no (DDR training binary is proprietary)
  &lt;/td&gt;
  &lt;td&gt;no
  &lt;/td&gt;
  &lt;td&gt;no display support, therefore no good way to select previous system generations/entries
  &lt;/td&gt;
  &lt;td&gt;use stock u-boot as long as we can't upstream it
  &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;rk3588 barebox
  &lt;/td&gt;
  &lt;td&gt;Bootloader with display support
  &lt;/td&gt;
  &lt;td&gt;no (same as u-boot)
  &lt;/td&gt;
  &lt;td&gt;no
  &lt;/td&gt;
  &lt;td&gt;not available yet
  &lt;/td&gt;
  &lt;td&gt;use stock u-boot
  &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;WiFi
  &lt;/td&gt;
  &lt;td&gt;Atheros QCNFA335 and QCNFA222 seem to be the only supported options for M2
  &lt;/td&gt;
  &lt;td&gt;yes
  &lt;/td&gt;
  &lt;td&gt;yes
  &lt;/td&gt;
  &lt;td&gt;WiFi options sold by MNT aren't libre
  &lt;/td&gt;
  &lt;td&gt;requires Headset/Switch Board 2.0, USB tethering via phone or USB wifi is possible
  &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;Ethernet
  &lt;/td&gt;
  &lt;td&gt;Untested
  &lt;/td&gt;
  &lt;td&gt;?
  &lt;/td&gt;
  &lt;td&gt;?
  &lt;/td&gt;
  &lt;td&gt;I don't have an ix ethernet adapter, so I can't test this.
  &lt;/td&gt;
  &lt;td&gt;
  &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;FDE
  &lt;/td&gt;
  &lt;td&gt;Full Disk Encryption
  &lt;/td&gt;
  &lt;td&gt;maybe?
  &lt;/td&gt;
  &lt;td&gt;no
  &lt;/td&gt;
  &lt;td&gt;no display output, if I got this right also currently not possible with current bootloader subsystem on non-grub bootloaders?
  &lt;/td&gt;
  &lt;td&gt;encrypted /home partition should work
  &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;reform-tools
  &lt;/td&gt;
  &lt;td&gt;tooling package, contains hw-setup script
  &lt;/td&gt;
  &lt;td&gt;yes
  &lt;/td&gt;
  &lt;td&gt;no
  &lt;/td&gt;
  &lt;td&gt;not packaged yet
  &lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;h1&gt;Recap
&lt;/h1&gt;&lt;p&gt;As a recap of my last post, we're able to run Guix System on a MNT
  Pocket Reform laptop, if we ignore that:
&lt;/p&gt;&lt;ul&gt;
  &lt;li&gt;u-boot has to be stock and has to be already present on EMMC as we
    can't ship rk3588 u-boot in guix just yet.
  &lt;/li&gt;
  &lt;li&gt;all WiFi options offered by MNT aren't supported in
    linux-libre (but there are other options!)
  &lt;/li&gt;
  &lt;li&gt;there's currently not a feasible way to use full disk encryption.
  &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;I think the current state is a prime example of the Pareto principle,
as there's not really that much missing, even though it's difficult to
make an educated guess on a timeframe when some of the things missing
  can be resolved.
&lt;/p&gt;&lt;p&gt;I'd love to see parity in functionality to the stock system images by
MNT for Guix System on the reform laptops and think that it's probably
  achievable.
&lt;/p&gt;&lt;h1&gt;1. What's Already Available In Guix Proper
&lt;/h1&gt;&lt;p&gt;Let's start with excellent news: everything to bring up a rk3588
pocket reform laptop (within the aforementioned limitations) is
  already there!
&lt;/p&gt;&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;a
      &lt;code&gt;linux-libre-arm64-mnt-reform
      &lt;/code&gt; kernel variant (upstreamed by
      Vagrant).
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;the
      &lt;code&gt;reform2-lpc-module
      &lt;/code&gt; DKMS module for reading battery status and
shutting down the reform properly from userspace (upstreamed by
      Arjan).
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;a generic
      &lt;code&gt;u-boot
      &lt;/code&gt; package that works well enough to generate an
      &lt;code&gt;extlinux.conf
      &lt;/code&gt; that can be consumed by the u-boot variant the
      pocket reform is shipped with.
    &lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;h1&gt;2. Things On Their Way To Guix Proper
&lt;/h1&gt;&lt;p&gt;A
  &lt;a href=&quot;https://codeberg.org/guix/guix/pulls/5973&quot;&gt;barebones system image
  &lt;/a&gt; definition good enough to bring up Guix
System when flashed to an microSD card has been suggested as a PR for
inclusion in guix proper by me. This means, that, as soon as this is
merged, CI would pick up building bootable images that can be written
  to microSD.
&lt;/p&gt;&lt;h1&gt;3. What's Still Missing And Can Possibly Be Upstreamed
&lt;/h1&gt;&lt;h2&gt;FBCON Options Enablement (Rotation etc.)
&lt;/h2&gt;&lt;p&gt;A PR to add the relevant kernel config options to enable rotation of
the framebuffer console to the pocket reform kernel variants could be
created. I saw the rotation issue being resolved on some devices
during Guix Days, but forgot to ask which options were chosen to do
  this.
&lt;/p&gt;&lt;h2&gt;rk3588 U-Boot As Soon As Its Bootchain Is Fully Libre
&lt;/h2&gt;&lt;p&gt;As soon as
  &lt;a href=&quot;https://www.collabora.com/news-and-blog/blog/2024/02/21/almost-a-fully-open-source-boot-chain-for-rockchips-rk3588&quot;&gt;the proprietary DDR training blob can be replaced
  &lt;/a&gt; for the
rk3588 we'd be able to upstream a device-specific u-boot package. I
don't know if there currently are any efforts on freeing the DDR
training blob or what the progress is on this, for the time being
  that would remain the only blocker.
&lt;/p&gt;&lt;h2&gt;reform-tools
&lt;/h2&gt;&lt;p&gt;There's currently not a package for the
  &lt;code&gt;reform-tools
  &lt;/code&gt; in guix and not
  a service for the
  &lt;code&gt;reform-hw-setup
  &lt;/code&gt; shell script. I've been meaning to
replace said shell script with a proper shepherd service covering the
same functionality (right now my service calls the upstream script,
  but it could be guile &amp;amp; gexp all the way).
&lt;/p&gt;&lt;h1&gt;4. What's Currently Still Unsupported
&lt;/h1&gt;&lt;h2&gt;Full Disk Encryption
&lt;/h2&gt;&lt;p&gt;There's currently not a possible way to have full disk encryption with
this setup. However, using an encrypted home partition is possible and
may be good enough, even though I strongly prefer being able to use
  FDE. There's a draft GCD on
  &lt;a href=&quot;https://issues.guix.gnu.org/79248&quot;&gt;rewriting the Bootloader Subsystem
  &lt;/a&gt; to be
less GRUB centric, that would maybe also allow tackling these issues
  easier.
&lt;/p&gt;&lt;p&gt;The best case would be, to, instead of typing my LUKS password twice
twice (sic!), be able to use a keyfile to decrypt. And, if not using
a keyfile, to be actually able to see the password prompt and wether
or not unlocking has succeeded (this is also an issue on my
corebooted ThinkPad x230 with a FHD panel mod, my previous laptop,
that I had to blindly type my password four times as the prompt
  wasn't displaying on screen).
&lt;/p&gt;&lt;p&gt;I think for now I'll experiment with encrypting my
  &lt;code&gt;/home
  &lt;/code&gt; partition,
  and will document my setup and the results.
&lt;/p&gt;&lt;p&gt;Lack of FDE was seen as one of the bigger show stoppers during the
Guix Days session, and I agree with that, without fully knowing what a
  good and possible solution could look like.
&lt;/p&gt;&lt;h2&gt;Most Available WiFi Hardware
&lt;/h2&gt;&lt;p&gt;WiFi, as almost always with any kind of modern hardware, remains to
be an issue. Atheros QCNFA335 and QCNFA222 based cards will work on
the Headset/Switch Board 2.0 NGFF slot, so there's at least a libre
  option available.
&lt;/p&gt;&lt;h2&gt;Display Support in U-Boot
&lt;/h2&gt;&lt;p&gt;There's no display support in
  &lt;code&gt;u-boot
  &lt;/code&gt;, which means that, without
using a 3.3V USB-to-UART adapter hooked up to another computer,
there's not really a way to select different generations in the
  bootloader menu.
&lt;/p&gt;&lt;p&gt;The
  &lt;a href=&quot;https://mntre.com/media/reform_md/2026-01-31-dec-jan-update.html&quot;&gt;December and January Update by MNT
  &lt;/a&gt; states that there's been some
  success with display support for
  &lt;code&gt;barebox
  &lt;/code&gt;, so maybe, while not being
able to package it for guix just yet, it could be utilizied the same
  way we utilize u-boot right now as a
  &lt;code&gt;bring your own bootloader
  &lt;/code&gt; type
of thing. Packaging it for Guix would suffer from the same issues as
  &lt;code&gt;u-boot
  &lt;/code&gt; in terms of requiring proprietary blobs during the boot
  process.
&lt;/p&gt;&lt;h1&gt;5. Things I'll Hack On Next
&lt;/h1&gt;&lt;p&gt;Out of all aforementioned issues, I think I'll focus on the following
  things when I have time to spare:
&lt;/p&gt;&lt;ul&gt;
  &lt;li&gt;disk encryption, starting by figuring out a feasible encrypted
    &lt;code&gt;/home
    &lt;/code&gt; set-up, working my way up to be more knowledgable about
    what's missing to do FDE the annoying way (typing passwords twice!).
  &lt;/li&gt;
  &lt;li&gt;coming up with a
    &lt;code&gt;hw-setup
    &lt;/code&gt; shepherd service that's not a bash
    script.
  &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;I'd also love to team up with people on improving support for MNT family laptops in Guix System specifically, if you want to hack on one of the mentioned things with me feel free to contact me by e-mail!
&lt;/p&gt;</content></entry><entry><title>Installing And Running Guix System On (rk3588) MNT Pocket Reform</title><id>https://me.literatelisp.eu/installing-and-running-guix-system-on-rk3588-mnt-pocket-reform.html</id><author><name>Wilko</name><email>w@wmeyer.eu</email></author><updated>2026-01-26T22:00:00Z</updated><link href="https://me.literatelisp.eu/installing-and-running-guix-system-on-rk3588-mnt-pocket-reform.html" rel="alternate" /><content type="html">&lt;p&gt;I've been daily driving my MNT Pocket Reform for a year now, but only
recently managed to set-up Guix System earlier this January, after a
year of failed attempts. As of a few weeks ago I've been running:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Guix System using the (available in guix proper)
&lt;code&gt;linux-libre-arm64-mnt-reform&lt;/code&gt; kernel.&lt;/li&gt;&lt;li&gt;Installed on an NVMe SSD (which is possible since the latest reform
upstream u-boot that gave NVMe precedence over EMMC).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;and all of that has been pretty stable so far.&lt;/p&gt;&lt;p&gt;I'll try to briefly describe my setup and what's necessary to install
Guix System here. This is mostly based on
&lt;a href=&quot;https://codeberg.org/vagrantc/mnt-reform-guix-config/src/branch/main&quot;&gt;vagrantc/mnt-reform-guix-config&lt;/a&gt;
and is using packages Vagrant upstreamed (who should get all the
credit for enabling hardware support for MNT laptops in Guix System, I
didn't do anything besides writing my operating-system declaration for
my current set-up).&lt;/p&gt;&lt;h1&gt;A Minimal operating-system Declaration&lt;/h1&gt;&lt;p&gt;It's probably a good idea to preface this post with the
&lt;code&gt;operating-system&lt;/code&gt; declaration I currently use on my Pocket Reform as
it's quite minimal and gives a brief first overview of my setup:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(operating-system
  (host-name &amp;quot;minty&amp;quot;)
  (timezone &amp;quot;Europe/Paris&amp;quot;)
  (locale &amp;quot;en_US.utf8&amp;quot;)
  (keyboard-layout (keyboard-layout &amp;quot;us&amp;quot; &amp;quot;altgr-intl&amp;quot;))
  (bootloader (bootloader-configuration
                (bootloader u-boot-bootloader)))
  (file-systems (cons (file-system
                        (device (uuid &amp;quot;5bab4a71-b736-4534-b59b-824554610a06&amp;quot;))
                        (mount-point &amp;quot;/&amp;quot;)
                        (type &amp;quot;ext4&amp;quot;)) %base-file-systems))
  (kernel linux-libre-arm64-mnt-reform)
  (kernel-loadable-modules (list reform2-lpc-module))
  (kernel-arguments %mnt-pocket-reform-kernel-args)
  (initrd-modules %mnt-pocket-reform-initrd-modules)
  (users (cons* (user-account
                  (name &amp;quot;theesm&amp;quot;)
                  (group &amp;quot;users&amp;quot;)
                  (supplementary-groups '(&amp;quot;wheel&amp;quot; &amp;quot;netdev&amp;quot; &amp;quot;audio&amp;quot; &amp;quot;video&amp;quot;)))
                %base-user-accounts))
  (packages (append mnt-pocket-reform-sway-desktop-packages %base-packages))
  (services
   (modify-services minty-services
     (delete login-service-type)
     (delete mingetty-service-type))))&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;%mnt-pocket-reform-kernel-args&lt;/code&gt; contains a list of kernel-args
that's similiar to what the stock image is using:&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;(define %mnt-pocket-reform-kernel-args (list &amp;quot;no_console_suspend&amp;quot;
                                             &amp;quot;cryptomgr.notests&amp;quot;
                                             &amp;quot;loglevel=3&amp;quot;
                                             &amp;quot;clk_ignore_unused&amp;quot;
                                             &amp;quot;cma=256M&amp;quot;
                                             &amp;quot;swiotlb=65535&amp;quot;
                                             &amp;quot;console=ttyS2,1500000&amp;quot;
                                             &amp;quot;fbcon=rotate:3&amp;quot;
                                             &amp;quot;fbcon=font:TER16x32&amp;quot;
                                             &amp;quot;console=tty1&amp;quot;))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(note: the &lt;code&gt;fbcon&lt;/code&gt; configuration has no effect, never bothered to
remove it though)&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;%mnt-pocket-reform-initrd-modules&lt;/code&gt; contains a list of initrd
modules which ressembles what &lt;a href=&quot;https://codeberg.org/vagrantc/mnt-reform-guix-config/src/commit/afec35a589df79b7b7708da5c8636d36eeb85d2f/config-mnt-reform.scm#L293&quot;&gt;Vagrants MNT Reform
config&lt;/a&gt;
is using and which is working for the Pocket Reform as well (I don't
know if all modules are necessary though):&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;(define %mnt-pocket-reform-initrd-modules (list &amp;quot;rfkill&amp;quot; &amp;quot;dm_mod&amp;quot; &amp;quot;rk805_pwrkey&amp;quot; &amp;quot;hantro_vpu&amp;quot;
    					&amp;quot;snd_soc_wm8960&amp;quot; &amp;quot;v4l2_vp9&amp;quot; &amp;quot;rockchip_saradc&amp;quot; &amp;quot;v4l2_h2
64&amp;quot; &amp;quot;v4l2_jpeg&amp;quot;
    					&amp;quot;industrialio_triggered_buffer&amp;quot; &amp;quot;v4l2_mem2mem&amp;quot; &amp;quot;rockch
ip_thermal&amp;quot;
    					&amp;quot;kfifo_buf&amp;quot; &amp;quot;snd_soc_rockchip_i2s_tdm&amp;quot; &amp;quot;videobuf2_dma_
contig&amp;quot;
    					&amp;quot;videobuf2_memops&amp;quot; &amp;quot;videobuf2_v4l2&amp;quot; &amp;quot;panthor&amp;quot; &amp;quot;videode
v&amp;quot; &amp;quot;drm_gpuvm&amp;quot;
    					&amp;quot;videobuf2_common&amp;quot; &amp;quot;drm_exec&amp;quot; &amp;quot;snd_soc_audio_graph_card&amp;quot; &amp;quot;mc&amp;quot;
    					&amp;quot;drm_shmem_helper&amp;quot; &amp;quot;gpu_sched&amp;quot; &amp;quot;snd_soc_simple_card_utils&amp;quot;
    					&amp;quot;pci_endpoint_test&amp;quot; &amp;quot;fuse&amp;quot; &amp;quot;x_tables&amp;quot; &amp;quot;ipv6&amp;quot; &amp;quot;onboard_usb_dev&amp;quot;
    					&amp;quot;dwmac_rk&amp;quot; &amp;quot;stmmac_platform&amp;quot; &amp;quot;stmmac&amp;quot; &amp;quot;phy_rockchip_naneng_combphy&amp;quot;
    					&amp;quot;phy_rockchip_usbdp&amp;quot; &amp;quot;typec&amp;quot; &amp;quot;rtc_pcf8523&amp;quot;
    					&amp;quot;phy_rockchip_samsung_hdptx&amp;quot; &amp;quot;pcs_xpcs&amp;quot; &amp;quot;nvme&amp;quot; &amp;quot;nvme_core&amp;quot;
    					&amp;quot;rockchipdrm&amp;quot; &amp;quot;analogix_dp&amp;quot; &amp;quot;dw_hdmi_qp&amp;quot; &amp;quot;dw_mipi_dsi&amp;quot; &amp;quot;ahci&amp;quot;
    					&amp;quot;dm-crypt&amp;quot; &amp;quot;xts&amp;quot;))&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;mnt-pocket-reform-sway-desktop-packages&lt;/code&gt; contains a list of
system packages I use, mostly sway and sway adjacent stuff as well
as a handful of utilities.&lt;/li&gt;&lt;li&gt;&lt;code&gt;minty-services&lt;/code&gt; contains a list of services I use on the pocket
reform. I included &lt;a href=&quot;https://codeberg.org/vagrantc/mnt-reform-guix-config/src/commit/afec35a589df79b7b7708da5c8636d36eeb85d2f/config-mnt-reform.scm#L216&quot;&gt;vagrantc/mnt-reform-guix-config:
reform-hw-setup-service&lt;/a&gt;
in it which is the only Pocket Reform specific service, It's not
necessary to be able to use Guix System on the Pocket Reform though.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Bootloader&lt;/h2&gt;&lt;p&gt;I think being able to properly boot via NVMe was the missing bit that
enabled me to switch from the stock debian-based image to Guix System,
as I never took the chance to install it to EMMC (which probably
would've meant replacing the stock u-boot) and running Guix System
from microSD had poor performance.&lt;/p&gt;&lt;p&gt;My current set-up relies on the presence of the stock u-boot on
EMMC, which would consume the &lt;code&gt;/boot/extlinux/extlinux.conf&lt;/code&gt; generated
by the generic u-boot package that's included in the bootloader bit:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(bootloader (bootloader-configuration
  (bootloader u-boot-bootloader)))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;of my systems &lt;code&gt;configuration.scm&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;I did experiment with including the non-free u-boot package in my
configuration at first, trying to come up with something that could be
used in the bootloader section of the &lt;code&gt;operating-system&lt;/code&gt; declaration,
but that pretty much lead to nowhere, while creating the initial
microSD image. I didn't understand at that time that doing so wasn't
necessary to boot from microSD, as providing a &lt;code&gt;extlinux.conf&lt;/code&gt; to be
found on microSD or NVMe would be good enough for the stock u-boot to
let Guix System boot.&lt;/p&gt;&lt;h2&gt;Networking&lt;/h2&gt;&lt;p&gt;I use USB tethered networking provided by my Oneplus 6t (WiFi and
mobile data) as I haven't gotten around to permanently install a WiFi
card in it yet. I mostly use mobile data while being away from home
and have my phone plugged in while sitting at my desk at home, so it's
pretty convenient for my scenario.&lt;/p&gt;&lt;p&gt;I think I'll end up putting something ath9k based in it as soon as my
&lt;a href=&quot;https://shop.mntre.com/products/mnt-pocket-reform-headset-switch-board-2-0?taxon_id=13&quot;&gt;Headset/Switch Board
2.0&lt;/a&gt;
arrives, so I would be able to continue using &lt;code&gt;linux-libre&lt;/code&gt; and to use
pre-build substitutes for the kernel. Even though the rk3588 is
powerful enough to build its kernel from source. I currently have to build
a modified kernel from source until my &lt;a href=&quot;https://codeberg.org/guix/guix/pulls/5760&quot;&gt;pull request to add wireguard and USB
tethering support&lt;/a&gt; to the
MNT kernel variant is merged, which takes between 40-50m per kernel
build.&lt;/p&gt;&lt;p&gt;Regarding WiFi option if we want to stay libre and blob-free there are
two options that would probably be fitting the M.2 NGFF slot:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Atheros QCNFA335&lt;/li&gt;&lt;li&gt;Atheros QCNFA222&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;reform2-lpc (DKMS)&lt;/h2&gt;&lt;p&gt;Guix proper provides a package for the &lt;code&gt;reform2-lpc&lt;/code&gt; DKMS module that
enables to read the battery status and is necessary to fully shutdown
the Pocket Reform from userspace. It can be passed to
&lt;code&gt;kernel-loadable-modules&lt;/code&gt; in a &lt;code&gt;operating-system&lt;/code&gt; declaration:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(kernel-loadable-modules (list reform2-lpc-module))&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Battery&lt;/h2&gt;&lt;p&gt;On most days, I'm able to get 3-4h of battery life out of the Pocket
Reform until it needs a charge, depending on display brightness and
what CPU governor I set. It could be improved by putting larger
batteries in it, but I fail to see the need to do that for my usage
scenario. I get similar results using the stock debian-based operating
system.&lt;/p&gt;&lt;h1&gt;Installing Guix System&lt;/h1&gt;&lt;p&gt;I booted a minimal config that's similar to my current
operating-system declaration minus the sway parts from microSD and
pretty much just &lt;code&gt;guix system init&lt;/code&gt;ed to the NVMe, rebooted, and
have been enjoying Guix System on my Pocket Reform ever since.&lt;/p&gt;&lt;p&gt;This is the image type I've used to build the microSD image alongside
a &lt;code&gt;operating-system&lt;/code&gt; declaration that's similiar to the one opening
this post:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(define mnt-pocket-reform-image-type
  (image-type
   (name 'mnt-pocket-reform-raw)
   (constructor (lambda (os)
                  (image
                   (inherit
                    (raw-with-offset-disk-image (* 16 (expt 2 20))))
                   (operating-system os)
                   (platform aarch64-linux))))))

(define mnt-pocket-reform-barebones-raw-image
  (image
   (inherit
    (os+platform-&amp;gt;image mnt-pocket-reform-sway-os aarch64-linux
                        #:type mnt-pocket-reform-image-type))
   (name 'mnt-pocket-reform-barebones-raw-image)))

mnt-pocket-reform-barebones-raw-image&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;even though running Guix as a foreign package manager on top of the
stock OS would've been good enough to install via &lt;code&gt;guix system init&lt;/code&gt;
to NVMe as well, so building a microSD image first isn't strictly
necessary.&lt;/p&gt;&lt;h2&gt;tldr&lt;/h2&gt;&lt;p&gt;To be able to use Guix System on the rk3588 we need:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;a recent stock u-boot running on the MNT Pocket Reform EMMC that
includes NVMe in its boot order.&lt;/li&gt;&lt;li&gt;a generic &lt;code&gt;u-boot-bootloader&lt;/code&gt; configuration in our
&lt;code&gt;operating-system&lt;/code&gt; declaration that generates an &lt;code&gt;extlinux.conf&lt;/code&gt;
that can be consumed by said stock u-boot.&lt;/li&gt;&lt;li&gt;the &lt;code&gt;linux-libre-arm64-mnt-reform&lt;/code&gt; kernel available in guix proper.&lt;/li&gt;&lt;li&gt;the &lt;code&gt;reform2-lpc-module&lt;/code&gt; that's also available in guix proper.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;and either a microSD image or guix as a foreign package manager to run
&lt;code&gt;guix system image&lt;/code&gt; or &lt;code&gt;init&lt;/code&gt; from.&lt;/p&gt;</content></entry><entry><title>Guix System On A Raspberry Pi 3b</title><id>https://me.literatelisp.eu/guix-system-on-a-raspberry-pi-3b.html</id><author><name>Wilko</name><email>w@wmeyer.eu</email></author><updated>2024-02-27T18:00:00Z</updated><link href="https://me.literatelisp.eu/guix-system-on-a-raspberry-pi-3b.html" rel="alternate" /><content type="html">&lt;p&gt;I've been running my trusty Raspberry Pi Single-Board Computer as a
DNS, DHCP and Gitolite-Server at home since around 2016. It's been
running on a minimal Raspbian and later on NixOS image, but I always
wanted to switch it over to Guix System, to be able to do most of the
configuration of my small server in Guile using Guixes tooling for
maintenance and systems administration. I'll briefly describe what I
did to succesfully boot Guix System in the following. I won't talk
about the actual usage of Guix as a DNS, DHCP and Gitolite-Server on a
Raspberry Pi for now, but eventually will cover these aspects later.&lt;/p&gt;&lt;h1&gt;Firmware Issues&lt;/h1&gt;&lt;p&gt;First things first, the FSF lists VideoCore IV based SBCs such as the
Raspberry Pi as &lt;em&gt;Single-board computers with fatal flaws&lt;/em&gt;. To quote
them&lt;a href=&quot;https://www.fsf.org/resources/hw/single-board-computers&quot;&gt;^1&lt;/a&gt; directly:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Boards based on the Broadcom VideoCore 4 family, such as the
Raspberry Pi, require non-free software to startup, although
signature checks are not enforced. A free proof-of-concept
replacement firmware has been developed, but it is not in a usable
state, and development has halted. Until the non-free startup
program is fully freed, these boards are useless in the free world.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;What's interesting about the Raspberry Pi 3b here, is that it's
primary processor, is the Broadcom VPU. When it gets powered on, the
ARM core is off, and only gets enabled when the first stage boot ROM
is able to read the proprietary second-stage bootloader binary blob
(bootcode.bin) from SD-Card.&lt;/p&gt;&lt;p&gt;The second-stage bootloader then looks for a third-stage bootloader in
a provided config.txt, which will be u-boot in our case, which then
takes care of the rest of the boot process.&lt;/p&gt;&lt;p&gt;There have been efforts to write a &lt;a href=&quot;https://github.com/christinaa/rpi-open-firmware/blob/master/README.md&quot;&gt;libre VPU firmware&lt;/a&gt;, but for now we have to rely on a proprietary bootcode.bin.&lt;/p&gt;&lt;p&gt;This being said, the Raspberry Pi is far from being my preferred ARM
SBC, as it's pretty reliant on proprietary firmware; but as I already
own such a device and its technically working fine, I see no reason
replacing it with something else as replacing working hardware isn't
really sustainable.&lt;/p&gt;&lt;h1&gt;Going The Non-Free Path&lt;/h1&gt;&lt;p&gt;Guix System follows the GNU FSDG&lt;a href=&quot;https://www.gnu.org/distros/free-system-distribution-guidelines.en.html&quot;&gt;^2&lt;/a&gt;, which means that there won't be
and will never be any upstream support for the non-free components
required to boot-up the Raspberry Pi.&lt;/p&gt;&lt;p&gt;So to get the best possible support in terms of hardware, I wanted to be as close to the raspberry pi upstream as possible and use:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A kernel based on &lt;a href=&quot;https://github.com/raspberrypi/linux&quot;&gt;raspberrypi/linux&lt;/a&gt;&lt;/li&gt;&lt;li&gt;And &lt;a href=&quot;https://github.com/raspberrypi/firmware&quot;&gt;raspberrypi/firmware&lt;/a&gt; for propietary firmware.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Luckily I stumbled upon a repository a few month ago where someone already made a packaging attempt for these two things, it can be found here: &lt;a href=&quot;https://git.pantherx.org/development/hardware/raspberry/-/tree/main?ref_type=heads&quot;&gt;PantherX/raspberry&lt;/a&gt;. The image  (as of 2024-02-27) doesn't build out of the box and was written for a later revision of Rasperry Pi. So I'm going to use this as a base with minor modifications.&lt;/p&gt;&lt;h1&gt;Building A First System Image&lt;/h1&gt;&lt;p&gt;As said before building the unmodified pantherx/raspberry image with:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;guix system --target=aarch64-linux-gnu image raspberry-pi.scm --skip-checks --verbosity=3 -K&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;did fail because of two things:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;gawk-mesboot build failed for cross-compilation, so I had to
disable grafting by setting --no-grafts (there was upstream issue
for this behaviour already: &lt;a href=&quot;https://issues.guix.gnu.org/66866&quot;&gt;Grafting breaks
cross-compilation&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The template by PantherX tries to set a bunch of environmental
variables during configure phase. Setting these explicitly lets the kernel
compilation fail in an early stage with:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;scripts/extract-cert.c:21:10: fatal error: openssl/bio.h: No such file or directory&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;not setting those fixes it and my kernel builds. I also replaced
bcm2711_defconfig withbcmrpi3_defconfig as the PantherX
configuration originally targets a later revision of
Raspberry Pis.&lt;/p&gt;&lt;p&gt;I applied the following changes to the rpi-kernel.scm:&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;diff --git a/rpi-kernel.scm b/../guix-mono/projects/raspberrypi/rpi-kernel.scm
index 426cb25..359c88c 100644
--- a/rpi-kernel.scm
+++ b/../guix-mono/projects/raspberrypi/rpi-kernel.scm
@@ -114,22 +114,11 @@
       (format #t &amp;quot;`ARCH' set to `~a'~%&amp;quot; (getenv &amp;quot;ARCH&amp;quot;))
 
       (when target
-        (setenv &amp;quot;C_INCLUDE_PATH&amp;quot; (string-join
-                                  (cdr (string-split (getenv &amp;quot;C_INCLUDE_PATH&amp;quot;) #\:))
-                                  &amp;quot;:&amp;quot;))
-
-        (setenv &amp;quot;CPLUS_INCLUDE_PATH&amp;quot; (string-join
-                                      (cdr (string-split (getenv &amp;quot;CPLUS_INCLUDE_PATH&amp;quot;) #\:))
-                                      &amp;quot;:&amp;quot;))
-
-        (setenv &amp;quot;LIBRARY_PATH&amp;quot; (string-join
-                                (cdr (string-split (getenv &amp;quot;LIBRARY_PATH&amp;quot;) #\:))
-                                &amp;quot;:&amp;quot;))
         (setenv &amp;quot;CROSS_COMPILE&amp;quot; (string-append target &amp;quot;-&amp;quot;))
         (format #t &amp;quot;`CROSS_COMPILE' set to `~a'~%&amp;quot;
                 (getenv &amp;quot;CROSS_COMPILE&amp;quot;))))
     (setenv &amp;quot;KERNEL&amp;quot; &amp;quot;kernel8&amp;quot;)
-    (invoke &amp;quot;make&amp;quot; &amp;quot;bcm2711_defconfig&amp;quot;)
+    (invoke &amp;quot;make&amp;quot; &amp;quot;bcmrpi3_defconfig&amp;quot;)
     (let ((port (open-file &amp;quot;.config&amp;quot; &amp;quot;a&amp;quot;))
           (extra-configuration #$(config-&amp;gt;string %default-extra-linux-options)))
       (display extra-configuration port) &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;added nss-certs to %base-packages to be able to have applications
talk TLS on the raspberry pi in the raspberry-pi.scm that contains
the operating-system declaration used by our prospective image:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(packages (append (list nss-certs) %base-packages))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and build the image with:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;guix system --no-grafts --target=aarch64-linux-gnu image raspberry-pi.scm --skip-checks --verbosity=3 -K&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally, I used dd to write it to a microSD card, and afterwards
resized the second partition (root partition) on said microSD:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;echo &amp;quot;, +&amp;quot; | sfdisk -N 2 /dev/mmcblk0
e2fsck -f /dev/mmcblk0p2 
resize2fs /dev/mmcblk0p2 &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;to full-size and successfully booted Guix on my Raspberry Pi 3b.&lt;/p&gt;&lt;h1&gt;Next Steps&lt;/h1&gt;&lt;p&gt;Now being able to boot Guix System on my Raspberry Pi 3b, I'll
probably:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Try to build a recent 5.15.x series kernel and more recent firmware.&lt;/li&gt;&lt;li&gt;Try to do this for a 6.6.x series kernel which should be the latest
currently available in the raspberrypi/linux fork.&lt;/li&gt;&lt;li&gt;Write shepherd services for a DHCP and DNS server as well as
Gitolite.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I may consider sharing my notes on these topics on here as well.&lt;/p&gt;</content></entry></feed>