Add native GNU Hello FreeBSD build harness
This commit is contained in:
@@ -115,14 +115,57 @@ Current assessment:
|
||||
- no source changes were needed in `~/repos/bdwgc` yet, but the earlier FreeBSD warning keeps it on the watch list
|
||||
- the project can now move on to Phase 1.2 with a known-good local Guile fallback
|
||||
|
||||
## 2026-04-01 — Phase 1.2 started: native GNU Hello build validated on FreeBSD
|
||||
|
||||
Completed work:
|
||||
|
||||
- added a reusable native build harness:
|
||||
- `tests/native-build/run-gnu-hello.sh`
|
||||
- used the current Guix package definition in `~/repos/guix/gnu/packages/base.scm` as the source of truth for:
|
||||
- GNU Hello version `2.12.3`
|
||||
- expected Guix nix-base32 source hash `183a6rxnhixiyykd7qis0y9g9cfqhpkk872a245y3zl28can0pqd`
|
||||
- verified the downloaded tarball against the translated SHA256:
|
||||
- `0d5f60154382fee10b114a1c34e785d8b1f492073ae2d3a6f7b147687b366aa0`
|
||||
- successfully executed the standard native build lifecycle on `FreeBSD 15.0-STABLE` amd64:
|
||||
- fetch
|
||||
- hash verification
|
||||
- extract
|
||||
- configure
|
||||
- build
|
||||
- staged install
|
||||
- runtime execution
|
||||
- confirmed the staged binary runs and prints:
|
||||
- `Hello, world!`
|
||||
- captured build metadata including:
|
||||
- compiler and make versions
|
||||
- host triplet
|
||||
- configure command
|
||||
- staged output path
|
||||
- runtime shared-library dependencies
|
||||
- wrote the results to `docs/reports/phase1-native-gnu-hello.md`
|
||||
|
||||
Important findings:
|
||||
|
||||
- GNU Hello built successfully with FreeBSD base `make`, not just `gmake`
|
||||
- that contrasts with the earlier local Guile build, which did require GNU `gmake`
|
||||
- even this minimal GNU package links against FreeBSD-userland-provided libraries such as `libiconv` and `libintl`, which is useful data for later Guix package modeling
|
||||
- this step is still a native shell-driven build exercise, not yet a real Guix package build
|
||||
|
||||
Current assessment:
|
||||
|
||||
- Phase 1.2 now has a concrete native autotools success case on FreeBSD
|
||||
- the host can perform the basic fetch/verify/configure/build/install/run cycle needed for later `gnu-build-system` adaptation work
|
||||
- Guix-specific build orchestration is still missing, but the environmental baseline is stronger now
|
||||
|
||||
Recent commits:
|
||||
|
||||
- `e380e88` — `Add FreeBSD Guile verification harness`
|
||||
- `cd721b1` — `Update progress after Guile verification`
|
||||
- `27916cb` — `Diagnose Guile subprocess crash on FreeBSD`
|
||||
- `02f7a7f` — `Validate local Guile fix on FreeBSD`
|
||||
|
||||
Next recommended step:
|
||||
|
||||
1. begin Phase 1.2 by creating a minimal native FreeBSD build environment exercise (for example, GNU Hello or an even smaller autotools package)
|
||||
2. use the local fixed Guile build when subprocess helpers are required
|
||||
3. keep `bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear
|
||||
1. extend Phase 1.2 with at least one additional representative GNU/autotools package build on FreeBSD, or
|
||||
2. prototype a tiny Scheme-based `gnu-build-system`-like phase runner using the known-good local Guile path, starting from the GNU Hello flow
|
||||
3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear
|
||||
|
||||
133
docs/reports/phase1-native-gnu-hello.md
Normal file
133
docs/reports/phase1-native-gnu-hello.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# Phase 1.2 started: native FreeBSD GNU Hello build exercise
|
||||
|
||||
Date: 2026-04-01
|
||||
|
||||
## Summary
|
||||
|
||||
This step begins Phase 1.2 from `docs/PLAN.md` by validating a minimal native GNU autotools build on FreeBSD.
|
||||
|
||||
A reusable harness was added:
|
||||
|
||||
- `tests/native-build/run-gnu-hello.sh`
|
||||
|
||||
The harness downloads GNU Hello, verifies the source hash against the current Guix package definition, configures it, builds it, installs it into a staging directory, and runs the resulting binary.
|
||||
|
||||
## Source and integrity verification
|
||||
|
||||
The exercise uses the same GNU Hello release currently referenced by the Guix source tree at `~/repos/guix/gnu/packages/base.scm`:
|
||||
|
||||
- package: `hello`
|
||||
- version: `2.12.3`
|
||||
- Guix nix-base32 hash: `183a6rxnhixiyykd7qis0y9g9cfqhpkk872a245y3zl28can0pqd`
|
||||
|
||||
The harness converts the Guix nix-base32 hash to hexadecimal using `(guix base32)` and verifies the downloaded tarball with `sha256(1)`.
|
||||
|
||||
Verified SHA256:
|
||||
|
||||
```text
|
||||
0d5f60154382fee10b114a1c34e785d8b1f492073ae2d3a6f7b147687b366aa0
|
||||
```
|
||||
|
||||
## Verification command
|
||||
|
||||
```sh
|
||||
METADATA_OUT=/tmp/gnu-hello-metadata.txt ./tests/native-build/run-gnu-hello.sh
|
||||
```
|
||||
|
||||
## Result
|
||||
|
||||
The native FreeBSD build succeeds.
|
||||
|
||||
Observed outcome:
|
||||
|
||||
- source fetch: success
|
||||
- source hash verification: success
|
||||
- extract: success
|
||||
- configure: success
|
||||
- build: success
|
||||
- staged install: success
|
||||
- runtime execution: success
|
||||
|
||||
Observed program output:
|
||||
|
||||
```text
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
## Environment used
|
||||
|
||||
From the captured metadata:
|
||||
|
||||
- host: `FreeBSD 15.0-STABLE amd64`
|
||||
- compiler: `cc` (`FreeBSD clang version 19.1.7`)
|
||||
- make tool: `make` (FreeBSD base make)
|
||||
- host triplet: `x86_64-unknown-freebsd15.0`
|
||||
- configure command: `CC=cc .../configure --prefix=/usr/local`
|
||||
|
||||
## Notable findings
|
||||
|
||||
### 1. A simple GNU autotools package builds with FreeBSD base `make`
|
||||
|
||||
GNU Hello built successfully using FreeBSD's native `/usr/bin/make`.
|
||||
|
||||
This is a useful contrast with the earlier local Guile build work, where GNU `gmake` was required. So for Phase 1.2, the immediate result is:
|
||||
|
||||
- some standard GNU autotools packages can build on FreeBSD with native base tooling
|
||||
- but more complex packages still may require GNU-specific build tools
|
||||
|
||||
### 2. Runtime dependencies reflect FreeBSD userland packaging choices
|
||||
|
||||
The staged `hello` binary is dynamically linked and pulls in:
|
||||
|
||||
- `libiconv.so.2`
|
||||
- `libintl.so.8`
|
||||
- `libc.so.7`
|
||||
- `libthr.so.3`
|
||||
- `libsys.so.7`
|
||||
|
||||
This is relevant for later Guix porting work because even a minimal GNU package on FreeBSD picks up non-Linux runtime linkage patterns that will need to be modeled correctly.
|
||||
|
||||
### 3. Guile was only needed for hash translation, not for the build itself
|
||||
|
||||
The build harness uses Guile plus `(guix base32)` only to translate the Guix package hash into hexadecimal for source verification.
|
||||
|
||||
The actual package build is performed entirely with native FreeBSD/GNU userland tools:
|
||||
|
||||
- `fetch`
|
||||
- `sha256`
|
||||
- `bsdtar`
|
||||
- `cc`
|
||||
- `make`
|
||||
|
||||
## What this step demonstrates
|
||||
|
||||
This step demonstrates that the current FreeBSD host can already perform the basic lifecycle expected of a future adapted `gnu-build-system` flow:
|
||||
|
||||
1. fetch source
|
||||
2. verify source integrity
|
||||
3. unpack source
|
||||
4. run `configure`
|
||||
5. compile
|
||||
6. install into a staging directory
|
||||
7. execute the resulting binary
|
||||
8. collect basic input/output metadata
|
||||
|
||||
## Remaining gaps relative to the full Phase 1.2 goal
|
||||
|
||||
This is a native build exercise, not yet a real Guix package build.
|
||||
|
||||
Still outstanding:
|
||||
|
||||
- building the package through Guix abstractions rather than a shell harness
|
||||
- recording Guix-style dependency graphs and derivation-like metadata
|
||||
- Linux-vs-FreeBSD output/process comparison from the same package build
|
||||
- trying at least one more representative GNU package beyond Hello
|
||||
|
||||
## Recommendation for the next step
|
||||
|
||||
Continue Phase 1.2 by either:
|
||||
|
||||
1. creating a second native build exercise for another small GNU autotools package, or
|
||||
2. starting a very small FreeBSD-specific prototype of `gnu-build-system`-like phase execution in Scheme using the now-validated local Guile path
|
||||
|
||||
The current GNU Hello harness provides a good baseline for either direction.
|
||||
199
tests/native-build/run-gnu-hello.sh
Executable file
199
tests/native-build/run-gnu-hello.sh
Executable file
@@ -0,0 +1,199 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
guix_source_dir=${GUIX_SOURCE_DIR:-"$HOME/repos/guix"}
|
||||
hello_version=${HELLO_VERSION:-2.12.3}
|
||||
expected_nix_base32=${HELLO_NIX_BASE32:-183a6rxnhixiyykd7qis0y9g9cfqhpkk872a245y3zl28can0pqd}
|
||||
source_url=${HELLO_SOURCE_URL:-"https://ftp.gnu.org/gnu/hello/hello-$hello_version.tar.gz"}
|
||||
prefix=${PREFIX:-/usr/local}
|
||||
cc_bin=${CC_BIN:-cc}
|
||||
make_bin=${MAKE_BIN:-make}
|
||||
|
||||
if [ ! -d "$guix_source_dir/guix" ]; then
|
||||
echo "Guix source tree not found at $guix_source_dir" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "${GUILE_BIN:-}" ]; then
|
||||
guile_bin=$GUILE_BIN
|
||||
elif command -v guile3 >/dev/null 2>&1; then
|
||||
guile_bin=$(command -v guile3)
|
||||
elif command -v guile-3.0 >/dev/null 2>&1; then
|
||||
guile_bin=$(command -v guile-3.0)
|
||||
else
|
||||
echo "Unable to find GUILE_BIN, guile3, or guile-3.0 in PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$guile_bin" ]; then
|
||||
echo "Guile binary is not executable: $guile_bin" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v fetch >/dev/null 2>&1; then
|
||||
echo "fetch not found in PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v sha256 >/dev/null 2>&1; then
|
||||
echo "sha256 not found in PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v bsdtar >/dev/null 2>&1; then
|
||||
echo "bsdtar not found in PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v "$cc_bin" >/dev/null 2>&1; then
|
||||
echo "C compiler not found: $cc_bin" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v "$make_bin" >/dev/null 2>&1; then
|
||||
echo "make tool not found: $make_bin" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
jobs=${JOBS:-$(sysctl -n hw.ncpu 2>/dev/null || echo 1)}
|
||||
guile_prefix=$(CDPATH= cd -- "$(dirname "$guile_bin")/.." && pwd)
|
||||
guile_lib_dir=$guile_prefix/lib
|
||||
if [ -e "$guile_lib_dir/libguile-3.0.so.1" ]; then
|
||||
if [ -n "${LD_LIBRARY_PATH:-}" ]; then
|
||||
export LD_LIBRARY_PATH="$guile_lib_dir:$LD_LIBRARY_PATH"
|
||||
else
|
||||
export LD_LIBRARY_PATH="$guile_lib_dir"
|
||||
fi
|
||||
fi
|
||||
|
||||
cleanup=0
|
||||
if [ -n "${WORKDIR:-}" ]; then
|
||||
workdir=$WORKDIR
|
||||
mkdir -p "$workdir"
|
||||
else
|
||||
workdir=$(mktemp -d /tmp/fruix-gnu-hello.XXXXXX)
|
||||
cleanup=1
|
||||
fi
|
||||
|
||||
if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then
|
||||
cleanup=0
|
||||
fi
|
||||
|
||||
cleanup_workdir() {
|
||||
if [ "$cleanup" -eq 1 ]; then
|
||||
rm -rf "$workdir"
|
||||
fi
|
||||
}
|
||||
trap cleanup_workdir EXIT INT TERM
|
||||
|
||||
expected_sha256_hex=$(GUILE_AUTO_COMPILE=0 \
|
||||
GUILE_LOAD_PATH="$guix_source_dir${GUILE_LOAD_PATH:+:$GUILE_LOAD_PATH}" \
|
||||
"$guile_bin" -c "(use-modules (guix base32) (rnrs bytevectors) (ice-9 format)) (for-each (lambda (b) (format #t \"~2,'0x\" b)) (bytevector->u8-list (nix-base32-string->bytevector (cadr (command-line))))) (newline)" \
|
||||
"$expected_nix_base32")
|
||||
|
||||
src_tarball=$workdir/hello-$hello_version.tar.gz
|
||||
src_dir=$workdir/hello-$hello_version
|
||||
build_dir=$workdir/build
|
||||
stage_dir=$workdir/stage
|
||||
metadata_file=$workdir/gnu-hello-build-metadata.txt
|
||||
configure_log=$workdir/configure.log
|
||||
build_log=$workdir/build.log
|
||||
install_log=$workdir/install.log
|
||||
|
||||
printf 'Using Guile: %s\n' "$guile_bin"
|
||||
printf 'Using LD_LIBRARY_PATH: %s\n' "${LD_LIBRARY_PATH:-<unset>}"
|
||||
printf 'Working directory: %s\n' "$workdir"
|
||||
printf 'Fetching: %s\n' "$source_url"
|
||||
fetch -o "$src_tarball" "$source_url"
|
||||
|
||||
actual_sha256_hex=$(sha256 -q "$src_tarball")
|
||||
if [ "$actual_sha256_hex" != "$expected_sha256_hex" ]; then
|
||||
echo "sha256 mismatch for $src_tarball" >&2
|
||||
echo "expected: $expected_sha256_hex" >&2
|
||||
echo "actual: $actual_sha256_hex" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bsdtar -xf "$src_tarball" -C "$workdir"
|
||||
mkdir -p "$build_dir" "$stage_dir"
|
||||
|
||||
host_triplet=$(sh "$src_dir/build-aux/config.guess")
|
||||
configure_cmd="CC=$cc_bin $src_dir/configure --prefix=$prefix"
|
||||
|
||||
(
|
||||
cd "$build_dir"
|
||||
env CC="$cc_bin" "$src_dir/configure" --prefix="$prefix"
|
||||
) >"$configure_log" 2>&1
|
||||
|
||||
(
|
||||
cd "$build_dir"
|
||||
env CC="$cc_bin" "$make_bin" -j"$jobs"
|
||||
) >"$build_log" 2>&1
|
||||
|
||||
(
|
||||
cd "$build_dir"
|
||||
env CC="$cc_bin" "$make_bin" DESTDIR="$stage_dir" install
|
||||
) >"$install_log" 2>&1
|
||||
|
||||
installed_binary=$stage_dir$prefix/bin/hello
|
||||
if [ ! -x "$installed_binary" ]; then
|
||||
echo "installed hello binary not found: $installed_binary" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
hello_output=$(env LC_ALL=C "$installed_binary")
|
||||
if [ "$hello_output" != "Hello, world!" ]; then
|
||||
echo "unexpected hello output: $hello_output" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
binary_file=$(file "$installed_binary")
|
||||
runtime_deps=$(ldd "$installed_binary")
|
||||
cc_version=$($cc_bin --version | sed -n '1p')
|
||||
make_version=$($make_bin -V MAKE_VERSION 2>/dev/null || $make_bin --version 2>/dev/null | sed -n '1p' || echo unknown)
|
||||
uname_string=$(uname -a)
|
||||
|
||||
cat >"$metadata_file" <<EOF
|
||||
hello_version=$hello_version
|
||||
source_url=$source_url
|
||||
expected_nix_base32=$expected_nix_base32
|
||||
expected_sha256_hex=$expected_sha256_hex
|
||||
actual_sha256_hex=$actual_sha256_hex
|
||||
guix_source_dir=$guix_source_dir
|
||||
guile_bin=$guile_bin
|
||||
cc_bin=$cc_bin
|
||||
cc_version=$cc_version
|
||||
make_bin=$make_bin
|
||||
make_version=$make_version
|
||||
host_triplet=$host_triplet
|
||||
configure_command=$configure_cmd
|
||||
workdir=$workdir
|
||||
source_dir=$src_dir
|
||||
build_dir=$build_dir
|
||||
stage_dir=$stage_dir
|
||||
installed_binary=$installed_binary
|
||||
hello_output=$hello_output
|
||||
binary_file=$binary_file
|
||||
configure_log=$configure_log
|
||||
build_log=$build_log
|
||||
install_log=$install_log
|
||||
uname=$uname_string
|
||||
runtime_deps_begin
|
||||
$runtime_deps
|
||||
runtime_deps_end
|
||||
EOF
|
||||
|
||||
if [ -n "${METADATA_OUT:-}" ]; then
|
||||
mkdir -p "$(dirname "$METADATA_OUT")"
|
||||
cp "$metadata_file" "$METADATA_OUT"
|
||||
fi
|
||||
|
||||
printf 'PASS gnu-hello-native-build\n'
|
||||
printf 'Hello output: %s\n' "$hello_output"
|
||||
if [ "$cleanup" -eq 0 ]; then
|
||||
printf 'Installed binary: %s\n' "$installed_binary"
|
||||
printf 'Metadata file: %s\n' "$metadata_file"
|
||||
else
|
||||
printf '%s\n' 'Work directory will be removed on exit (set KEEP_WORKDIR=1 to preserve it).'
|
||||
fi
|
||||
if [ -n "${METADATA_OUT:-}" ]; then
|
||||
printf 'Copied metadata to: %s\n' "$METADATA_OUT"
|
||||
fi
|
||||
printf '%s\n' '--- metadata ---'
|
||||
cat "$metadata_file"
|
||||
Reference in New Issue
Block a user