Files
fruix/docs/reports/phase1-guix-build-gap-analysis.md

10 KiB

Phase 1.2 follow-up: gap analysis between current FreeBSD prototypes and a real Guix package build

Date: 2026-04-01

Summary

This step documents the concrete remaining gap between the current FreeBSD validation harnesses and a true Guix package/derivation/store-daemon build.

The repository now has three relevant validation layers:

  • native shell-driven GNU Hello build:
    • tests/native-build/run-gnu-hello.sh
  • Scheme-driven GNU Hello builder-phase prototype:
    • tests/native-build/gnu-hello-guix-phase-runner.scm
    • tests/native-build/run-gnu-hello-guix-phase-runner.sh
  • Scheme-driven GNU which builder-phase prototype:
    • tests/native-build/gnu-which-guix-phase-runner.scm
    • tests/native-build/run-gnu-which-guix-phase-runner.sh

Those prototypes prove that FreeBSD can already execute a small but real subset of Guix builder-side GNU build logic when paired with the fixed local Guile build.

They do not yet prove that FreeBSD can perform an actual Guix package build.

Current validated surface

What is already validated on FreeBSD amd64:

  1. Guile can run the necessary Scheme code, provided the locally fixed Guile build is used.
  2. Guix builder-side (guix build gnu-build-system) code can run a subset of %standard-phases.
  3. Two small GNU packages build successfully through that subset:
    • GNU Hello
    • GNU which
  4. The following builder phases have been exercised successfully:
    • set-SOURCE-DATE-EPOCH
    • unpack
    • configure
    • build
    • check
    • install

This means the question is no longer "can FreeBSD run any Guix builder-side GNU phase logic at all?"

The question is now "what still separates these prototypes from a real Guix package build?"

What a real Guix package build does beyond the current prototypes

At a high level, a real Guix package build goes through these layers:

  1. package object -> bag lowering
    • package->bag in ~/repos/guix/guix/packages.scm
  2. bag -> derivation lowering
    • bag->derivation in ~/repos/guix/guix/packages.scm
  3. build-system lowering and builder gexp creation
    • lower and gnu-build in ~/repos/guix/guix/build-system/gnu.scm
  4. gexp residualization into store items and imported module closures
    • lower-object in ~/repos/guix/guix/gexp.scm
  5. daemon connection and build request submission
    • open-connection and set-build-options in ~/repos/guix/guix/store.scm
    • build-derivations in ~/repos/guix/guix/derivations.scm
  6. daemon-side execution with store management, build users, and isolation
    • guix-daemon behavior documented in ~/repos/guix/doc/guix.texi
    • daemon implementation details in ~/repos/guix/nix/libstore/build.cc

The current FreeBSD prototypes only validate a slice of step 3, and they do so in a manually constructed environment.

Gap matrix

1. Package lowering is not exercised yet

Current prototypes:

  • call gnu-build directly
  • manually provide the source tarball URL/hash context
  • manually choose outputs and phases

Missing real Guix behavior:

  • no <package> object is lowered through package->bag
  • no implicit inputs are attached by lower
  • no package->derivation call occurs
  • no real .drv file is generated

Why this matters:

A large amount of actual Guix behavior lives above the builder-phase layer. The package record, arguments, native inputs, propagated inputs, outputs, search paths, and implicit inputs are all resolved before the builder runs.

FreeBSD implication:

The current prototypes show that builder-side Scheme logic works, but they do not yet show that Guix's host-side package lowering logic can successfully target FreeBSD.

2. Implicit GNU build-system inputs are bypassed

In real Guix, gnu-build-system adds implicit inputs through standard-packages in ~/repos/guix/guix/build-system/gnu.scm, which ultimately comes from %final-inputs in ~/repos/guix/gnu/packages/commencement.scm.

That implicit input set includes toolchain and utility packages such as:

  • tar
  • gzip
  • bzip2
  • file
  • diffutils
  • patch
  • findutils
  • gawk
  • zstd
  • sed
  • grep
  • xz
  • coreutils
  • make
  • bash
  • ld-wrapper
  • binutils
  • gcc
  • libc
  • libc:static

Current prototypes instead rely on host tools already present on FreeBSD, such as:

  • fetch
  • sha256
  • bsdtar
  • /bin/sh
  • /usr/bin/install
  • host cc
  • host make

Why this matters:

A real Guix package build is not just "run the phases somehow". It runs them with a specific Guix-managed tool universe and search-path model.

FreeBSD implication:

The current prototypes do not yet answer whether Guix's implicit input model can be lowered, realized, and used coherently on FreeBSD.

3. Imported module closure and build-side module materialization are bypassed

