# 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 `` 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. ## Recommended next step 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