Real gnu-build in ~/repos/guix/guix/build-system/gnu.scm builds a gexp that uses with-imported-modules and gexp->derivation so that builder-side modules become store material.

Current prototypes instead:

  • set GUILE_LOAD_PATH directly to ~/repos/guix
  • load Guix modules straight from the checkout
  • do not build/store an imported module closure
  • do not validate generated Guix configuration modules such as guix config

Why this matters:

This is one of the biggest remaining gaps. Our prototypes prove that the builder-side code itself can run, but they do not prove that Guix can correctly package up the builder program, its modules, and its imported dependencies as a derivation input graph.

FreeBSD implication:

Before a true Guix package build can work, FreeBSD will need a functioning path for:

  • imported Guix Scheme modules
  • build-side module resolution in a store context
  • derivation generation for those module closures

4. The store is still only simulated

Current prototypes use store-like output names under /tmp, for example:

  • /tmp/.../0000000000000000-hello-2.12.3
  • /tmp/.../0000000000000000-which-2.21

Missing real Guix behavior:

  • no canonical /gnu/store
  • no true content-addressed store path computation
  • no .drv path registration
  • no store database updates
  • no garbage-collection roots
  • no validity registration or reference graph maintenance

Why this matters:

Guix's reproducibility, dependency tracking, and garbage collection all depend on the real store, not just on an output directory that looks store-like.

FreeBSD implication:

A real FreeBSD port must eventually establish a functioning /gnu/store equivalent with daemon-managed metadata, not just staged output directories.

5. No daemon RPC path has been validated

Real Guix clients talk to the daemon using open-connection in ~/repos/guix/guix/store.scm and submit builds through build-derivations in ~/repos/guix/guix/derivations.scm.

Current prototypes:

  • do not connect to a daemon
  • do not negotiate the daemon protocol
  • do not set build options via set-build-options
  • do not submit derivations for building

Why this matters:

Even if derivation generation were to succeed on FreeBSD, Guix still needs an operational daemon path to realize builds and manage the store.

FreeBSD implication:

At some point the port must stop being "Scheme code can run locally" and become "a Guix client can ask a daemon to build something".

6. No real build isolation or build-user model is in place

The Guix manual section on guix-daemon documents that builds normally run:

  • under dedicated build users from --build-users-group
  • in a chroot containing only declared dependencies
  • and on GNU/Linux, inside additional namespaces/containers

The daemon code in ~/repos/guix/nix/libstore/build.cc also clearly depends on:

  • a build-users group
  • UID switching
  • temporary build directories
  • chroot setup
  • Linux container features when available

Current prototypes:

  • run as the current user
  • do not switch to build users
  • do not restrict filesystem visibility to declared inputs
  • do not use chroot
  • do not use jails
  • do not isolate network access

Why this matters:

This is the largest architectural gap relative to the final FreeBSD goal.

FreeBSD implication:

The current results are strong evidence for builder-side portability, but they say almost nothing yet about the eventual jail/build-user/isolation design required for a proper port.

7. Substitutes, grafts, and offloading are untouched

Real Guix package builds may involve:

  • substitutes
  • grafts
  • daemon-side build options
  • offloading

Relevant code paths appear in:

  • package->derivation in ~/repos/guix/guix/packages.scm
  • set-build-options in ~/repos/guix/guix/store.scm
  • guix-daemon documentation in ~/repos/guix/doc/guix.texi

Current prototypes:

  • always build locally
  • do not use substitutes
  • do not test graft behavior
  • do not exercise offload logic

Why this matters:

These are not the first blockers for a minimal FreeBSD prototype, but they remain part of the full Guix execution model.

Practical conclusion

The current FreeBSD work has successfully de-risked the following narrow question:

Can FreeBSD run Guix builder-side GNU build phases for small packages when Guile is fixed?

Answer: yes.

The next blockers are now clearly above that layer:

  1. package lowering to bags/derivations
  2. imported module/store materialization
  3. real store and daemon connectivity
  4. daemon-side isolation and build-user execution

Most actionable next milestone

The smallest high-value milestone after this analysis is likely:

Minimal milestone: derivation-generation validation without claiming full build support

Try to validate that FreeBSD can at least get through the host-side lowering path for a tiny package far enough to produce a derivation or identify the first concrete failure point.

That would answer a much sharper question than the current prototypes:

Does FreeBSD fail first in host-side Guix lowering, in store interaction, or in daemon execution?

This is the narrowest next step that meaningfully approaches a real Guix package build.

Proceed with a targeted derivation-generation investigation for a tiny package, using the current GNU Hello package as the first candidate if practical, and record the exact first failure boundary among:

  • missing generated Guix modules/configuration
  • store connection assumptions
  • derivation emission
  • daemon availability
  • daemon-side execution assumptions